程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++派生類中定義基類的虛函數時需注意的事項

C++派生類中定義基類的虛函數時需注意的事項

編輯:C++入門知識

先給出文字說明,然後再給出代碼解釋:
  如果我們決定改寫基類所提供的虛擬函數,那麼派生類所提供的新定義,其函數型別必須完全符合基類所聲明的函數原型,包括:參數列、返回型別、常量性(const-ness)。
  下面給出程序說明:基類num_sequence中聲明虛擬函數what_am_i(),派生類中改寫該函數。
  1、正確的寫法
  1.1 基類的聲明
1 #pragma once
2
3 class num_sequence
4 {
5 public:
6     num_sequence(void);
7     virtual const char* what_am_i() const { return "num_sequence \n"; } //注意這裡的兩個const
8     virtual ~num_sequence(void);

  1.2 派生類中正確的改寫
#pragma once
#include "num_sequence.h"

class Fibonacci :
    public num_sequence
{
public:
    Fibonacci(void);
    virtual const char* what_am_i() const { return "Fibonacci \n"; } //同樣注意這裡的兩個const,少哪個都不行,
                                        //後面詳解少其中任何一個const的運行情況www.2cto.com
    ~Fibonacci(void);
};


   上述是正確的改寫,下面給出兩種缺少const的錯誤改寫:
2.1 少 函數後面的const(即第二個const)
  Wrong1
 1 #pragma once
 2 #include "num_sequence.h"
 3
 4 class Fibonacci :
 5     public num_sequence
 6 {
 7 public:
 8     Fibonacci(void);
 9     virtual const char* what_am_i() { return "Fibonacci \n"; } //注意這裡少了const
10     ~Fibonacci(void);
11 };

main函數中測試:
 1 // EssentialCppP162.cpp : 定義控制台應用程序的入口點。
 2 //
 3
 4 #include "stdafx.h"
 5
 6 #include "Fibonacci.h"
 7 #include <iostream>
 8
 9 using namespace std;
10 int _tmain(int argc, _TCHAR* argv[])
11 {
12     Fibonacci b;
13     num_sequence p;
14     num_sequence *pp = &b;
15     cout << pp->what_am_i();
16     cout << b.what_am_i();
17     return 0;
18 }

輸出的結果為:
num_sequence
Fibonacci
請按任意鍵繼續. . .
 
解釋:這裡子類Fibonacci中並沒有改寫基類的what_am_i(),而是重新定義了一個what_am_i()函數(PS:這裡說成是重載what_am_i()更合適)。所以盡管pp是指向子類的指針,但子類沒有重定義該虛函數,最後就調用的是基類的what_am_i()函數,輸出num_sequence。而b.what_am_i()則因為b為非const,會調用Fibonacci中的what_am_i())。(PPS:這裡如果是const num_sequence *pp = &b; cout << pp->what_am_i(); 輸出也是num_sequence,原因不說了。)
PS:這裡Essential C++ P161上說的是在 Intel C++編譯器上編譯時,會輸出警告: warning #653: "const char *Fibonacci::what_am_i()" does not match "num_sequence::what_am_i" -- virtual function override intended?
  但我在VS200中文版中測試時候完全沒有警告,所以寫改寫基類虛擬函數時候一定要小心,盡量用ctrl+c從基類中復制過來,防止手動敲入函數名字時出錯。
2.2 少函數返回類型中的的const(即前面的那個const)
  Wrong2
 1 #pragma once
 2 #include "num_sequence.h"
 3
 4 class Fibonacci :
 5     public num_sequence
 6 {
 7 public:
 8     Fibonacci(void);
 9     virtual char* what_am_i() const { return "Fibonacci \n"; }
10     ~Fibonacci(void);
11 };


  此種情況編譯器不會通過編譯,因為函數重載不是根據返回類型來定的,所以編譯器會認為這裡的what_am_i()是繼承的基類的函數。然後根據本篇文章開頭說的函數型別必須完全符合基類的聲明,這裡就會報錯。VS2008下報錯為:
  1>e:\vsprog\臨時測試文件夾\essentialcppp162\essentialcppp162\fibonacci.h(11) : error C2555: “Fibonacci::what_am_i”: 重寫虛函數返回類型有差異,且不是來自“num_sequence::what_am_i”的協變
  1>e:\vsprog\臨時測試文件夾\essentialcppp162\essentialcppp162\num_sequence.h(7) : 參見“num_sequence::what_am_i”的聲明
 
2.3 兩個const都少了
  Wrong3
 1 #pragma once
 2 #include "num_sequence.h"
 3
 4 class Fibonacci :
 5     public num_sequence
 6 {
 7 public:
 8     Fibonacci(void);
 9     virtual char* what_am_i() { return "Fibonacci \n"; }
10     ~Fibonacci(void);
11 };

這和第一種錯誤一樣,都是一個重載的函數,而不是改寫基類的虛擬函數。。
 
關於繼承基類的虛擬函數的說明就到此結束。最後說一下改寫基類的虛擬函數時,子類中聲明不一定非得加上關鍵詞virtual。編譯器會依據兩個函數的原型聲明,決定某個函數是否會改寫其基類中的同名函數( 比如這裡1.2中可以寫成這樣const char* what_am_i() const { return "Fibonacci \n"; } )。
 
 
=============================
補充:
  “返回型別必須完全吻合” 這一規則有個例外:當基類的虛擬函數返回某個基類形式(通常是pointer或reference)時:派生類中的同名函數便可以返回該基類所派生出來的型別:舉例如下(尚不知道這裡實際工程項目中的用處):
基類num_sequnece: virtual num_sequence *clone() = 0;
子類Fibonacci: [virtual] Fibonacci *clone() { return new Fibonacci ( *this ); }

 

摘自  ziyoudefeng
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved