1. 成員函式過載特徵
- 相同的範圍(在同一個類中)
- 函式名稱相同
- 引數不同
- virtual 關鍵字可有可無
2. 覆蓋的特徵
- 覆蓋是指派生類函式覆蓋基類函式,所以範圍不同(分別位於派生類和基類)
- 函式名稱相同
- 引數相同
- 基類函式必須有 virtual 關鍵字
如下示例中,函式 Base::f(int)與 Base::f(float)相互過載,而 Base::g(void)被 Derived::g(void)覆蓋。
#include <iostream.h>
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); // Base::f(int) 42
pb->f(3.14f); // Base::f(float) 3.14
pb->g(); // Derived::g(void)
}
3. 隱藏規則
- 如果派生類的函式與基類函式同名,但是引數不同。此時,無論有無 virtual 關鍵字,基類的函式都被隱藏。(主要與過載的區別,過載要在同一個類中)
- 如果派生類的函式與基類函式同名,並且引數也相同,但是基類函式沒有 virtual 關鍵字。此時,基類的函式被隱藏。(注意與覆蓋的區別,覆蓋有 virtual 關鍵字)
如下示例中:
-
- 函式 Derived::f(float)覆蓋了 Base::f(float)。
- 函式 Derived::g(int)隱藏了 Base::g(float),而不是過載。
- 函式 Derived::h(float)隱藏了 Base::h(float),而不是覆蓋。
#include <iostream.h>
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; }
};
4. 引數的預設值
- 引數預設值只能出現在函式的宣告中,而不能出現在定義體中。
- 如果函式有多個引數,引數只能從後向前挨個兒預設。
- 不合理地使用引數的預設值將導致過載函式產生二義性。
5. 不能被過載的運算子
- 不能改變 C++內部資料型別(如 int,float 等)的運算子。
- 不能過載‘ .’,因為‘ .’在類中對任何成員都有意義,已經成為標準用法。
- 不能過載目前 C++運算子集合中沒有的符號,如#,@,$等。原因有兩點,一是難以
理解,二是難以確定優先順序。 - 對已經存在的運算子進行過載時,不能改變優先順序規則,否則將引起混亂。
6. 函式內聯
1)內聯的工作過程:
對於任何行內函數,編譯器在符號表裡放入函式的宣告(包括名字、引數型別、返回值型別)。如果編譯器沒有發現行內函數存在錯誤,那麼該函式的程式碼也被放入符號表裡。在呼叫一個行內函數時,編譯器首先檢查呼叫是否正確(進行型別安全檢查,或者進行自動型別轉換,當然對所有的函式都一樣)。如果正確,行內函數的程式碼就會直接替換函式呼叫,於是省去了函式呼叫的開銷。這個過程與預處理有顯著的不同,因為前處理器不能進行型別安全檢查,或者進行自動型別轉換。假如行內函數是成員函式,物件的地址( this)會被放在合適的地方,這也是前處理器辦不到的。
2)行內函數的程式設計風格
- 關鍵字 inline 必須與函式定義體放在一起才能使函式成為內聯,僅將 inline 放在函式宣告前面不起任何作用。
- 定義在類宣告之中的成員函式將自動地成為行內函數。
3)內聯的注意事項
-
- 內聯是以程式碼膨脹(複製)為代價,僅僅省去了函式呼叫的開銷,從而提高函式的執行效率。如果執行函式體內程式碼的時間,相比於函式呼叫的開銷較大,那麼效率的收穫會很少。另一方面,每一處行內函數的呼叫都要複製程式碼,將使程式的總程式碼量增大,消耗更多的記憶體空間。
- 以下情況不宜使用內聯:
( 1)如果函式體內的程式碼比較長,使用內聯將導致記憶體消耗代價較高。
( 2)如果函式體內出現迴圈,那麼執行函式體內程式碼的時間要比函式呼叫的開銷大。 - 類的建構函式和解構函式容易讓人誤解成使用內聯更有效。要當心建構函式和解構函式可能會隱藏一些行為,如“偷偷地”執行了基類或成員物件的建構函式和解構函式。所以不要隨便地將建構函式和解構函式的定義體放在類宣告中。