我一直在努力解决这个问题:
目前我有这段代码:
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)调用虚方法,则调用B :: init,而不是D :: init。
有没有一种很好的方法来完成这项工作,还是我需要在D中重新编写所有B&C的ctors?
谢谢!
答案 0 :(得分:2)
您无法从构造函数中调用虚函数。这与对象的构造顺序有关:
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
。首先构造基类,因此在派生类中,您可以调用方法并使用父级的成员。
事实上,通过上面的简单示例,您可以在g
构造函数中使用变量F
,因为之前调用了父构造函数。否则会形成错误,因为E
的构造函数是g
到7
这与你的问题有什么关系?
好吧,在基础构造函数中,您正在调用虚函数。您希望调用的虚函数在派生类中调度。问题是,它还没有派生类。
你看,首先构建了类B
。现在还没有D
!由于尚未存在D
,因此无法调用D
函数进行虚拟调度!因此,编译器将回退到当时可以选择的函数。在您的情况下,该函数是B
init函数。
答案 1 :(得分:1)
正如其他人所说,在构造函数中调用派生的虚函数并不是一件容易的事,但它并不是解决问题的唯一方法。
在您特定的情况下,我理解为您希望初始化继承类的成员但仍然重用基类构造函数,您可以使用类内成员初始化。这有效:
#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;
}
正如您所见[{3}},使用GCC编译上面的代码(并且没有优化)会生成Derived
构造函数,并调用Base
构造函数和初始化std::string
成员。
答案 2 :(得分:0)
是。虚方法在构造函数中非虚拟地调用,因为在调用基类构造函数时尚未构造派生类。
这是一种结束调用纯虚函数的已知方法 - 只需调用一些从构造函数调用纯虚函数的中间函数(你不能直接从构造函数调用纯虚函数,编译器不允许你)
要解决您的问题,而不是继承构造函数,请声明您自己的并调用基类构造函数,然后进行特定的初始化。