C++之构造函数和析构函数中不要调用virtual函数(9)---《Effective C++》
来源:互联网 发布:根据package.json安装 编辑:程序博客网 时间:2024/05/16 13:39
条款9:绝不要在构造函数和析构函数中调用virtual函数
为什么不要在构造函数和析构函数中调用virtual函数呢?下面请大家带着上述问题来看如下代码:
class Base{public: Base(); virtual void hello(); ... }private: int x; int y;};Base::Base(){ ... hello();}class ABase:public Base{public: virtual void hello();//这儿可以声明为virtual,也可以不用声明为virtual,因为在基类中已经声明为virtual,那么子类中相应的所有函数都就变味virtual ...};class BBase::public Base{public: virtual void hello(); ...}ABase a;
试想上面代码运行时候会发生什么问题?ABase的构造函数被调用,ABase的基类Base构造函数一定更早调用,即ABase中从Base中继承的x,y变量通过Base的构造函数被初始化,ABase中的z变量尚未被初始化,此时好戏上演。
1)Base类的构造函数中调用的虚函数hello()函数是基类Base的,还是子类ABase的呢?答案当然是基类Base的,因为在基类Base的构造函数执行期间,virtual函数绝对不会下降到子类ABase阶层,如果这样比较枯燥的话,我们可以反向解释:2)基类Base的构造函数执行期间,子类ABase中的成员变量z并没有被初始化,如果在基类Base的构造函数中调用的virtual函数已经下降到了子类ABase阶层,那么Base中调用的这个virtual函数一定要取取用子类ABase中的成员变量,而这些成员变量并没有被初始化,别挣扎了,C++不允许这样,可以这样理解:在Base类构造期间,virtual函数不是virutal函数,3)其实最主要的原因是:在子类ABase对象的基类构造函数执行期间,对象的类型是基类Base的,而不是子类ABase的,不止virtual函数会被解至基类Base中,也会把对象视为基类Base类型,在本例中,当子类ABase的构造函数执行起来时,一定先调用基类Base的构造函数来初始化子类ABase中的基类成分,这时候对象的类型是基类Base的,同时这时子类ABase中的专属成分如z尚未被初始化,对象在子类构造函数(即子类中的基类构造函数执行结束后)开始执行之前一定不会成为一个子类对象。
同样对着适用于析构函数,C++的析构函数先执行子类的析构函数,后执行基类的析构函数,执行和构造函数执行的顺序刚好相反,一旦子类析构函数开始执行,对象中的子类成员变量呈现未定义值,C++视它们不存在,进入基类析构函数之后就成为一个基类对象,C++的任何部分包括virtual函数,dynamic_casts也同样这样看待它。
**
需要注意的是,有的编译器对这种情况报错,而有的并不报错,很坑的!
**
由于这样并没有执行virtual函数,达到相应的效果,因此,C++明确规定不能在构造函数和析构函数中调用virtual函数。
其他方法可以解决这个问题,其中之一是在基类Base中virtual函数hello声明为non-virtual,然后要求子类ABase构造函数传递必要的信息给Base构造函数,因为基类Base中调用了Base的成员函数hello,不可能下降至子类ABase中,因此安全,为了双重安全,我们也可以选择利用static函数提供数据给基类Base数据,这样在子类ABase中一定不会存在未被初始化的数据,而后这个构造函数就可以安全的调用non-virtual函数hello,如:
class Base{public: Base(int x,int y); void hello();//现在是个non-virtual函数 ...private: int x; int y;};Base::Base(int x,int y):x(x),y(y){ hello();//现在是个non-virtual调用}class ABase:public Base{public: ABase(params):Base(createParams(params)){ ... } ...private: static *** createParams(parameters);};
这种方式是怎样的呢?你无法使用virtual函数从基类Base向下调用,在构造期间,你可以籍由“令子类将必要的构造信息向上传递值基类构造函数”替换加以弥补,这里令createParams函数为static,也就不可能意外指向“初期未成熟之子类ABase对象中尚未初始化的成员变量”。
总结如下:在构造函数中不要调用virtual函数,因为这类调用从不下降至子类derived class这层。
- C++之构造函数和析构函数中不要调用virtual函数(9)---《Effective C++》
- 《Effective C++》不要在构造函数和析构函数中调用虚函数
- 【Effective c++】条款09:绝不再构造和析构过程中调用virtual函数
- Effective C++:条款09:绝不在构造和析构过程中调用virtual函数
- 读书笔记《Effective C++》条款09:绝不在构造和析构过程中调用virtual函数
- Effective C++——》条款9:绝不在构造和析构过程中调用virtual函数
- 9绝对不要在构造函数和析构函数中调用virtual函数
- Effective C++ 笔记之六 绝不在构造和析构函数中调用virtual函数
- C++之析构函数和构造函数调用时间---补充(2)《Effective C++》
- effective c++条款9(绝不在构造和析构过程中调用virtual函数)
- 【effective C++】不要在构造函数或析构函数内调用虚函数
- 《Effective C++》学习笔记条款09 决不让构造和析构过程中调用virtual函数
- Effective C++ Item 09-绝不在构造函数和析构函数中调用virtual函数
- C++不要在构造函数和析构函数中调用virtual函数的原因
- 浅谈C++--绝不在构造和析构函数中调用virtual函数
- Effective C++ Item 9 绝不在构造和析构过程中调用virtual函数
- Effective C++ Item 9 绝不在构造和析构过程中调用virtual函数
- Effective C++ 条款9:绝不在构造和析构过程中调用virtual函数
- 给easyui-combotree控件赋值,数组值,多个值
- 27个提升效率的iOS开源库推荐
- 对于亚洲车型汽车诊断的解析研究
- Android 各种Loading 炫酷View
- 源--String
- C++之构造函数和析构函数中不要调用virtual函数(9)---《Effective C++》
- 【动态规划】UVa 1331 最大面积最小三角形剖分
- 单片机通过软件实现按键消抖
- redis数据结构hash命令
- Python的任务调度模块APScheduler学习1(基本认识)
- 类实现求三角柱体体积、表面积
- Python中的break、continue、pass
- Altium Designer 10 PCB简要设计及其例程
- 食物链(并查集)