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};
~~~
閱讀以上代碼,你不能確定成員函數D::func()是否故意重載了`A::func()`.它也可能是個偶然發生的重載,因為兩個函數的參數列表和名字都碰巧一樣。
簽名不匹配是一個更為常見的情景。這導致意外創建一個新的虛函數(而不是重載一個已存在的虛函數),正如以下例子所示:
~~~
class G
{
public:
virtual void func(int);
};
class H: G
{
public:
virtual void func(double);
};
~~~
這種情況下,程序員本打算在類H中重載`G::func()`的。然而,由于`H::func()`擁有不同的簽名,結果創建了一個新的虛函數,而非對基類函數的重載:
~~~
H *p=new H;
p->func(5); //calls G::f
p->func(5.0); // calls H::f
~~~
碰到這種情況,不是所有的編譯器都會給個警告,有時那樣做會被設置成抑制這種警告。
基于上面的兩個錯誤
在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
};
~~~
當處理到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
~~~
同樣,你可以通過聲明它為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
};
~~~
`C::func()`是否聲明為override沒關系,一旦一個虛函數被聲明為final,派生類不能再重載它。
- 前言
- 吐血整理C++11新特性
- C++11新特性之std::function
- c++11特性之正則表達式
- c++11特性之Lambda表達式
- c++11特性之override和final關鍵字
- c++11特性之std::thread--初識
- c++11特性之std::thread--初識二
- c++11特性之initializer_list
- c++11特性之std::thread--進階
- c++11特性之std::thread--進階二
- C++11新特性之 CALLBACKS
- C++11新特性之 std::array container
- C++11新特性之 nullptr
- C++11新特性之 rvalue Reference(右值引用)
- C++11新特性之 Move semantics(移動語義)
- C++11新特性之 default and delete specifiers
- C++11新特性之 Static assertions 和constructor delegation
- 開始使用C++11的幾個理由
- C++11新特性之 std::future and std::async