重寫(override)
首先,重寫是指派生類的方法覆蓋基類的方法,要求方法名、方法的參數都相同。重寫是C++中實現多態這個特性基礎。重寫又稱為覆蓋,是指派生類函數覆蓋基類函數,與重定義不同,重寫要求被重寫的基類函數為虛函數。
例如下面的代碼:
class Base{
public:
virtual int Total(int unit_price, int num) = 0;
};
class Derived :public Base{
public:
virtual int Total(int unit_price, int num)
{
cout << "test" << endl;
return 0;
}
};
class Child :public Derived{
public:
int Total(int unit_price, int num)
{
//
return unit_price*num;
}
};
總結一下,重寫是指派生類重新定義了基類的虛函數,基類函數必須有virtual關鍵字修飾,不能有static關鍵字;返回值類型必須是相同的,或者是協變的;此外重寫函數的訪問修飾符可以不同。
注意:一般重寫要求函數具有完全相同的入參,否則就會提示錯誤,而這個規則對於協變而言則有所放松。覆蓋的返回值不區分基類或者派生類,如下代碼:
class Base{
public:
virtual int Total(int unit_price, int num)
{
cout << "Base" << endl;
return 0;
}
};
class Derived :public Base{
public:
virtual int Total(int unit_price, int num)
{
cout << "test" << endl;
return 1;
}
};
//協變
class Father{
public:
virtual const Base& getClass() = 0;
};
class Child{
virtual const Derived& getClass()
{
Derived ret;
return ret;
}
};
在上面協變的例子中,要求Base和Derived兩個類必須在使用前被完整的定義。
協變返回類型的優勢在於,若是我們使用Father,就能獲得一個抽象的Base,如果我們正在處理Child,就會獲得一個Derived。協變的返回機制將我們從這樣一種處境中解脫出來:不得不使用易於出錯的轉換操作來“重新”提供類型信息,而這種信息是一開始就不應該丟掉的。
重載(overload)
然后是重載(overload),重載是應用於相同作用域之內的同名函數,由於參數列表不同而產生的不同的實現方法。此處提到的作用域有:全局作用域、局部作用域以及類作用域,當在同一個作用域內的時候同名的函數或者稱之為方法,由於參數列表的不同,而獲得的不同的函數。
int Sum(int a, int b);
int Sum(int a, int b, int c);
int Sum(float a, float b);
重載是一種語言特性,是一種語法規則,與多態無關,與面向對象無關。
重定義
重定義則是經常出現在基類和派生類之間,歸結起來有如下的特點:
1)不在同一個作用域,主要是指類作用域,分別位於基類和派生類之中;
2)函數名稱相同,但是返回值可以不同;
3)參數不同時,無論有沒有virtual關鍵字,基類的函數都會被隱藏;參數相同時,但是基類函數沒有關鍵字virtual,此時基類函數被隱藏。
例如:
class Base{
public:
virtual double Total(double a, double b)
{
return a + b;
}
void Print()
{
cout << "Base" << endl;
}
int Sum(int a, int b);
private:
//
};
class Derived :public Base{
public:
virtual double Total(double a, double b, double c)
{
return a + b + c;
}
void Print()
{
cout << "Derived" << endl;
}
int Sum(int a, int b, int c);
};
在運行Derived的實例的時候可以很容易的發現,基類中Sum函數被隱藏了。因此重定義又稱為隱藏,是指派生類的函數屏蔽了與其同名的基類函數。
int _tmain(int argc, _TCHAR* argv[])
{
Derived test;
test.Print();
Derived test_b;
Base *p;
p = new Derived;
p->Print();
Base *p_2;
p_2 = &test_b;
p_2->Print();
delete p;
system("pause");
return 0;
}
例如上面的類,我們在如上調用的時候得到了下面的輸出: