内容参考于《21天学通C++》(第八版)
不去纠结C++的原理和细节,从C的角度去学习C++,再通过C++项目去加深理解
六.多态
1. 示例1
#include <iostream>
using namespace std;
class Fish
{
public:
void Swim()
{
cout << "Fish swims! " << endl;
}
};
class Tuna :public Fish
{
public:
// override Fish::Swim
void Swim()
{
cout << "Tuna swims!" << endl;
}
};
void MakeFishSwim(Fish& inputFish)
{
// calling Fish::Swim
inputFish.Swim();
}
int main()
{
Tuna myDinner;
// calling Tuna::Swim
myDinner.Swim();
// sending Tuna as Fish
MakeFishSwim(myDinner);
return 0;
}
运行结果
Tuna swims!
Fish swims!
理想情况下,用户希望 Tuna 对象表现出金枪鱼的行为,即便通过 Fish 参数调用 Swim( )时亦如此。换句话说,第 25 行调用 inputFish.Swim( )时,用户希望执行的是 Tuna::Swim( )。要实现这种多态行为—让 Fish 参数表现出其实际类型(派生类 Tuna)的行为,可将 Fish::Swim( )声明为虚函数。
2. 虚函数
修改前面Fish类
class Fish
{
public:
virtual void Swim()
{
cout << "Fish swims! " << endl;
}
};
运行结果
Tuna swims!
Tuna swims!
3. 一个问题点
将派生类对象传递给基类参数时,并通过该参数调用函数时,将执行基类的函数。然而,还存在一个问题:如果基类指针指向的是派生类对象,通过该指针调用运算符 delete 时,结果将如何呢?
对于使用 new 在自由存储区中实例化的派生类对象,如果将其赋给基类指针,并通过该指针调用 delete,将不会调用派生类的析构函数。这可能导致资源未释放、内存泄露等问题,必须引起重视。
所以一个更加完美的基类
class Fish
{
public:
virtual void Swim()
{
cout << "Fish swims! " << endl;
}
virtual ~Fish() // virtual destructor!
{
cout << "Destroyed Fish" << endl;
}
};