1、不要在构造函数中调用虚函数的原因

在概念上,构造函数的工作是为对象进行初始化。在构造函数完成之前,被构造的对象被认为“未完全生成”。当创建某个派生类的对象时,如果在它的基类的构造函数中调用虚函数,那么此时派生类的构造函数并未执行,所调用的函数(派生类的虚函数)可能操作还没有被初始化的成员,将导致灾难的发生。

2、不要在析构函数中调用虚函数的原因

同样的,在析构函数中调用虚函数,函数的入口地址也是在编译时静态决定的。也就是说,实现的是实调用而非虚调用。 
考察如下例子。

#include <iostream>
using namespace std; class A{
public:
virtual void show(){
cout<<"in A"<<endl;
}
virtual ~A(){show();}
}; class B:public A{
public:
void show(){
cout<<"in B"<<endl;
}
}; int main(){
A a;
B b;
}

程序输出结果是: 
in A 
in A

在类B的对象b退出作用域时,会先调用类B的析构函数,然后调用类A的析构函数,在析构函数~A()中,调用了虚函数show()。从输出结果来看,类A的析构函数对show()调用并没有发生虚调用。

从概念上说,析构函数是用来销毁一个对象的,在销毁一个对象时,先调用该对象所属类的析构函数,然后再调用其基类的析构函数,所以,在调用基类的析构函数时,派生类对象的“善后”工作已经完成了,这个时候再调用在派生类中定义的函数版本已经没有意义了。

因此,一般情况下,应该避免在构造函数和析构函数中调用虚函数,如果一定要这样做,必须清楚,这是对虚函数的调用其实是实调用

===============================补充=======================

Effective C++条款9讲构造函数中不要调用虚函数已经很清楚了,析构函数与其类似

我猜你的疑惑在于不了解基类与派生类析构函数的执行顺序,C++中派生类在构造时会先调用基类的构造函数再调用派生类的构造函数,析构时则相反,先调用派生类的析构函数再调用基类的构造函数。

假设一个派生类的对象进行析构,首先调用了派生类的析构,然后在调用基类的析构时,遇到了一个虚函数,这个时候有两种选择:Plan A是编译器调用这个虚函数的基类版本,那么虚函数则失去了运行时调用正确版本的意义;Plan B是编译器调用这个虚函数的派生类版本,但是此时对象的派生类部分已经完成析构,“数据成员就被视为未定义的值”,这个函数调用会导致未知行为。

实际情况中编译器使用的是Plan A,如果虚函数的基类版本不是纯虚实现,不会有严重错误发生,但你依然会困惑虚函数机制失效,说不准又是“一张通往彻夜调试的直达车票”,所以Effective C++建议不要这么干

(主要要清楚在继承中构造函数初始化的顺序(先基类后派生类)、析构函数调用的顺序(先派生类后基类))

【校招面试 之 C/C++】第10题 C++不在构造函数和析构函数中调用虚函数的更多相关文章

  1. 第十六周oj刷题——Problem E: B 构造函数和析构函数

    Description 在建立类对象时系统自己主动该类的构造函数完毕对象的初始化工作, 当类对象生命周期结束时,系统在释放对象空间之前自己主动调用析构函数. 此题要求: 依据主程序(main函数)和程 ...

  2. 【校招面试 之 网络】第3题 HTTP请求行、请求头、请求体详解

    1.HTTP请求报文解剖 HTTP请求报文由3部分组成(请求行+请求头+请求体): 下面是一个实际的请求报文: ①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE.HEA ...

  3. 【校招面试 之 网络】第2题 TCP的可靠传输、流量控制、滑动窗口

    1.可靠传输 (1)三次握手 TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接: (1)第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_S ...

  4. 【校招面试 之 网络】第1题 TCP和UDP

    TCP UDP1.TCP与UDP基本区别  (1)基于连接与无连接  (2)TCP要求系统资源较多,UDP较少:   (3)UDP程序结构较简单(头只有8个字节:源端口号.目标端口号.长度.差错)   ...

  5. 轻松搞定面试中的“虚"

    提要 今天要整理的知识点是C++中有关虚的一切. 包括:虚函数,纯虚函数,虚基类,虚继承... 1.什么是虚函数,有什么作用? 在基类用virtual声明成员函数为虚函数.这样就可以在派生类中重新定义 ...

  6. 【校招面试 之 C/C++】第9题 C++多态

    C++的多态性用一句话概括就是:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数.如果对象类型是派生类,就调用派生类的函数:如果对象类型是基类 ...

  7. 《剑指offer-名企面试官精讲典型编程题》读后感

    首先,不得不说这是一本好书!!! 我接触这本书是在学长的推荐下去看的,而且口碑还是挺好的一本书,豆瓣的评分也比较高,当我刚看了它,我就深深的爱上了这本书,到现在为止,我已经看了三遍这本书了,平时无聊时 ...

  8. TWinControl与TControl的覆盖函数(TWinControl对TControl的10个消息覆盖函数,17个覆盖函数,私有虚函数仍可多态)

    手工找出来,对比一下,有助于VCL框架的理解.----------------------------------------------------------------------------- ...

  9. 牛客网Java刷题知识点之构造函数可以调用一般函数,但是一般函数不可以直接调用构造函数

    不多说,直接上干货! 通过 牛客网Java刷题知识点之构造函数是什么.一般函数和构造函数什么区别呢.构造函数的重载.构造函数的内存图解 我们对构造函数有了一个比较清楚的认识,当我们在创建对象时,我们会 ...

随机推荐

  1. 1065 A+B and C (64bit) (20 分)

    1065 A+B and C (64bit) (20 分) Given three integers A, B and C in [−2^​63​​,2​^63​​], you are suppose ...

  2. Thread 1 cannot allocate new log的问题分析 (转载)

    Thread 1 cannot allocate new log的问题分析 发生oracle宕机事故,alert文件中报告如下错误: Fri Jan 12 04:07:49 2007Thread 1 ...

  3. Spark分析之DAGScheduler

    DAGScheduler概述:是一个面向Stage层面的调度器: 主要入参有: dagScheduler.runJob(rdd, cleanedFunc, partitions, callSite, ...

  4. Memcached缓存框架

    开发基于BS模式的程序,都有报表模块,那么如何开发报表模块. 1.定时发布报表数据到指定的临时表(可能是定时任务) 2.用户通过HTTP请求后台,访问临时表,查询报表数据 3.增加memcached缓 ...

  5. 基于Linux的Samba开源共享解决方案测试(二)

    单NAS网关50Mb码率视音频文件的稳定读测试结果如下: 50Mb/s负载性能记录 NAS网关资源占用 稳定读 稳定读 CPU空闲 内存空闲 网卡占用 13个稳定流 96.70% 10G 104MB/ ...

  6. Python数据分析_Pandas01_数据框的创建和选取

    主要内容: 创建数据表 查看数据表 数据表索引.选取部分数据 通过标签选取.loc 多重索引选取 位置选取.iloc 布尔索引 Object Creation 新建数据 用list建series序列 ...

  7. RNN循环神经网络结构

    note: RNN处理有序的数据.例如一句话 一层双向的循环神经网络示意图(没有 S0' 则为单层循环): 正向循环S0 到 Si:y1的值受X1,A1以及上一层的A0影响 反向循环Si 到 S0:y ...

  8. 尝试了一些时间,最简单的apache上设置用IP访问一个虚拟目录

    就是其实新建一个 多域名访问的设置 <VirtualHost *:80> DocumentRoot /var/www/ ServerName IP</VirtualHost> ...

  9. DistCp 集群之间数据拷贝工具

    DistCp(分布式拷贝)是用于大规模集群内部和集群之间拷贝的工具.可以将数据拷贝到另个一集群,也可以将另一个集群的数据拷贝到本集群.

  10. socket编程一些注意的东西

    帮一个同学做了一下面试的作业.主要是socket编程要写一个多人博彩游戏室.没注意,被一些地方坑了一下,而且其实如果没有这个概念,还不好发现. 1.readLine() http://blog.csd ...