派生类多态
派生类实例 传入 基类引用参数。将派生类对象 视为基类对象,并 执行派生类的被覆盖函数。
ps.好吧,下面,我又刨根问底儿了:
覆盖的条件:
- 基类函数必须是虚函数(使用Virtual关键字进行声明);
- 发生覆盖的两个函数必须分别位于派生类和基类中;
- 函数名称与参数列表必须完全一样;
#include <iostream>
#include <stdlib.h>
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 << "Carp swims!" << endl;
}
};
void MakeFileSwim(Fish& inputFish){ //基类引用
inputFish.Swim();
}
int main(){
Tuna myDinner;
Carp myLunch;
Fish rice;
MakeFileSwim(myDinner); //调用Tune派生类Swim
MakeFileSwim(myLunch); //调用Carp派生类Swim
MakeFileSwim(rice); //调用Fish类Swim
return 0;
}
基类指针 指向 派生类对象,需要 在基类定义 虚析构函数。
堆上定义的派生类对象,若无虚构造函数,delete时 无法 析构派生类部分内存。
#include <iostream>
#include <stdlib.h>
using namespace std;
class Fish {
public:
Fish() {
cout << "Constructed Fish" << endl;
}
virtual ~Fish() { //虚析构函数 调用完这个 不影响调用派生类的析构函数
cout << "Destroyed Fish" << endl;
}
};
class Tuna :public Fish {
public:
Tuna() {
cout << "Constructed Tuna" << endl;
}
~Tuna() {
cout << "Destroyed Tuna" << endl;
}
};
void DeleteFishMemory(Fish* pFish) { //基类指针 指向 派生类实例
delete pFish;
}
int main() {
cout << "ALLOCATING A TUNA ON THE FREE STORE:" << endl;
Tuna* pTuna = new Tuna;
cout << "DELETING THE TUNA:" << endl;
DeleteFishMemory(pTuna);
system("pause");
return 0;
}
虚函数表
以上“派生类实例 传入 基类实例的引用参数”,派生类实例调用哪个覆盖函数 是在运行阶段决定的/即多态的逻辑决定的,这种逻辑是编译器在编译阶段提供的,即虚函数表。
编译器分别为 “实现了虚函数的基类” 和 “覆盖了虚函数的派生类” 分别创建一个虚函数表(VFT)。实例化基类或者派生类时,会为对应的类 创建一个隐藏的指针,指向相应的VFT。可以将VFT视为一个包含函数指针的静态数组,其中 每个指针都指向相应的虚函数的实现。
上图Derived类,除了Base类的Func2(),其余都进行了覆盖:
Derived obj;
obj.Func2(); //调用的是Base的Func2()
void DoSomething(Base& obj){
obj.Func1(); //obj传入派生类实例,基类Fun1虚函数被派生类覆盖,调用派生类Func1
}
int main(){
Derived obj;
DoSomething(obj);
}
抽象基类
不能实例化的基类!声明纯虚函数,可创建抽象基类。
抽象基类的派生类 必须 实现纯虚函数。
#include <iostream>
#include <stdlib.h>
using namespace std;
class Fish {
public:
virtual void Swim() = 0; //纯虚函数
};
class Tuna :public Fish {
public:
void Swim() { //派生类 必须对纯虚函数 进行实现
cout << "Tuna swim fast in the sea!" << endl;
}
};
void MakeFishSwim(Fish& inputFish) {
inputFish.Swim();
}
int main() {
Tuna mydinner;
MakeFishSwim(mydinner);
system("pause");
return 0;
}
虚继承
解决菱形继承 成员变量二义性问题,使用虚继承。
#include <iostream>
#include <stdlib.h>
using namespace std;
class Animal { //菱形结果 虚继承只进行一次 调用最上层基类的成员函数,拷贝成员变量
public:
Animal() {
cout << "Animal Constructor" << endl;
}
int age;
};
class Mammal:public virtual Animal{}; //virtual虚继承
class Bird:public virtual Animal{};
class Reptile:public virtual Animal {};
class Platypus final :public Mammal, public Bird, public Reptile {
public:
Platypus() {
cout << "Platypus constructor" << endl;
}
};
int main() {
Platypus duckBilledP;
duckBilledP.age = 25;
system("pause");
return 0;
}
//O:Animal Constructor
// Platypus constructor
override限定符:核实被覆盖的函数 在基类里 是否声明为虚的。
final:不能在派生类进行覆盖。
class Derived:public Base{
public:
void Swim() override{
cout << "valid Swin fun is a virtual fun in Base" << endl;
}
void Last() final{
cout << "forbid overlap in Derived's child" << endl;
}
};