C++11强类型枚举,override/final
C++11(一)開篇
這個系列主要介紹C++11的一些新的特性,C++11問世至今已經有將近十年了。但是許多公司仍然停留在C++98上。之前在部門分享過C++11的知識,在這里分享給有需要的人。
C++是一門偉大的語言,永遠給程序員最大的設計自由, 未使用的特性從不產生副作用,新版本永遠完全兼容舊版本。C++11先前被稱作C++0x,即ISO/IEC 14882:2011,是C++編程語言的一個標準。
之前的C++標準包括C++98、C++03。雖然此后的[C++14]才是C++的現行標準,但C++14旨在對C++11的小擴展(漏洞修復、功能改進),而C++11仍然是一個具有熱度的關鍵詞。
?
C++11的特性主要包括下面幾個方面:
-
提高運行效率的語言特性:右值引用、泛化常量表達式
-
原有語法的使用性增強:初始化列表、統一的初始化語法、類型推導、范圍for循環、Lambda表達式、final和override、構造函數委托
-
語言能力的提升:空指針nullptr、default和delete、長整數、靜態assert
-
C++標準庫的更新:智能指針、正則表達式、哈希表等
就像C++之父說的, C++11簡直就是一個新的語言,C++11深深的影響了編程的模式。學好C++11已成為C++人必備的技能。
?
C++11(二)面向對象之enum 強類型枚舉
總得來說,C++11標準是一群天才們制定的,每一個標準的制定都有其應用改進的場景。
Enum也不例外,這個C++11系列都會有小例子或者分析它解決了什么痛點。
what is enum?in C++98/C++11
我們在編程時有時想讓一個變量的值只在規定范圍里取值,那么就會考慮使用enum類型。C++11之前的enum類型是繼承C的:
enum?color?{RED,?GREEN,?BLUE,?BLACK};然后我們再用enum color來定義變量,并賦值,
enum color myColor = GREEN;默認情況下,枚舉值從0開始,依次加1。其好處就是在不指定專門值的情況下,枚舉值基本不存在重復值,便于代碼的維護。若某些值超過枚舉類型所能容納的范圍,編譯會產生warning警告,需注意。
how to use enum
語法:
enum class type4:type{a, b, c};//加class,具名,指定底層類型type
enum?class?type5{a,?b,?c};//不指定底層類型??
進入C++11后,使用enum有三點要注意。
-
enum要根據作用域區分,枚舉分為限定作用域(C++11引入)和不限定作用域兩種,定義如下:
enum MONTH ? ? // ?不限定作用域
{
? ? ? ? JANUARY, ?FEBRUARY, ?MARCH, ?APRIL, ?MAY, ?JUNE,
? ? ? ? JULY, ?AUGUST, ?SEPTEMBER, ?OCTOBER, ?NOVEMBER, ?DECEMBER
};?
- enum的大小
進入C++11以后我們可以制定enum的大小,進而優化內存。例如可以在enum的名字后面指定我們想該enum使用的類型,
enum class DAY : uint8_t // 限定作用域{ MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY = 255, SUNDAY // 枚舉值為256,但由于超過類型所能容納的大小,值為0};-
enum 不可隱式轉換
why using C++11 enum
《Effective Modern C++》中,Scott Meyers建議優先使用限定作用域的枚舉類型。原因主要有以下幾個方面:
a.?限定作用域的枚舉類型將名字空間污染降低,如下:
auto day = SUNDAY; // SUNDAY被限定在DAY作用域內auto day = DAY::SUNDAY; // OKauto month = JANUARY; // OK 非強類型作用域?enum?type1{a,?b,?c};???enum?type2{a,?d,?e};??問題來了,兩種枚舉類型都有a枚舉常量,而且作用域相同,發生了沖突。強類型作用域就不會有這個問題
b. 限定作用域的枚舉類型是強型別的,限定作用域的枚舉類型無法通過隱式轉換到其他類型,而不限定的枚舉類型可以自動轉換為整形。
int num = DAY::SUNDAY; // 限定作用域的枚舉類型不會進行隱式轉換int num = MONTH::JANUARY; // OK當然,可以使用強制類型轉換static_cast實現限定作用域的枚舉類型轉換。
if(t<type1::b);???????????????????//同一個enum類型比較,可以??if(t>type2::b);???????????????????//非同一個enum類型,不能隱式轉換為int等值,不嗯呢該比較??if((int)t?>?(int)type2::b)????????//強制類型轉換,可以通過?c.?可以指定底層類型
C語言下面,enum大小是一個整型大小,但是C下整型有很多種,char、long int和short int等,具體哪一種呢?下面引用《C in a nutshell》里的一句話來解釋下,
The?compiler?may?select?the?appropriate?integer?type?depending?on?the?defined?values?of the?enumeration?constants.
意思就是enum類型的大小是由編譯器根據定義值的大小來選擇合適的整數類型,所以enum類型的大小并不是固定的。
舉個例子:
#include?<stdio.h> enum?color1{RED = 0,GREEN,BLUE }; enum?color2{GRAY = 0x1122334455,YELLOW,PURPLE }; int?main(void){printf("enum color1: %d\n", sizeof(enum color1));printf("enum color2: %d\n", sizeof(enum color2));return 0; }輸出如下,
enum color1: 4enum?color2:?8 因為enum color2的大小已經超過了4個字節,這樣編譯器就會把它的大小擴大。這樣會有一個潛在的弊端:如果我們定義了一個結構體,其成員有enum類型,那么就可能導致結構體大小發生變化,而我們卻沒有察覺,例如隨著代碼的更迭,我們加入了更多enum規定的范圍值,當超過某個值時,它的大小就產生了變化,這是比較危險的。
而且如果enum規定的范圍值超過了指定大小,編譯會報錯,如這種,
enum color1 : uint8_t {RED = 266,GREEN,BLUE }; int main() {printf("enum color1: %d\n", sizeof(enum color1));return 0; } 出錯信息如下:?
C++11(四)override/final
override
描述:override是C++11中的一個繼承控制關鍵字。override確保在派生類中聲明的重載函數跟基類的虛函數有相同的聲明。
override明確地表示一個函數是對基類中一個虛函數的重載。更重要的是,它會檢查基類虛函數和派生類中重載函數的簽名不匹配問題。如果簽名不匹配,編譯器會發出錯誤信息。?
override表示函數應當重寫基類中的虛函數(用于派生類的虛函數中) 。
目的:
-
在函數比較多的情況下可以提示讀者某個函數重寫了基類虛函數(表示這個虛函數是從基類繼承,不是派生類自己定義的);
-
強制編譯器檢查某個函數是否重寫基類虛函數,如果沒有則報錯。
用法:在類的成員函數參數列表后面添加該關鍵字既可。
下面舉個小例子:
struct A {virtual void foo();void bar(); }; struct B : A {void foo() const override; // Error: B::foo does not override A::foo// (signature mismatch)void foo() override; // OK: B::foo overrides A::foovoid bar() override; // Error: A::bar is not virtual };根據注釋,我們可以很清晰的理解這個關鍵字的意思。有些人可能認為這個關鍵字沒啥用。自己寫程序的時候注意一下就好了,不必要用這個關鍵字。一開始我也是這么以為的,知道有一天我跌進了這個坑里。
故事是這樣的。之前寫過一個程序,大概是這樣的:
struct A {virtual void foo();void?fooo(); }; struct B : A {void?foo(){...}//這個是之前別人寫的void?fooo(){...}//這個是我后加的 }; 當然當時的程序很復雜,我想調用foo然后從B中重寫的foo。但是foo和fooo長的特別像我其實實現了fooo,結果調用foo,發現寫的程序一直不生效。調試半天也無果。。。。后來發現是寫錯了,如果當時寫上這個關鍵字,編譯就會立馬報錯,不會花費大量時間debug。。。final
final阻止類的進一步派生和虛函數的進一步重寫。這個很簡單,舉個小例子就明白了:
struct Base{virtual void foo(); }; struct A : Base{void foo() final; // A::foo is overridden and it is the final overridevoid bar() final; // Error: non-virtual function cannot be overridden or be final }; struct B final : A // struct B is final {void foo() override; // Error: foo cannot be overridden as it's final in A }; struct C : B // Error: B is final { };我建議在寫程序的時候盡量在合適的地方用這兩個關鍵字,這樣就能在程序編譯的時候就發現隱藏的錯誤。
總結
以上是生活随笔為你收集整理的C++11强类型枚举,override/final的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux中磁盘还有空间,但创建文件时提
- 下一篇: C++11构造与禁用默认函数