我想在调用父构造函数之前进行一些处理。下面的例子说明了我为什么要这样做,尽管为了清楚起见我已经做了一些微不足道的事情。真正的父构造函数正在进行一些渲染,但我们首先尝试解决这个问题。
本质上,当父构造函数调用overriden函数但子目标数据尚未设置时,会出现问题。我该如何解决这个问题?
class BaseClass {
public:
int myNumber;
BaseClass(){
myNumber = 0;
this->printNumber();
}
virtual void printNumber(){
printf("My number is %d\n", this->myNumber);
}
}
class ChildClass : BaseClass {
public:
float childNumber;
ChildClass(float myNumber) : BaseClass() {
this->childNumber = myNumber;
}
void printNumber(){
printf("My number is %f\n", this->childNumber);
}
}
答案 0 :(得分:9)
当父构造函数调用overriden函数时,问题就出现了,
不,这从未发生过。在BaseClass
的构造函数中,其动态类型也是BaseClass
,因此printNumber()
调用将解析为其自己的数字而不是某些派生类。为什么?因为当时ChildClass
的构造函数尚未完成运行,因此尚未创建。
作为 @FredLarson 评论,以下是有关此主题的更多信息:http://parashift.com/c++-faq/calling-virtuals-from-ctors.html
答案 1 :(得分:2)
与上面说的其他人一样,你不应该从构造函数中调用虚拟成员。但是为了解决你的问题,有一个可能对你有帮助的习惯用法,它被称为base-from-member:
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Base-from-Member
它基本上做的是利用基类按声明的顺序初始化的事实。在初始化基类之前,您可以在单独的基类中执行您需要执行的操作。
class OtherBaseClass {
int Num;
OtherBaseclass(float num) : Num(num)
{
printf("My number is %d\n", this->Num);
}
};
class ChildClass : OtherBaseClass, BaseClass {
public:
float childNumber;
ChildClass(float myNumber) : OtherBaseClass(myNumber), BaseClass() {
....
答案 2 :(得分:2)
请注意,基类的构造函数无法调用派生类的虚函数版本,也就是说,您的ChildClass::printNumber()
函数不会被调用。
也就是说,如果你想在基类的构造函数之前执行某些操作,一种方法是使用另一个基类,并将它放在另一个基类之前:
class RunMeFirst
{
public RunMeFirst()
{ printf("whatever...\n"); }
};
class ChildClass : private RunMeFirst, public BaseClass
{ /*...*/ };
答案 3 :(得分:1)
您是否必须在基类中实现呈现功能?您可以改为使用合成而不是继承。使用合成将允许您轻松控制成员初始化顺序,例如:
#include <iostream>
class renderer
{
public:
renderer(int number)
{
std::cout << "Number is " << number << std::endl;
}
};
class foo
{
public:
foo()
: number_(12)
, renderer_(number_)
{
}
private:
int number_;
renderer renderer_;
};
int main()
{
foo bar;
}
一般来说,prefer composition to inheritance。此外,从设计的角度来看,Liskov Substitution Principle也可能在这里使用。
答案 4 :(得分:0)
在基类构造函数之前运行了几件事:
一种常用的解决方案称为“基于成员习语”,并涉及将成员移动到首先构造的新基类。
答案 5 :(得分:0)
感谢@ K-ballo指出错误,因此我能够重新构建代码以执行我想要的操作,但由于这不是问题的技术正确答案,我会留下正确的答案按原样回答。
class BaseClass {
public:
int myNumber;
BaseClass(bool initialize = true){
myNumber = 0;
if (initialize){
this->initialize();
}
}
void initialize(){
this->printNumber();
}
virtual void printNumber(){
printf("My number is %d\n", this->myNumber);
}
}
class ChildClass : BaseClass {
public:
float childNumber;
ChildClass(float myNumber) : BaseClass(false) {
this->childNumber = myNumber;
this->initialize();
}
void printNumber(){
printf("My number is %f\n", this->childNumber);
}
}