这是我在阅读Effective c++中认为比较重要的部分,下面给出了我对这一节的理解,并写出对应的比较容易理解的代码。
我们原本认为构造子类对象时,如果在父类的构造函数中调用虚函数就会调用子类的虚函数,然而编译器会调用父类的虚函数,如果父类的虚函数是纯虚函数,编译器就会找不到父类虚函数的实现代码。
编译器对这种在父类中调用虚函数的做法的一个解决方案是:继承类对象的基类对象构造期间对象的类型是基类而不是继承类。
合理的解释: 在基类构造函数执行时,继承类的成员变量尚未初始化,如果使用这些未初始化的成员将导致不明确行为。 对析构函数同理。
这是与java c#不相同的一个地方。
class A {
public:
A() {
init();
}
virtual void log() const {
cout << "lkqA" << endl;
cout << typeid(this).name() << endl;
};
void init() {
log();
}
~A() {
log();
}
};
class B : public A {
void log() const {
cout << "lkq" << endl;
}
};
int main(){
B b;
}
解决方案;
在基类中将虚函数该为非虚,并在继承类的构造函数初始值列表传递信息给基类的构造函数,然后那个构造函数就可以安全地调用非虚函数。
class A {
public:
A(string p) {
init(p);
}
void log(string p) const {
cout << "lkqA" << endl;
cout << typeid(this).name() << endl;
cout << p << endl;
};
void init(string p ) {
log(p);
}
~A() {
}
};
class B : public A {
public:
B(string p ):A(p){}
};
int main(){
string p = "5201314";
B b(p);
}
请记住
在构造和析构期间不要调用虚函数,因为这类调用从不下降至继承类。