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++对象在三个地方构建:
无论在那里构建,其过程都是两步:首先,分配一块内存;其次,调用构造函数。好,问题来了,如果构造函数是虚函数,那么就需要通过
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++:构造函数和析构函数能否为虚函数
更多解读:
为什么C++的构造函数不可以是虚函数,而析构函数可以是虚函数