如果沒有繼承,類只是具有一些相關行爲的數據結構,這只是對過程語言的一大改進,而繼承則開闢了完全不同的新天地。通過繼承,可以在已有類的基礎上創建新類。這樣,類就成爲可重用和可擴展的組件。博主的《漫談繼承技術》系列博文將講述各種利用繼承功能的方法。學習繼承的語法,和利用繼承的一些複製技術。本篇博文先給大家介紹一下重寫方法時的一些特殊情況,希望對大家加深對繼承技術的理解有一定的幫助。
重寫方法時的特殊情況
靜態基類方法
在C++中,不能重寫靜態方法。方法不可能既是靜態的又是虛擬的。如果派生類中存在的靜態方法與基類中的靜態方法同名,實際上這是兩個獨立的方法。舉個栗子。
#include <iostream>
using namespacestd;
//基類super
class super
{
public:
virtual~super(){}
staticvoidstaticFun();
};
//基類super的靜態方法
void super::staticFun()
{
cout<< "call: "<< __FUNCTION__ << endl;
}
//派生類sub繼承自super
class sub: public super
{
public:
virtual~sub(){}
staticvoidstaticFun();
};
//派生類sub的靜態方法,方法名稱和參數列表同基類完全一樣
void sub::staticFun()
{
cout<< "call: "<< __FUNCTION__ << endl;
}
int main(intargc,char**argv)
{
sub mysub = sub();
super &ref = mysub;
super *ptr = &mysub;
super::staticFun();
sub::staticFun();
mysub.staticFun();
ref.staticFun();
ptr->staticFun();
return0;
}
程序運行結果:
靜態方法屬於定義它的類所有,而不屬於特定的對象。當類中的方法調用靜態方法時,所調用的版本是通常的名稱解析來決定的。當使用對象、指針或引用調用類的靜態方法時,實際上並不涉及到調調用,只是用來判斷編譯時的類型,真正起作用的是類型信息。
private或protected基類方法
方法的訪問說明符會判斷誰可以調用這些方法,派生類無法調用基類的private方法(基類的private方法對於派生類不可見),但可以重寫這些方法。
#include <iostream>
using namespacestd;
//基類super
class super
{
public:
virtual~super(){}
virtualvoidcallshow() const;
private:
virtualvoidshow() const;
};
void super::callshow()const
{
cout<< "call: "<< __FUNCTION__ << "->";
show();
}
void super::show()const
{
cout<< "call: "<< __FUNCTION__ << endl;
}
//派生類sub繼承自super
class sub: public super
{
public:
virtual~sub(){}
private:
//派生類重寫基類的private方法
virtualvoidshow() const override;
};
void sub::show()const
{
cout<< "call: "<< __FUNCTION__ << endl;
}
int main(intargc,char**argv)
{
sub mysub = sub();
super *ptr = &mysub;
//調用基類的public方法
ptr->callshow();
return0;
}
程序運行結果:
注意到了麼?callshow調用的是派生類的show方法。通過重寫這個private方法,派生類完全修改了沒有更改的現有基類public方法的行爲。重寫private或protected方法可以在不做重大改動的情況下改變類的某些特性。對了,差點忘了,注意Java和C#僅允許重寫public和protected方法,不能重寫private方法。
基類方法具有默認參數
派生類與基類可以具有不同的默認參數,但使用的參數僅取決於聲明的變量類型,而不是底層的對象。舉個栗子。
#include <iostream>
using namespacestd;
//基類super
class super
{
public:
virtual~super(){}
virtualvoidshow(int nValue) const;
};
//給基類show方法指定默認參數
void super::show(intnValue= 10) const
{
cout<< "call: "<< __FUNCTION__ << " nValue = "<< nValue << endl;
}
//派生類sub繼承自super
class sub: public super
{
public:
virtual~sub(){}
virtualvoidshow(int nValue) constoverride;
};
//給派生類show方法指定默認參數
void sub::show(intnValue= 20) const
{
cout<< "call: "<< __FUNCTION__ << " nValue = "<< nValue << endl;
}
int main(intargc,char**argv)
{
sub mysub = sub();
super mysuper = super();
super *ptr = &mysub;
//通過派生類對象調用show方法
mysub.show();
//通過基類對象調用show方法
mysuper.show();
//通過指向派生類對象的基類指針調用show方法
ptr->show();
return0;
}
程序運行結果:
從程序運行結果可以看出,如果sub對象調用show(),將執行sub版本的show(),默認參數爲20。如果super對象調用show(),將執行super版本的show(),默認參數爲10。然而,如果使用實際指向sub對象的super指針或者super引用調用show(),將執行sub版本的show(),但使用super的默認參數10。
C++根據描述對象的表達式類型在編譯時綁定默認參數(也就是我們常說的靜態綁定),而不是根據實際的對象類型綁定參數。在C++中,默認參數不會被“繼承”。當重寫具有默認參數的方法時,也應該提供默認參數,這個參數的值應該與基類版本相同(這裏是爲了給大家舉個栗子,所有默認參數值取得不同)。建議使用符號常量做默認值,這樣可以在派生類中使用同一個符號常量。
派生類方法具有不同的訪問級別
在派生類繼承基類時,可以採用兩種方法來修改方法的訪問級別——可以加強限制,也可以放寬限制。
放寬限制
#include <iostream>
using namespacestd;
//基類super
class super
{
public:
super(){}
virtual~super(){}
protected:
//基類protected方法
virtualvoidshow(const std::string&str) const;
};
void super::show(conststd::string &str)const
{
cout<< __FUNCTION__ << ": "<< str << endl;
}
//派生類sub繼承基類super
class subfinal: public super
{
public:
sub(){}
virtual~sub(){}
//以public訪問說明重寫show方法,放寬限制
virtualvoidshow(const std::string&str) const override;
//提供訪問基類show方法的接口
voidcallshow(const std::string&str) const;
};
void sub::show(conststd::string &str)const
{
cout<< __FUNCTION__ << ": "<< str << endl;
}
void sub::callshow(conststd::string &str)const
{
cout<< __FUNCTION__ << "->";
__super::show(str);
}
int main()
{
//用基類指針指向派生類對象
sub *sp = new sub();
//調用的是派生類的show方法,基類方法被隱藏
sp->show("hello");
//通過派生類的public接口調用基類的protected方法
sp->callshow("hello");
//釋放資源
deletesp;
//將基類指針置爲nullptr,避免野指針
sp = nullptr;
return0;
}
程序運行結果:
上例中提供了兩種訪問show函數的方法,一種是重寫基類的show方法,另一種是在派生類中提供調用基類show方法的接口。
加強限制
#include <iostream>
using namespacestd;
//基類super
class super
{
public:
super(){}
virtual~super(){}
//基類public方法
virtualvoidshow(const std::string&str) const;
};
void super::show(conststd::string &str)const
{
cout<< __FUNCTION__ << ": "<< str << endl;
}
//派生類sub繼承基類super
class subfinal: public super
{
public:
sub(){}
virtual~sub(){}
protected:
//以protected訪問說明重寫show方法,加強限制
virtualvoidshow(const std::string&str) const override;
};
void sub::show(conststd::string &str)const
{
cout<< __FUNCTION__ << ": "<< str << endl;
}
int main()
{
sub mysub = sub();
//用基類指針指向派生類對象
super *sp = &mysub;
//mysub.show();
//通過基類類的public接口調用派生類的protected方法
sp->show("hello");
return0;
}
程序運行結果:
上例程序中,當我們通過sp訪問show方法時,無法限制訪問基類的public方法,再結合多態性,將調用派生類的protected方法。
如果想了解更多關於繼承技術相關的知識,請關注博主《漫談繼承技術》系列博文,相信你能夠在那裏尋找到更多有助你快速成長和深入你對繼承相關的知識和一些複製的技術理解和掌握。