c++有关构造函数和析构函数中调用虚函数问题
今天看了一道迅雷的笔试题目,然后引起一段思考,题目如下:
下列关于虚函数的说法正确的是()
A、在构造函数中调用类自己的虚函数,虚函数的动态绑定机制还会生效。
B、在析构函数中调用类自己的虚函数,虚函数的动态绑定机制还会生效。
C、静态函数不可以是虚函数
D、虚函数可以声明为inline
此题答案给的是BCD,当时我就产生很大疑惑,所以我对四个选项依依来验证。
1、首先对于AB选项,我做了如下代码:
#include <iostream>
using namespace std;
class ClassA
{
public:
ClassA()
{
cout<<"classA-begin"<<endl;
OutPut();
cout<<"classA-endl"<<endl;
}
virtual ~ClassA()
{
cout<<"~classA-begin"<<endl;
OutPut();
cout<<"~classA-endl"<<endl;
}
void virtual OutPut()
{
cout<<"A"<<endl;
}
}; class ClassB:public ClassA
{
public:
ClassB()
{
cout<<"ClassB-begin"<<endl;
OutPut();
cout<<"ClassB-endl"<<endl;
}
virtual ~ClassB()
{
cout<<"~ClassB-begin"<<endl;
OutPut();
cout<<"~ClassB-endl"<<endl;
}
void OutPut()
{
cout<<"B"<<endl;
} }; int main()
{
ClassA *a=new ClassB();
a->OutPut();
delete a;
getchar();
return ; }
在vs2010中输出结果为:

可以看到,在new ClassB时,虽然在父类ClassA的构造函数调了的是被ClassB覆盖的虚函数Output(),但是实际上还是调用的ClassA的OutPut。这是因为
继承类在构造的时候总是首先调用其基类的构造函数来对属于其基类的部分进行构造,在这个时候,整个类被当作基类来处理,继承类的部分对整个类来说好像不存在一样,直到基类的构造函数退出并进入继承类的构造函数,该类才被当作继承类来出来处理。对析构也一样,只是析构的顺序正好相反。
由此可知AB错误。(可以参考:http://www.cnblogs.com/xiaoxibo/archive/2011/07/18/2212612.html)
对于C选项:
因为静态成员函数没有this,也就没有存放vptr的地方,同时其函数的指针存放也不同于一般的成员函数,其无法成为一个对象的虚函数的指针以实现由此带来的动态机制。静态是编译时期就必须确定的,虚函数是运行时期确定的。故C项正确。
对于D选项:
inline函数和virtual函数有着本质的区别,inline函数是在程序被编译时就展开,在函数调用处用整个函数体去替换,而virtual函数是在运行期才能够确定如何去调用的,因而inline函数体现的是一种编译期机制,virtual函数体现的是一种运行期机制。
因此,内联函数是个静态行为,而虚函数是个动态行为,他们之间是有矛盾的。
函数的inline属性是在编译时确定的, 然而,virtual的性质则是在运行时确定的,这两个不能同时存在,只能有一个选择,文件中声明inline关键字只是对编译器的建议,编译器是否采纳是编译器的事情。
我并不否认虚函数也同样可以用inline来修饰,但你必须使用对象来调用,因为对象是没有所谓多态的,多态只面向行为或者方法,但是C++编译器,无法保证一个内联的虚函数只会被对象调用,所以一般来说,编译器将会忽略掉所有的虚函数的内联属性。
所以D正确。
故此题答案为CD
c++有关构造函数和析构函数中调用虚函数问题的更多相关文章
- 【校招面试 之 C/C++】第10题 C++不在构造函数和析构函数中调用虚函数
1.不要在构造函数中调用虚函数的原因 在概念上,构造函数的工作是为对象进行初始化.在构造函数完成之前,被构造的对象被认为“未完全生成”.当创建某个派生类的对象时,如果在它的基类的构造函数中调用虚函数, ...
- 在构造函数和析构函数中调用虚函数------新标准c++程序设计
在构造函数和析构函数中调用虚函数不是多态,因为编译时即可确定调用的是哪个函数.如果本类有该函数,调用的就是本类的函数:如果本类没有,调用的就是直接基类的函数:如果基类没有,调用的就是间接基类的函数,以 ...
- 读书笔记 effective c++ Item 9 绝不要在构造函数或者析构函数中调用虚函数
关于构造函数的一个违反直觉的行为 我会以重复标题开始:你不应该在构造或者析构的过程中调用虚函数,因为这些调用的结果会和你想的不一样.如果你同时是一个java或者c#程序员,那么请着重注意这个条款,因为 ...
- EC笔记,第二部分:9.不在构造、析构函数中调用虚函数
9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #; } 上述程序会产生什么样的输出呢? 你一定会以为会输出: cls2 make cls2 delete ...
- C++箴言:避免构造或析构函数中调用虚函数
如果你已经从另外一种语言如C#或者Java转向了C++,你会觉得,避免在类的构造函数或者析构函数中调用虚函数这一原则有点违背直觉.但是在C++中,违反这个原则会给你带来难以预料的后果和无尽的烦恼. 正 ...
- C++进阶--构造函数和析构函数中的虚函数
//############################################################################ /* 任何时候都不要在构造函数或析构函数中 ...
- 【C++】不要在构造函数或析构函数内调用虚函数
这个问题来自于<Effective C++>条款9:永远不要在构造函数或析构函数中调用虚函数 . 假设有如下代码: class Transaction {// 所有交易的基类 public ...
- C++构造与析构函数中调用虚函数的问题
前些天想把以前写的内存池算法重写一遍,跨平台是第一目标,当时突发奇想,因为不愿意做成一大堆#if..#end,所以想利用C++的多态性,但是怎么让内存池完好退出却没想到自认为完美的方案.但是一个很偶然 ...
- C++-不要在构造和析构函数中调用虚函数
在实习的单位搞CxImage库时不知为什么在Debug时没有问题,但是Release版里竟然跳出个Pure virtual function call error! 啥东西呀,竟然遇上了,就探个究竟吧 ...
随机推荐
- php.ini 文件中配置的意义注释
;;;;;;;;;;;;;;;;;;;; About php.ini ; //关于php;;;;;;;;;;;;;;;;;;;; PHP's initialization file, gener ...
- Linux Academy Learn Notes
Linux Essentials Certification Globbing ls ?.txt --- ? stands for one character while * means one or ...
- sublime比较好用的插件
emmet, markdown preview, package Control, SFTP, Anaconda
- mac下使用命令行打包出现bash gradle command not found的解决方案
命令行打包的时候出现 bash gradle command not found这个问题,主要是因为gradle环境丢失.需要重新配置gradle的环境变量. 1. gradle路径的查找 然后gra ...
- ECS_8080端口连接拒绝问题排查
原文链接 用户ECS网络设置 上图是用户ECS的网络示意图: ecs处于vpc网络下 ecs加入了一个安全组,该安全组出入方向均开放8080端口 ecs有两个网卡,一个私网主网卡(有虚线的网卡),一个 ...
- 一起学习java
一.Servlet学习 下面是Servlet一个整体的继承结构 首先说一下Servlet这个接口这个主要包含的有init,service,destroy等方法,这里主要介绍这3个 ...
- 数据库数据对比自动生成sql
1.故事背景 有一次迭代步入尾声,提交给用户测试,系统管理员在测试环境中初始了一些数据,然后在上线的时候系统管理员再去正式环境初始这一些数据,然而这次数据太多了,说了一次:”为什么要初始化两次?“ 你 ...
- weather API 天气api接口 收集整理
腾讯 http://sou.qq.com/online/get_weather.php?callback=Weather&city=南京 中国天气-weather.com.cn http:// ...
- 二分查找(binary search)
二分查找又叫折半查找,要查找的前提是检索结果位于已排序的列表中. 概念 在一个已排序的数组seq中,使用二分查找v,假如这个数组的范围是[low...high],我们要的v就在这个范围里.查找的方法是 ...
- eclipse下启动tomcat项目,访问tomcat默认端口显示404错误
解决:打开eclipse的server视图,双击你配置的那个tomcat,打开编辑窗口,查看server locations,看看是否选择了第一个选项(默认是第一个选项),即use workspace ...