笔记:条款9: 绝不在构造和析构过程中调用virtual函数

这是我在阅读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);
}

请记住

 在构造和析构期间不要调用虚函数,因为这类调用从不下降至继承类。

猜你喜欢

转载自blog.csdn.net/lkq_primer/article/details/81121743