析构函数为什么要声明为虚 函数???
基类的析构函数需要声明为虚函数:
当派生类对象经由一个基类指针被删除,而该基类带着一个non-virtual析构函数,实际执行时通常发生的是对象的派生类成员没有被销毁。这也就是局部销毁,会发生内存泄漏,所以我们通常将基类的析构函数需要声明为虚函数。
class Base
{
public:
Base()
:_b(1)
{
cout << "Base()" << endl;
}
~Base()
{
cout << "~Base()" << endl;
}
protected:
int _b;
};
class Derived : public Base
{
public:
Derived()
:_d(2)
{
cout << "Derived()" << endl;
}
~Derived()
{
cout << "~Derivde()" << endl;
}
protected:
int _d;
};
void test()
{
Base *p;
p = new Derived;
delete p;
}
运行结果:
可以发现程序只删除了base class对象,造成了局部销毁。
解决:将基类的析构函数生命为virtual,此后删除派生类对象就会销毁整个对象,包括派生类成分。
class Base
{
public:
Base()
:_b(1)
{
cout << "Base()" << endl;
}
virtual ~Base()
{
cout << "~Base()" << endl;
}
protected:
int _b;
};
class Derived : public Base
{
public:
Derived()
:_d(2)
{
cout << "Derived()" << endl;
}
~Derived()
{
cout << "~Derivde()" << endl;
}
protected:
int _d;
};
void test()
{
Base *p;
p = new Derived;
delete p;
}
运行结果:
可以发现,如果将base class的析构函数声明为虚函数,就不存在局部销毁的问题。
注意:
1.任何类只要带有 virtual 函数都几乎应该也有一个 virtual 析构函数。
2.如果类不含 virtual 函数,通常表示他并不意图被用做一个基类。当类不企图被当作基类时候令其析构函数为virtual 往往是个馊主意,这个原因大家也可以想一下。
不能被声明为虚函数的函数
1.普通函数
普通函数只能被重载,不能被重写,声明为虚函数没有任何意义,因为编译器会在编译时绑定函数。
2.构造函数:
因为构造函数本身就是为了明确初始化对象成员才产生的。如果构造函数是虚函数,就需要通过 vtable 来调用,但是此时对象还没有实例化,无法找到 vtable ,所以不能为虚函数。
从实现上来看,vtable 是在构造函数调用之后才建立的,因而构造函数不能为虚函数,同时编译器也根本无法通过编译。
3.内联成员函数:
因为内联函数是为了在代码中直接展开,减少函数调用的花费,而虚函数是为了在继承后对象能够准确的执行自己的动作。
而且内联函数在编译时被展开,虚函数在运行时才能动态绑定。
4.静态成员函数:
静态成员函数对于每一个类来说只有一份,所有的对象公用一份代码,它的实现就不是为了构成多态,也没有要动态绑定的必要性。
5.友元函数:
因为友元函数并不支持继承,对于没有继承特性的函数没有虚函数的说法。