C++:构造函数和析构函数能否为虚函数

原文:http://blog.csdn.net/xhz1234/article/details/6510568

C++:构造函数和析构函数能否为虚函数?

简单回答是:构造函数不能为虚函数,而析构函数可以且常常是虚函数。

(1) 构造函数不能为虚函数

让我们来看看大牛C++之父 Bjarne Stroustrup 在《The C++ Programming Language》里是怎么说的:

To construct an object, a constructor needs the exact type of the object it is to create. Consequently, a constructor cannot be virtual. Furthermore, a constructor is not quite an ordinary function, In particular, it interacts with memory management in ways ordinary member functions don‘t. Consequently, you cannot have a ponter to a constructor.

--- From 《The C++ Progamming Language》15.6.2

然而大牛就是大牛,这段话对一般人来说太难理解了。那下面就试着解释一下为什么:

这就要涉及到C++对象的构造问题了,C++对象在三个地方构建:(1)函数堆栈;(2)自由存储区,或称之为堆;(3)静态存储区。无论在那里构建,其过程都是两步:首先,分配一块内存;其次,调用构造函数。好,问题来了,如果构造函数是虚函数,那么就需要通过vtable 来调用,但此时面对一块 raw memeory,到哪里去找 vtable 呢?毕竟,vtable 是在构造函数中才初始化的啊,而不是在其之前。因此构造函数不能为虚函数。

(2)析构函数可以是虚函数,且常常如此

这个就好理解了,因为此时 vtable 已经初始化了;况且我们通常通过基类的指针来销毁对象,如果析构函数不为虚的话,就不能正确识别对象类型,从而不能正确销毁对象。

困惑我们的是我们却经常看到“虚构造函数”这样的说法,这就要归咎于不负责任或者说误人子弟的媒体了(包括书、技术文章等等)。因为他们说的是类似下面这样的做法:

class Expr {

public:

     Expr();

     Expr(const Expr&);

     virtual Expr* new_expr() { return new Expr(); }

     virtual Expr* clone() { return new Expr(*this); }

};

---转自Linux Tour

时间: 2024-11-08 13:23:03

C++:构造函数和析构函数能否为虚函数的相关文章

构造函数,析构函数是否为虚函数

1:构造函数不能为虚函数 1):虚函数是用父类指针引用子类对象用的,(父类)构造函数在被调用的时候,子类对象还没被创建,不能用虚函数 2):虚函数是通过vtable来调用的,vtable存在于对象的存储空间中,构造函数被调用的时候,对象还未生成,空间未分配, 因此构造函数不能为虚函数 2:析构函数可以为虚函数,而且尽量设置为虚函数 1):释放对象的时候,先调用子类的析构函数,再调用父类的析构函数. 非虚函数是静态绑定的,当去释放一个指向子类对象的父类指针时,如果父类的析构函数是非虚函数,这时就只

构造函数和析构函数中的虚函数

构造派生类对象时首先运行基类构造函数初始化对象的基类部分.在执行基类构造函数时,对象的派生类部分是未初始化的.实际上,此时对象还不是一个派生类对象. 撤销派生类对象时,首先撤销它的派生类部分,然后按照与构造顺序的逆序撤销它的基类部分. 在这两种情况下,运行构造函数或析构函数的时候,对象都是不完整的.为了适应这种不完整,编译器将对象的类型视为在构造或析构期间发生了变化.在基类构造函数或析构函数中,将派生类对象当作基类类型对象对待. 构造或析构期间的对象类型对虚函数的绑定有影响. 如果在构造函数或析

在构造函数和析构函数中调用虚函数------新标准c++程序设计

在构造函数和析构函数中调用虚函数不是多态,因为编译时即可确定调用的是哪个函数.如果本类有该函数,调用的就是本类的函数:如果本类没有,调用的就是直接基类的函数:如果基类没有,调用的就是间接基类的函数,以此类推.例如: #include<iostream> using namespace std; class A { public: virtual void hello(){cout<<"A::hello()"<<endl;} virtual void

C++进阶--构造函数和析构函数中的虚函数

//############################################################################ /* 任何时候都不要在构造函数或析构函数中调用虚函数 */ class dog { public: string m_name; dog(string name) {m_name = name; bark();} virtual void bark() { cout<< "Woof, I am just a dog "

[C++]在构造函数及析构函数中调用虚函数

(ISO/IEC 14882:2011 section 12.7.4): Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2).When a virtual function is called directly or indirectly from a constructor or from a destructor, inc

EC笔记,第二部分:9.不在构造、析构函数中调用虚函数

9.不在构造.析构函数中调用虚函数 1.在构造函数和析构函数中调用虚函数会产生什么结果呢? #include <iostream> using namespace std; class cls1{ public: cls1(){ newMake(); }; ~cls1(){ deleteIt(); }; virtual void newMake(){ cout<<"cls1 make"<<endl; } virtual void deleteIt()

虚析构函数与纯虚函数

虚析构函数 通过基类的指针删除派生类对象时,通常情况只调用基类的析构函数 但是,删除一个派生类对象时,应该先调用派生类的析构函数,然后调用基类的析构函数(构造时自顶向下,析构时自底向上) 这种情况会产生内存泄漏,最终导致系统应可用内存不足而崩溃 解决办法 把基类的析构函数声明为virtual,此时派生类的析构函数即使不声明为virtual也为virtual函数 在调用基类的指针删除派生类对象时,会先调用派生类的析构函数,最后调用基类的析构函数 一般方法 如果一个类定义了虚函数,那么析构函数也应该

为什么构造函数不能为虚函数,而析构函数可以为虚函数

1.  构造函数为什么不能为虚函数? a.  存储空间角度: 虚函数的调用需要虚函数表指针,而该指针存放在对象的内容空间中,需要调用构造函数才可以创建他的值,否则即使开辟了空间,则虚表指针为随机值,不会找到构造函数:若构造函数声明为虚函数,那么由于对象还未创建,还没有内存空间,更没有虚函数表地址用来调用虚函数——构造函数了. b.  使用上:  从实现上看,vbtl在构造函数调用后才建立,因而构造函数不可能成为虚函数: 虚函数主要是实现多态,在运行时才可以明确调用对象,根据传入的对象类型,来调用

第八章:不要在构造和析构函数中使用虚函数

前言 本文将讲解一个新手C++程序员经常会犯的错误 - 在构造/析构函数中使用虚函数,并分析错误原因所在以及规避方法. 错误起因 首先,假设我们以一个实现交易的类为父类,然后一个实现买的类,一个实现卖的类为其子类. 这三个类的对象初始化过程中,都需要完成注册的这么一件事情 (函数).然而,各自注册的具体行为是不同的. 有些人会写出以下这样的代码: 1 class Transaction { 2 public: 3 Transaction(); // 父类构造函数 4 //...... 5 pri