用初始化列表和超类构造函数声明子类构造函数的正确方式

Proper way of declaring subclass constructer with both initialization lists and superclass constructor

本文关键字:构造函数 方式 子类 声明 列表 超类 初始化      更新时间:2023-10-16

我目前的情况如下。这或多或少是一个简单的继承案例,我对此有很多问题

我有一个抽象类(=它有纯虚拟函数(,有两个变量foo_bar_。CCD_ 3由构造函数中的一个参数设置。对于大多数子类,bar_应该默认为1000,但我希望有一个特定的类将其覆盖为50000。

下面是一个代码片段:

class Base {
protected:
const int foo_;
const int bar_;
public:
Base(int foo) : foo_{foo}, bar_{1000} {}
}
class Derived : public Base {}

首先,有一个快速的问题:是像我在示例中那样在初始化列表中初始化bar_更好,还是在变量声明为const int bar_{1000};的顶部进行?

第二个快速问题:在初始化列表中使用{}可以吗?还是应该使用()

如何正确编写派生类的构造函数?我想专门调用我为Base定义的构造函数,并使用初始化列表将bar_设置为50000。

我的想法是这样的:

Derived(int foo) : Base(foo), bar_{50000} {}

编辑:经过一番尝试,我注意到修改Derived的构造函数列表中的bar_显然是不可能的,因为"bar_" is not a nonstatic data member or base class of class "Derived"

是像我在示例中那样在初始化列表中初始化bar_更好的做法,还是在变量声明为const int bar_{1000}的顶部进行;?

这与其说是"最佳实践",不如说是"你想要什么"?1000是默认的初始值,它被构造函数中的初始值设定项"覆盖"。你可以有默认的初始化器,例如一个构造函数使用不同的初始化器和一个不使用的构造函数。

如何正确编写派生类的构造函数?

您可以编写一个受保护的构造函数,允许您传递两个值:

class Base {
protected:
const int foo_;
const int bar_;
Base(int foo, int bar) : foo_(foo), bar_(bar) {}
public:
Base(int foo) : foo_{foo}, bar_{1000} {}
};
class Derived : public Base {
public:
Derived(int foo) : Base(foo,5000) {}
};

这个问题有很多方面需要解决。

我对初始化的偏好是:

class Base {
protected:
const int foo_{};
const int bar_{1000};
public:
Base(int foo) : foo_{foo} {}
}

我喜欢这样做的原因是因为一个类可以有多个构造函数。这样可以更容易地维护默认值。

对于初始化的问题,我放弃了。只需使用现有的样式指南。(目前,他们似乎在所有地方使用{}都是标准化的(除了构造函数之外,初始化更麻烦,如果你想对细节感到震惊,我可以推荐:Nicolai Josuttis"C++初始化的噩梦"。

对于在派生类中编写构造函数,我认为您的成员不应该受到保护。如果它是私有的,那么写它的唯一方法是:

class Base {
private:
const int foo_{};
const int bar_{1'000};
protected:
Base(int foo, int bar) : foo_{foo}, bar_{bar} {}
public:
Base(int foo) : foo_{foo} {}
}
class Derived : public Base {
public:
Derived(int foo) : Base{foo, 50'000} {}
}

这样,我就可以通过一个受保护的方法公开对它们的访问。即使忽略了这个建议,我也会使用这种技术来初始化它,因为如果只看"Base"类,最容易理解会发生什么。