C++:构造函数和析构函数能否为虚函数
2015-09-12 15:12
316 查看
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); }
};
问题一:虚析构函数与普通虚函数有什么区别
首先,在C++中,每个类都只有一个析构函数,比如在子类Son中,便不能再添加父类father的虚函数virtual ~Father(void)的实现版本,这与普通虚函数是不同,普通虚函数是要在派生类中,重新给出父类中虚函数的实现,并且函数名相同(编译器实现的同名覆盖,会把所有析构函数解析为一个名字,如Destructor,故在子类中不会再添加父类的析构函数,因为子类有自己的析构函数,此时,若父类析构函数为虚函数,用子类对象的父类指针去访问父类析构函数其实就是多态,访问的为子类析构函数)。
问题二:虚析构函数的实现机制
虚析构函数,也是通过vftable来实现的,实际上当父类的析构函数声明为虚函数时,子类的析构函数也变成了虚函数(虽然两者函数名不同),即告诉编译器,我和我的派生类都需要动态(运行时)完成析构函数执行。
转自:/article/2375810.html
简单回答是:构造函数不能为虚函数,而析构函数可以且常常是虚函数。
(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); }
};
问题一:虚析构函数与普通虚函数有什么区别
首先,在C++中,每个类都只有一个析构函数,比如在子类Son中,便不能再添加父类father的虚函数virtual ~Father(void)的实现版本,这与普通虚函数是不同,普通虚函数是要在派生类中,重新给出父类中虚函数的实现,并且函数名相同(编译器实现的同名覆盖,会把所有析构函数解析为一个名字,如Destructor,故在子类中不会再添加父类的析构函数,因为子类有自己的析构函数,此时,若父类析构函数为虚函数,用子类对象的父类指针去访问父类析构函数其实就是多态,访问的为子类析构函数)。
问题二:虚析构函数的实现机制
虚析构函数,也是通过vftable来实现的,实际上当父类的析构函数声明为虚函数时,子类的析构函数也变成了虚函数(虽然两者函数名不同),即告诉编译器,我和我的派生类都需要动态(运行时)完成析构函数执行。
转自:/article/2375810.html
相关文章推荐
- C++设计模式——单例模式
- C++的sort函数逆序排序
- c语言-预处理指令
- ubuntu12.04 安装eclipse C++,并配置交叉编译工程
- C++基础知识
- [LeetCode] 036. Valid Sudoku (Easy) (C++)
- c++实现两个大整数相加(一)
- C++ <利用指针翻转字符串>
- C++程序中尽量避免#define
- C++中栈区 堆区 常量区
- C/C++常用头文件及函数汇总
- c++11——列表初始化
- C、C++: 引用、指针、实例、内存模型、namespace
- 一个c语言写的文件系统
- Effective C++ 条款47 请使用traits classes表现类型信息
- 【反思】一个价值两天的BUG,无论工作还是学习C语言的朋友都看看吧!
- 为什么C++编译器不支持模板头文件和实现代码分离的编译
- 一:c语言(数据类型和运算符)
- C 语言漫谈(一)
- 第二周项目1-C/C++语言中函数参数传递的三种方式