C++ 继承基构造函数,但仍调用默认派生构造函数

C++ Inherit base constructor, but still call default derived constructor

本文关键字:构造函数 调用 默认 派生 继承 C++      更新时间:2023-10-16

我一直在为这个问题而苦苦挣扎:

目前我有这个代码:

class B {
public:
B(int, int, int, int);
[many other ctors]
};
class D : public B {
public:
using B::B;
[other methode]
};

现在我希望 D 管理一些指针,我需要独立于传递给构造函数的参数进行初始化。

我试过这个:

class B {
public:
B(int, int, int, int) {
[other stuff]
init();
}
[many other ctors]
virtual void init() {}
};
class D : public B {
public:
using B::B;
void init() {
mPointer = new Stuff(42);
}
private:
mPointer = nullptr;
};

但显然,如果你从 B::B(int,int,int,int,int) 调用虚拟方法,它会调用 B::init,而不是 D::init。

有没有一种很好的方法来完成这项工作,或者我需要用 D 重写所有 B 的 ctors?

谢谢!

不能从构造函数调用虚函数。这与对象的构造顺序有关:

struct E {
E() { std::cout << "E" << std::endl; }
int g = 7;
};
struct F : E {
B() { std::cout << "F" << g << std::endl; }
};
F f;

构造f时,程序将输出EF7。首先构造基类,因此在派生类中,可以调用方法并使用父类的成员。

实际上,通过上面的简单示例,您可以在构造函数中使用变量gF因为之前调用了父构造函数。否则它的格式不正确,因为E的构造函数是设置g7

这与您的问题有什么关系?

好吧,在基构造函数中,您正在调用一个虚函数。您希望在派生类中调度调用的虚函数。问题是,还没有派生类。

您会看到,首先构造类B。目前还没有D!由于尚不存在D,因此无法执行虚拟调度来调用D函数!因此,编译器将回退到当时可以选择的函数。在您的情况下,该函数B初始化函数。

正如其他人所说,在构造函数中调用派生的虚函数并非易事,但这不是解决问题的唯一方法。

在您的特定情况下,我理解为您想要初始化继承类的成员但仍重用基类构造函数,您可以使用类内成员初始化。这有效:

#include <string>
#include <iostream>
class Base {
public:
Base(int, int, int) { std::cout << "Calling base constructor" << std::endl; }
};
class Derived : public Base {
public:
using Base::Base;
std::string member{"This is a member string"};
};
int main() {
Derived d(1, 2, 3);
std::cout << d.member << std::endl;
return 0;
}

正如你在这里看到的,使用 GCC 编译上面的代码(并且没有优化)确实会生成一个Derived构造函数,它会调用Base构造函数初始化std::string成员。

是的。虚拟方法从构造函数中非虚拟调用,因为在调用基类构造函数时尚未构造派生类。

这是最终调用纯虚函数的已知方法 - 只需调用一些从构造函数调用纯虚拟函数的中间函数(你不能直接从构造函数调用纯虚函数,编译器不允许你)。

若要解决您的问题,请声明您自己的构造函数并调用基类构造函数,然后进行特定的初始化,而不是继承构造函数。