【问题标题】:Delegating constructors and reference parameters委托构造函数和引用参数
【发布时间】:2020-02-21 16:22:20
【问题描述】:

我想通过重载为我的类实现几个构造函数。据我了解,遵循 DRY 原则的惯用方式是使用一种称为委托构造函数的功能。我还看到了关于在任何地方使用引用参数并不惜一切代价避免使用指针的想法,因为引用是一种 c++ 方式等。

所以我认为这可以用指针来实现(可行):

class B {};
class C {};

class A {
public:
    A();
    A(const B* b);
    A(const B* b, const C* c);
private:
    const B* b_;
    const C* c_;
};

// These ctors short and concise, delegating work to last ctor
A::A() : A(nullptr, nullptr) {}
A::A(const B* b) : A(b, nullptr) {}

// This ctor contains code that deals with b or c being nullptr
// Ideally I only modify code in this ctor (DRY)
A::A(const B* b, const C* c) : b_(b), c_(c) { 
   //code
}

以下,显然不起作用:

class B {};
class C {};

class A {
public:
    A();
    A(const B& b);
    A(const B& b, const C& c);
private:
    const B& b_;
    const C& c_;
};

A::A() : A(nullptr, nullptr) {}

A::A(const B& b) : A(b, nullptr) {}

A::A(const B& b, const C& c) : b_(b), c_(c) {
   //code
}

所以问题是如何按照指针示例中的语义实现委托构造函数,但将引用作为构造函数的参数。

(我是否完全错过了这里的某个地方?甚至可能只是盯着整体思路?)

【问题讨论】:

  • 我假设 b_c_ 是引用?请提供minimal reproducible example。您不能将 nullptr 分配给引用,如果您的值可以为 null,则需要使用指针
  • 谢谢@AlanBirtles。我在示例中添加了一些代码。希望这进一步澄清了这个问题。

标签: c++ pointers constructor pass-by-reference


【解决方案1】:

假设您的“A”成员是引用,允许这样做的一种方法是为您的每个类设置一些特殊的“null”值:

class B {};
class C {};

class A
{
public:
    A();
    A(const B& b);
    A(const B& b, const C& c);
private:
    const B& b_;
    const C& c_;
    static const B null_b;
    static const C null_c;
};

A::A() : A(null_b, null_c) {}

A::A(const B& b) : A(b, null_c) {}

A::A(const B& b, const C& c) : b_(b), c_(c) {
}

【讨论】:

  • 我看到这种方法的方式在语义上最接近我对指针参数化构造函数的理解(第一个代码 sn-p 有问题)。那么问题是使用委托构造函数和引用参数来安排代码的传统(通用、标准)方式吗?
  • @psb 我认为这与委托构造函数没有太大关系,它与引用成员可能为“null”有关,通常如果成员可以为 null,那么指针会更合适
  • @psb 我猜你过于关注参考而不是你想要表达的内容
【解决方案2】:

您不能将nullptr 传递给引用。它的存在正是为了这个目的。

指针是一个包含变量地址的变量。引用是地址变量,所以它不能引用任何东西,也不能重新赋值。

当你写作时

 A(const B& b)

您正在签订合同。你在说:“我想用强制的 B 对象构造 A。B 为 null 不是这里的选项。”

委托给这个构造函数意味着遵循它的契约。因此,在这个假设下,您的代表团可以正常工作:

struct B{};

struct A{
  A() : A(B{}){}  // Constructing a pre-defined B object

  A(const B& b) : _b{b}{}
  B _b;  
};


int main ()
{
  A a;
}

Live code here

说,如果你想表达一个可为空的类型,你可以使用std::optional,如果 C++17 是一个选项。如果您有多态对象,我建议您使用智能指针更好地表达所有权并更好地控制您的代码。

【讨论】:

  • 谢谢莫亚。你的回答有一些我还没有消化的想法。我喜欢您通过将参数声明为引用或指针来陈述合同的表达方式。您对我过于关注参考的评论绝对是相关的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多