c++支持編譯時多態(tài)(靜態(tài)多態(tài))和運行時多態(tài)(動態(tài)多態(tài)),運算符重載和函數(shù)重載是編譯時多態(tài),而派生類和虛函數(shù)實現(xiàn)運行時多態(tài)。
運行時多態(tài):在父類上聲明虛函數(shù),發(fā)生了多態(tài)。
父類的引用或指針指向子類的對象
虛函數(shù)
格式:
virtual 返回值 函數(shù)名();
例:
class Animal
{
public:
Animal()
{
}
//虛函數(shù)
virtual void speak()
{
cout << "動物在說話" << endl;
}
};
class Cat:public Animal
{
public:
//子類寫父類中的虛函數(shù)這種寫法叫重寫,重寫必須返回值 參數(shù)個數(shù) 類型 順序都相同
void speak()
{
cout << "貓在說話" << endl;
}
};
void doSpeak(Animal &Animal)
{
Animal.speak();
}
void test()
{
Animal* cat = new Cat;
doSpeak(*cat);
}
多態(tài)原理:
當父類中有了虛函數(shù)后,內(nèi)部結(jié)構(gòu)就發(fā)生了改變
內(nèi)部多了一個vfprt(虛函數(shù)指針),指向vftable虛函數(shù)表
父類中結(jié)構(gòu) vtptr &Animal::speak
子類中 進行繼承 會繼承vfptr (虛函數(shù)指針)、 vftable(虛函數(shù)表)
在構(gòu)造函數(shù)中,會將虛函數(shù)表指針指向自己的虛函數(shù)表
-
如果發(fā)生了重寫,會替換掉虛函數(shù)表中原有的speak,改為&Cat::speak
多態(tài)優(yōu)點
開發(fā)有原則 :開閉原則 ---對擴展開放 對修改關(guān)閉
利用多態(tài)實現(xiàn) :利用后期擴展,結(jié)構(gòu)性非常好,可讀性高,多態(tài)內(nèi)部結(jié)構(gòu)復雜
缺點
效率稍微低一些
純虛函數(shù)
如果父類中有了純虛函數(shù),子類繼承父類,就必須要實現(xiàn)純虛函數(shù)
如果父類中有了純虛函數(shù),這個父類就無法實例化對象了,通常又稱為抽象類
格式:virtual 返回值 函數(shù)名()=0;
例:
class abstractCalculator
{
public:
//虛函數(shù)
/*virtual int getResult()
{
return 0;
}*/
//純虛函數(shù)
virtual int getResult()=0;
void setVal1(int val1)
{
this->val1 = val1;
}
void setVal2(int val2)
{
this->val2 = val2;
}
int getVal1()
{
return val1;
}
int getVal2()
{
return val2;
}
int val1;
int val2;
};
class PlusCalculator :public abstractCalculator
{
public:
int getResult()
{
return val1 + val2;
}
};
class SubCalculator :public abstractCalculator
{
public:
int getResult()
{
return val1 - val2;
}
};
調(diào)用:
void show(abstractCalculator& a)
{
cout<<a.getResult()<<endl;
}
void test()
{
abstractCalculator * a=new PlusCalculator;
a->setVal1(10);
a->setVal2(20);
show(*a);
}
虛析構(gòu)
普通析構(gòu)不會調(diào)用子類的析構(gòu),所有可能會導致清理不干凈
利用虛析構(gòu)來解決這個問題。
格式:virtual ~類名()();
純虛析構(gòu)
純虛構(gòu)需要聲明還需要實現(xiàn),類內(nèi)聲明,類外實現(xiàn)。
如果出現(xiàn)了純虛析構(gòu)函數(shù),這個類也算抽象類,不可以實例這個對象
格式:
virtual ~類名()()=0;