C++學習筆記----虛擬函式
阿新 • • 發佈:2021-01-28
技術標籤:C++
文章目錄
多型存在的問題
虛擬函式主要用於c++中的多型特性,對於類的繼承而言,如果用父類的指標指向子類的的物件,當用該指標操作子類物件時,該指標只能操作父類中的函式,而對於子類中特有的和過載的方法,用該指標將無法使用。案例:
class Base {//基類
public:
void test()
{
cout << "A" << endl;
}
};
class Derive :public Base{ //派生類
public:
void test()//派生類過載基類的test()
{
cout << "B" << endl;
}
void show()//派生類獨有的方法
{
cout << "show" << endl;
}
}
int main()
{
Base a;
Derive d;
//p1 p2均為Base類的指標
Base* p1 = &a;//p1指向Base類物件
Base* p2 = &d;//p2指向Derive類的物件
p1->test();//正確。呼叫A
p2->test();//呼叫Base類的test()
p2->show();//編譯錯誤,“Base中沒有成員show()”
}
虛擬函式擬要解決的問題
虛擬函式可以解決用父類的指標訪問子類中過載父類的函式上面案例的做出如下修改:
class Base {//基類
public:
virtual void test()
{
cout << "A" << endl;
}
};
class Derive : public Base{//派生類
public:
virtual void test()//派生類過載基類的test()
{
cout << "B" << endl;
}
void show()//派生類獨有的方法
{
cout << "show" << endl;
}
}
int main()
{
Base a;
Derive d;
//p1 p2均為Base類的指標
Base* p1 = &a;//p1指向Base類物件
Base* p2 = &d;//p2指向Derive類的物件
p1->test();//正確。呼叫A
p2->test();//呼叫Derive類的test()
p2->show();//編譯錯誤,“Base中沒有成員show()”
}
在需要過載的方法前面加上virtual關鍵字,就可以用父類的指標呼叫子類的過載方法。當基類中用虛擬函式時,其派生類在過載該虛擬函式時也是用虛擬函式的方式進行過載,過載虛擬函式時其關鍵字virtual可以省略,但是為了更直觀不建議省略。 進行虛擬函式過載時函式的引數和返回型別必須和原來父類的函式一樣。上述規則在有種情況下是不成立的,當函式返回的是類本身的指標或者引用。例子如下:
class Base {
public:
virtual Base * clone()
{
Base* p = new Base;
return p;
}
virtual void show()
{
cout << "test Base" << endl;
}
};
class Derive :public Base{
public:
virtual Derive* clone()
{
Derive* p = new Derive;
return p;
}
void show() {
cout << "test Derive" << endl;
}
};
int main()
{
Base a;
Derive d;
Base* p1 = a.clone();//呼叫基類的clone()函式
Base* p2 = d.clone();//呼叫派生類的clone()函式
p1->show();
p2->show();
delete p1;
delete p2;
}
final和override
虛擬函式過載時,如果引數和基類的引數不同則編譯器將會認為該函式為派生類的獨有的函式,為了能夠知道派生類是否正確的覆蓋了虛擬函式,C++中引入了關鍵字override,用以檢查派生類是否正確的覆蓋了虛擬函式。
只有虛擬函式的覆蓋才能在函式的後面加上override(加到引數列表、const、&符的後面)
當某個虛擬函式後面被加上final關鍵字後,表示該函式將不能夠被覆蓋,如果覆蓋這樣的虛擬函式則編譯器將會報錯。
虛擬函式的預設引數
虛擬函式中同樣可以定義預設引數,但是對於派生類而言,如果派生類的物件掉用虛擬函式時使用到了預設引數,那麼該預設引數將會是基類的預設引數。
class Base {
public:
virtual void show(int i=0)
{
cout << i << endl;
}
};
class Derive :public Base{
public:
void show(int i=1)
{
cout << i << endl;
}
};
Base a;
Derive d;
a.show();//列印結果為0
b.show();//列印結果為0,派生類的預設值為基類的值。