c++學習 之 override和final

C++11之前,一直沒有繼承控制關鍵字。禁用一個類的進一步衍生是可能的但也很棘手。爲避免用戶在派生類中重載一個虛函數,你不得不向後考慮。

C++ 11添加了兩個繼承控制關鍵字:override和final。override確保在派生類中聲明的重載函數跟基類的虛函數有相同的簽名。final阻止類的進一步派生和虛函數的進一步重載。

虛函數重載

一個派生類可以重載在基類中聲明的成員函數,這是面向對象設計的基礎。然而像重載一個函數這麼簡單的操作也會出錯。關於重載虛函數的兩個常見錯誤如下: 
無意中重載 
簽名不匹配

首先,我們來分析一下無意中重載的綜合症。你可能只是通過聲明瞭一個與基類的某個虛成員函數具有相同的名字和簽名的成員函數而無意中重載了這個虛函數。編譯器和讀代碼的人很難發現這個bug因爲他們通常以爲這個新函數是爲了實現對基類函數的重載:

class A
{
 public:
    virtual void func();
};            
class B: A{};
class F{};
class D: A, F
{
 public:
  void func();//meant to declare a new function but

 //accidentally overrides A::func};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

閱讀以上代碼,你不能確定成員函數D::func()是否故意重載了A::func().它也可能是個偶然發生的重載,因爲兩個函數的參數列表和名字都碰巧一樣。

簽名不匹配是一個更爲常見的情景。這導致意外創建一個新的虛函數(而不是重載一個已存在的虛函數),正如以下例子所示:

class  G
{
public:
 virtual void func(int);
};

class H: G
{
public:
 virtual void func(double); 
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

這種情況下,程序員本打算在類H中重載G::func()的。然而,由於H::func()擁有不同的簽名,結果創建了一個新的虛函數,而非對基類函數的重載:

H *p=new H;
p->func(5); //calls G::f
p->func(5.0); // calls H::f
  • 1
  • 2
  • 3

碰到這種情況,不是所有的編譯器都會給個警告,有時那樣做會被設置成抑制這種警告。

基於上面的兩個錯誤

在C++11中,通過使用新關鍵字override可以消除這兩個bugs。override明確地表示一個函數是對基類中一個虛函數的重載。更重要的是,它會檢查基類虛函數和派生類中重載函數的簽名不匹配問題。如果簽名不匹配,編譯器會發出錯誤信息。

我們來看看override如何消除簽名不匹配bug的:

class G
{
public:
 virtual void func(int);
};
class H: G
{
public:
 virtual void func(double) override; //compilation error
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

當處理到H::func()聲明時,編譯器會 在一個基類查找與之匹配的虛函數。

final函數和類

C++11的關鍵字final有兩個用途。第一,它阻止了從類繼承;第二,阻止一個虛函數的重載。我們先來看看final類吧。

程序員常常在沒有意識到風險的情況下堅持從std::vector派生。在C++11中,無子類類型將被聲明爲如下所示:

class TaskManager {/*..*/} final; 
class PrioritizedTaskManager: public TaskManager {
};  //compilation error: base class TaskManager is final
  • 1
  • 2
  • 3

同樣,你可以通過聲明它爲final來禁止一個虛函數被進一步重載。如果一個派生類試圖重載一個final函數,編譯器就會報錯:

class A
{
pulic:
  virtual void func() const;
};
class  B: A
{
pulic:
  void func() const override final; //OK
};
class C: B
{
pulic:
 void func()const; //error, B::func is final
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

C::func()是否聲明爲override沒關係,一旦一個虛函數被聲明爲final,派生類不能再重載它。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章