“overload”翻譯過來就是:超載,過載,重載,超出標準負荷;“override”翻譯過來是:重置,覆蓋,使原來的失去效果。
先來說說重載的含義,在日常生活中我們經(jīng)常要清洗一些東西,比如洗車、洗衣服。盡管我們說話的時候并沒有明確地說用洗車的方式來洗車,或者用洗衣服的方式來洗一件衣服,但是誰也不會用洗衣服的方式來洗一輛車,否則等洗完時車早就散架了。考試大提示我們并不要那么明確地指出來就心知肚明,這就有重載的意思了。在同一可訪問區(qū)內(nèi)被聲名的幾個具有不同參數(shù)列的(參數(shù)的類型、個數(shù)、順序不同)同名函數(shù),程序會根據(jù)不同的參數(shù)列來確定具體調(diào)用哪個函數(shù),這種機制叫重載,重載不關(guān)心函數(shù)的返回值類型。這里,“重載”的“重”的意思不同于“輕重”的“重”,它是“重復”、“重疊”的意思。例如在同一可訪問區(qū)內(nèi)有:
① double calculate(double);
② double calculate(double,double);
③ double calculate(double, int);
④ double calculate(int, double);
⑤ double calculate(int);
⑥ float calculate(float);
⑦ float calculate(double);
六個同名函數(shù)calculate,①②③④⑤⑥中任兩個均構(gòu)成重載,⑥和⑦也能構(gòu)成重載,而①和⑦卻不能構(gòu)成重載,因為①和⑦的參數(shù)相同。
覆蓋是指派生類中存在重新定義的函數(shù),其函數(shù)名、參數(shù)列、返回值類型必須同父類中的相對應(yīng)被覆蓋的函數(shù)嚴格一致,覆蓋函數(shù)和被覆蓋函數(shù)只有函數(shù)體(花括號中的部分)不同,當派生類對象調(diào)用子類中該同名函數(shù)時會自動調(diào)用子類中的覆蓋版本,而不是父類中的被覆蓋函數(shù)版本,考試大,提示這種機制就叫做覆蓋。
下面我們從成員函數(shù)的角度來講述重載和覆蓋的區(qū)別。
成員函數(shù)被重載的特征有:
1) 相同的范圍(在同一個類中)
2) 函數(shù)名字相同
3) 參數(shù)不同
4) virtual關(guān)鍵字可有可無
覆蓋的特征有:
1) 不同的范圍(分別位于派生類與基類)
2) 函數(shù)名字相同
3) 參數(shù)相同
4) 基類函數(shù)必須有virtual關(guān)鍵字
比如,在下面的程序中:
#include
using namespace std;
class Base
{
public:
void f(int x){ cout << "Base::f(int) " << x << endl; }
void f(float x){ cout << "Base::f(float) " << x << endl; }
virtual void g(void){ cout << "Base::g(void)" << endl;}
};
class Derived : public Base
{
public:
virtual void g(void){ cout << "Derived::g(void)" << endl;}
};
void main(void)
{
Derived d;
Base *pb = &d;
pb->f(42); // 運行結(jié)果: Base::f(int) 42
pb->f(3.14f); // 運行結(jié)果: Base::f(float) 3.14
pb->g(); // 運行結(jié)果: Derived::g(void)
}
函數(shù)Base::f(int)與Base::f(float)相互重載,而Base::g(void)被Derived::g(void)覆蓋。
隱藏是指派生類的函數(shù)屏蔽了與其同名的基類函數(shù),規(guī)則如下:
1) 如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。此時,不論有無virtual關(guān)鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆)。
2) 如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒有virtual關(guān)鍵字。此時,基類的函數(shù)被隱藏(注意別與覆蓋混淆)。
比如,在下面的程序中:
#include
using namespace std;
class Base
{
public:
virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
void g(float x){ cout << "Base::g(float) " << x << endl; }
void h(float x){ cout << "Base::h(float) " << x << endl; }
};
class Derived : public Base
{
public:
virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
void g(int x){ cout << "Derived::g(int) " << x << endl; }
void h(float x){ cout << "Derived::h(float) " << x << endl; }
};
通過分析可得:
1) 函數(shù)Derived::f(float)覆蓋了Base::f(float)
2) 函數(shù)Derived::g(int)隱藏了Base::g(float),注意,不是重載
3) 函數(shù)Derived::h(float)隱藏了Base::h(float),而不是覆蓋
看完前面的示例,可能大家還沒明白隱藏與覆蓋到底有什么區(qū)別,因為我們前面都是講的表面現(xiàn)象,怎樣的實現(xiàn)方式,屬于什么情況。下面我們就要分析覆蓋與隱藏在應(yīng)用中到底有什么不同之處。在下面的程序中bp和dp指向同一地址,按理說運行結(jié)果應(yīng)該是相同的,可事實并非如此。
void main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); //運行結(jié)果: Derived::f(float) 3.14
pd->f(3.14f); //運行結(jié)果: Derived::f(float) 3.14
// Bad : behavior depends on type of the pointer
pb->g(3.14f); //運行結(jié)果: Base::g(float) 3.14
pd->g(3.14f); //運行結(jié)果: Derived::g(int) 3
// Bad : behavior depends on type of the pointer
pb->h(3.14f); //運行結(jié)果: Base::h(float) 3.14
pd->h(3.14f); //運行結(jié)果: Derived::h(float) 3.14
}
Examda提示: f()函數(shù)屬于覆蓋,而g()與h()屬于隱藏。從上面的運行結(jié)果,我們可以注意到在覆蓋中,用基類指針和派生類指針調(diào)用函數(shù)f()時,系統(tǒng)都是執(zhí)行的派生類函數(shù)f(),而非基類的f(),這樣實際上就是完成的“接口”功能。而在隱藏方式中,用基類指針和派生類指針調(diào)用函數(shù)f()時,系統(tǒng)會進行區(qū)分,基類指針調(diào)用時,系統(tǒng)執(zhí)行基類的f(),而派生類指針調(diào)用時,系統(tǒng)“隱藏”了基類的f(),執(zhí)行派生類的f(),這也就是“隱藏”的由來。
先來說說重載的含義,在日常生活中我們經(jīng)常要清洗一些東西,比如洗車、洗衣服。盡管我們說話的時候并沒有明確地說用洗車的方式來洗車,或者用洗衣服的方式來洗一件衣服,但是誰也不會用洗衣服的方式來洗一輛車,否則等洗完時車早就散架了。考試大提示我們并不要那么明確地指出來就心知肚明,這就有重載的意思了。在同一可訪問區(qū)內(nèi)被聲名的幾個具有不同參數(shù)列的(參數(shù)的類型、個數(shù)、順序不同)同名函數(shù),程序會根據(jù)不同的參數(shù)列來確定具體調(diào)用哪個函數(shù),這種機制叫重載,重載不關(guān)心函數(shù)的返回值類型。這里,“重載”的“重”的意思不同于“輕重”的“重”,它是“重復”、“重疊”的意思。例如在同一可訪問區(qū)內(nèi)有:
① double calculate(double);
② double calculate(double,double);
③ double calculate(double, int);
④ double calculate(int, double);
⑤ double calculate(int);
⑥ float calculate(float);
⑦ float calculate(double);
六個同名函數(shù)calculate,①②③④⑤⑥中任兩個均構(gòu)成重載,⑥和⑦也能構(gòu)成重載,而①和⑦卻不能構(gòu)成重載,因為①和⑦的參數(shù)相同。
覆蓋是指派生類中存在重新定義的函數(shù),其函數(shù)名、參數(shù)列、返回值類型必須同父類中的相對應(yīng)被覆蓋的函數(shù)嚴格一致,覆蓋函數(shù)和被覆蓋函數(shù)只有函數(shù)體(花括號中的部分)不同,當派生類對象調(diào)用子類中該同名函數(shù)時會自動調(diào)用子類中的覆蓋版本,而不是父類中的被覆蓋函數(shù)版本,考試大,提示這種機制就叫做覆蓋。
下面我們從成員函數(shù)的角度來講述重載和覆蓋的區(qū)別。
成員函數(shù)被重載的特征有:
1) 相同的范圍(在同一個類中)
2) 函數(shù)名字相同
3) 參數(shù)不同
4) virtual關(guān)鍵字可有可無
覆蓋的特征有:
1) 不同的范圍(分別位于派生類與基類)
2) 函數(shù)名字相同
3) 參數(shù)相同
4) 基類函數(shù)必須有virtual關(guān)鍵字
比如,在下面的程序中:
#include
using namespace std;
class Base
{
public:
void f(int x){ cout << "Base::f(int) " << x << endl; }
void f(float x){ cout << "Base::f(float) " << x << endl; }
virtual void g(void){ cout << "Base::g(void)" << endl;}
};
class Derived : public Base
{
public:
virtual void g(void){ cout << "Derived::g(void)" << endl;}
};
void main(void)
{
Derived d;
Base *pb = &d;
pb->f(42); // 運行結(jié)果: Base::f(int) 42
pb->f(3.14f); // 運行結(jié)果: Base::f(float) 3.14
pb->g(); // 運行結(jié)果: Derived::g(void)
}
函數(shù)Base::f(int)與Base::f(float)相互重載,而Base::g(void)被Derived::g(void)覆蓋。
隱藏是指派生類的函數(shù)屏蔽了與其同名的基類函數(shù),規(guī)則如下:
1) 如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。此時,不論有無virtual關(guān)鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆)。
2) 如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒有virtual關(guān)鍵字。此時,基類的函數(shù)被隱藏(注意別與覆蓋混淆)。
比如,在下面的程序中:
#include
using namespace std;
class Base
{
public:
virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
void g(float x){ cout << "Base::g(float) " << x << endl; }
void h(float x){ cout << "Base::h(float) " << x << endl; }
};
class Derived : public Base
{
public:
virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
void g(int x){ cout << "Derived::g(int) " << x << endl; }
void h(float x){ cout << "Derived::h(float) " << x << endl; }
};
通過分析可得:
1) 函數(shù)Derived::f(float)覆蓋了Base::f(float)
2) 函數(shù)Derived::g(int)隱藏了Base::g(float),注意,不是重載
3) 函數(shù)Derived::h(float)隱藏了Base::h(float),而不是覆蓋
看完前面的示例,可能大家還沒明白隱藏與覆蓋到底有什么區(qū)別,因為我們前面都是講的表面現(xiàn)象,怎樣的實現(xiàn)方式,屬于什么情況。下面我們就要分析覆蓋與隱藏在應(yīng)用中到底有什么不同之處。在下面的程序中bp和dp指向同一地址,按理說運行結(jié)果應(yīng)該是相同的,可事實并非如此。
void main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); //運行結(jié)果: Derived::f(float) 3.14
pd->f(3.14f); //運行結(jié)果: Derived::f(float) 3.14
// Bad : behavior depends on type of the pointer
pb->g(3.14f); //運行結(jié)果: Base::g(float) 3.14
pd->g(3.14f); //運行結(jié)果: Derived::g(int) 3
// Bad : behavior depends on type of the pointer
pb->h(3.14f); //運行結(jié)果: Base::h(float) 3.14
pd->h(3.14f); //運行結(jié)果: Derived::h(float) 3.14
}
Examda提示: f()函數(shù)屬于覆蓋,而g()與h()屬于隱藏。從上面的運行結(jié)果,我們可以注意到在覆蓋中,用基類指針和派生類指針調(diào)用函數(shù)f()時,系統(tǒng)都是執(zhí)行的派生類函數(shù)f(),而非基類的f(),這樣實際上就是完成的“接口”功能。而在隱藏方式中,用基類指針和派生類指針調(diào)用函數(shù)f()時,系統(tǒng)會進行區(qū)分,基類指針調(diào)用時,系統(tǒng)執(zhí)行基類的f(),而派生類指針調(diào)用時,系統(tǒng)“隱藏”了基類的f(),執(zhí)行派生類的f(),這也就是“隱藏”的由來。