1、多态:相同的消息传给不同的对象,产生了“不同形式的结果”。
//它是将派生类对象视为基类对象,并执行派生类的Swim()实现
//为了实现上述目的,需要把FIsh::Swim() 声明为虚函数,
//从而使派生类Tuna::Swim()和Crap::Swim()优先于被声明为虚函数的FIsh::Swim(),即进行覆盖
#include <iostream>
using namespace std;
class Fish
{
public:
virtual void Swim()
{
cout << "Fish swims!" << endl;
}
};
class Tuna :public Fish
{
public:
void Swim()
{
cout << "Tuna swims!" << endl;
}
};
class Carp :public Fish
{
public:
void Swim()
{
cout << "Crap swims!" << endl;
}
};
void MakeFishSwim(Fish& InputFish)
{
InputFish.Swim();
}
int main()
{
Tuna myDinner;
Carp myLunch;
MakeFishSwim(myDinner); //相同的消息传给不同的对象,产生了“不同形式的结果”
MakeFishSwim(myLunch);
return 0;
}
2、为什么需要虚构造函数?
对于使用new在自由存储区中实例化的派生类对象,如果将其赋给基类指针,并通过该指针调用delete,将不会调用派生类的析构函数。这可能导致资源未释放、内存泄漏等问题,必须引起重视,如下例。
#include <iostream>
using namespace std;
class Fish
{
public:
Fish()
{
cout << "Constructed Fish" << endl;
}
~Fish()
{
cout << "Destoryed Fish" << endl;
}
};
class Tuna :public Fish
{
public:
Tuna()
{
cout << "Constructed Tuna" << endl;
}
~Tuna()
{
cout << "Destoryed Tuna" << endl;
}
};
void DeleteFishMemeory(Fish* pFish)
{
delete pFish;
}
int main()
{
cout << "Allocating a Tuna on the free store:" << endl;
Tuna* pTuna = new Tuna;
cout << "Deleting the Tuna:" << endl;
DeleteFishMemeory(pTuna);
cout << "Instantiating a Tuna on the stack:" << endl;
Tuna myDinner;
cout << "Automatic destruction as it goes out of scope:" << endl;
return 0;
}
将析构函数声明为虚函数,确保通过基类指针调用delete时,将调用派生类的析构函数
#include <iostream>
using namespace std;
class Fish
{
public:
Fish()
{
cout << "Constructed Fish" << endl;
}
virtual ~Fish()
{
cout << "Destoryed Fish" << endl;
}
};
class Tuna :public Fish
{
public:
Tuna()
{
cout << "Constructed Tuna" << endl;
}
~Tuna()
{
cout << "Destoryed Tuna" << endl;
}
};
void DeleteFishMemeory(Fish* pFish)
{
delete pFish;
}
int main()
{
cout << "Allocating a Tuna on the free store:" << endl;
Tuna* pTuna = new Tuna;
cout << "Deleting the Tuna:" << endl;
DeleteFishMemeory(pTuna);
cout << "Instantiating a Tuna on the stack:" << endl;
Tuna myDinner;
cout << "Automatic destruction as it goes out of scope:" << endl;
return 0;
}
3、不能实例化的基类被称为抽象基类,这样的基类只有一个用途,那就是派生出其他类。在C++中,要创建抽象类,可声明纯虚函数。
通过声明类的一个或多个virtual函数为纯virtual函数,可以使一个类成为抽象类;
以下述方式声明的虚函数被称为纯虚函数:
class AbstractBase
{
public:
virtual void draw() const=0;
};
抽象基类提供了一种非常好的机制,让你能够声明所有派生类都必须实现的函数。如果Trout类从Fish类派生而来,但没有实现Trout::Swim(),将无法通过编译。
#include <iostream>
using namespace std;
//抽象基类提供了一种非常好的机制,让你能够声明所有派生类都必须实现的函数。
//如果Trout类从Fish类派生而来,但没有实现Trout::Swim(),将无法通过编译。
class Fish
{
public:
virtual void Swim() = 0;
};
class Tuna :public Fish
{
public:
void Swim()
{
cout << "Tuna swims fast in the sea!" << endl;
}
};
class Crap :public Fish
{
void Swim()
{
cout << "Crap swims slow in the lake!" << endl;
}
};
void MakerFishSwim(Fish& inputFish)
{
inputFish.Swim();
}
int main()
{
//Fish myFish;
Crap myLunch;
Tuna myDinner;
MakerFishSwim(myLunch);
MakerFishSwim(myDinner);
return 0;
}
4、使用多继承解决菱形问题
在继承层次结构中使用关键字virtual,将基类Animal的实例个数限定为1,如下例。只构造了一个Platypus。这是因为Animal类派生
Mammal、Bird和Reptile类时,使用了关键字virtual,这样Platypus继承这些类时,每个Platypus实例只能包含一个Animal实例。这样解决了很多问题,其中之一是第41行能通过编译,不再有二义性。
#include <iostream>
using namespace std;
class Animal
{
public:
Animal()
{
cout << "Animal constructor" << endl;
}
int Age;
};
class Mammal :public virtual Animal
{
};
class Bird:public virtual Animal
{
};
class Reptile :public virtual Animal
{
};
class Platypus :public Mammal, public Bird, public Reptile
{
public:
Platypus()
{
cout << "Platypus constructor" << endl;
}
};
int main()
{
Platypus duckBilledP;
duckBilledP.Age = 25;
}
C++关键字virtual的含义随上下文而异(我想这样做的目的很可能是为了省事),对其含义总结如下:
在函数声明中,virtual意味着当基类指针指向派生类对象时,通过它可调用派生类相应的函数。从Base类派生出Derived1和Derived2类时,如果使用了关键字virtual,则意味着再从Derived1和Derived2派生出Derived3时,,每个Derived3实例只包含一个Base实例。也就是说,关键字virtual被用于实现两个不同的概念。