虚析构函数
#include <iostream>
#include<string>
#include<cstdlib>
using namespace std;
class A
{
public:
~A()
{
cout << "A destructor" << endl;
}
};
class B :public A
{
~B()
{
cout << "B destructor" << endl;
}
};
int main()
{
A *pa = new B;
delete pa;
return 0;
}
运行结果:
A destructor // 只引发了 A 类的析构函数被调用,没有引发 B 类的析构函数
当将基类指针指向 new 运算符动态生成的派生类对象时,要通过 delete 来释放,应为该语句是静态联编的,编译器不可能知道此时 pa 指向哪个类型的对象,它只是根据 pa 类型是 A * ,来决定调用 A 类的析构函数,但实际上应该调用 B 类的析构函数才符合逻辑。
综上,delete pa
这样的语句应该根据 pa 所指的对象,来执行相应的析构函数。要实现这点,也用到了多态。因此,需要将基类的析构函数声明为虚函数,即虚析构函数。
改为:
class A
{
virtual ~A()
{
cout << "A destructor" << endl;
}
}
运行结果:
B destructor
A destructor
注意
派生类的析构函数会自动调用基类的析构函数。
一般,如果一个类定义了虚函数,则最好将析构函数也定义成虚函数。
只要在基类中某个函数被声明为虚函数,那么在派生类中,同名,同参数表的成员函数即使前面不写 virtual 关键字,也自动成为虚函数。
编译器看到是哪个类的指针,那么就会认为通过它访问的,就应该是哪个类的成员,编译器不会分析基类指针到底指向的是基类对象还是派生类对象。
#include <iostream>
using namespace std;
class A
{
public:
void fun()
{
cout << "A called" << endl;
}
};
class B :public A
{
void fun()
{
cout << "B called" << endl;
}
};
int main(void)
{
B b;
A *pa = &b;
pa->fun();
return 0;
}
运行结果:
A called
如果用上多态,则解决了这个问题:
#include <iostream>
using namespace std;
class A
{
public:
virtual void fun()
{
cout << "A called" << endl;
}
};
class B :public A
{
void fun()
{
cout << "B called" << endl;
}
};
int main(void)
{
B b;
A *pa = &b;
pa->fun();
return 0;
}
运行结果:
B called
由上,只在基类 A 中的 fun 函数前加了关键字 virtual (line 120),是该函数及其派生类中的同名,同参数表中的成员函数自动成为了虚函数,通过基类的指针调用虚函数时,就用到了多态。