Effective C++ ——让自己习惯C++
生活随笔
收集整理的這篇文章主要介紹了
Effective C++ ——让自己习惯C++
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
條款一:視C++為一個語言聯邦
? ? ? ?為了理解C++,你必須認識其主要的次語言。幸運的是總共只有四個:
- ?C:C++是由C語言繼承而來的,必然對C有很好的兼容性,這一部分主要包括C中的一些語言,庫函數等。但當你以C++內的C成分工作時,高效編程守則照出C語言的局限:沒有模板、沒有異常、沒有重載。。。
- ?Object-Oriented C++:這部分也就是C with Class所訴說的:classes(包括構造函數和析構函數)、封裝、繼承、多態、virtual函數(動態綁定)。。。。等等。
- ?Template C++:這一部分主要是泛型編程。
- ?STL:標準模板庫,主要是以template C++為基礎實現的,里面提供了很多有用的類和對應的算法,幫助我們很好的結果了C語言中要自己去解決的問題,主要有容器(數組就是一個特殊的容器)、迭代器(智能指針,之所以用迭代器是為了通用性)、算法(包括容器特殊的算法和容器間通用的算法)、函數對象(能想函數一樣被調用的對象,通過重定義對象中的()操作符來完成的)、適配器(可以理解為修改了容器接口實現的一種容器),這一部分是c++強大的后盾,學習C++。不能不學STL,不僅會用最好能知道STL中成員的實現方式,這樣就能更加高效的使用!
條款二:盡量以const,enum,inline替換#define
? ? ? ?可以理解為能在編譯器期間做的事情不要放到預編譯器中處理,預編譯器是對程序編譯之前的一個預先的處理,不會檢查對代碼最任何的檢出,這樣如果在編譯期間發現問題,如果問題是我們自己直接造成的那可能會很快的定位,想反的如果問題在預編譯期間做了一些處理,那樣在編譯中出現的問題可能會顯示預編譯中的問問題,這樣對問題定位不方便,例如:在程序中定義宏#define PI 3.1415,如果編譯過程中出現錯誤,錯誤顯示中會直接顯示3,1415,而不會對PI符號有所說明,如果宏是自己定義的還好,如果是引用的其他頭文件中的定義,那真的不是很好查的!對于條款二,主要有以下兩點說明:
1.盡量以const、enum定義來替換#define 定義。
? ? ? ?在頭文件中以#define定義的常量在預編譯期間直接對對應的符號進行替換,沒有內存的申請,這也是#define可以放到頭文件中的原因,對于const常量定義中,它將常量直接放入到符號表中,不會申請固定的內存,除非對該常量有內存的引用,這也就是為什么const定義的常量能像#define一樣放到頭文件中,在const常量的使用中主要常量重疊的出現,相關知識自行查閱!
? ? ? ?為了將常量的作用域限制于class內,你必須讓它成為class的一個成員;而為確保此常量至多只有一份實體,你必須讓它成為一個static成員:
class GamePlayer{ private:static const int NumTurns = 5;//常量聲明式int score[NumTurns];//使用該常量..... }? ? ? ?上面中NumTurns是常量的聲明而不是定義式,在后面的使用中如果只是使用該常量并沒有用到該常量的地址,就可以不用再對該常量做定義,否組需要如下的定義:const int GamePlayer::NumTurns;? ? ? ?請把這個式子放進一個實現文件而非頭文件。由于class常量已在聲明時獲得初值,因此定義時不可以再設初值。
? ? ? ?對應的在有些編譯器中是不支持在聲明常量的時候直接賦值的,例如:class GamePlay{ private:static const int NumTurns;//static class常量聲明位于頭文件內....... }后面接著定義:
const int GamePlay::NumTurns=5;//static class常量定義位于實現文件內
enum
1 ?比較像#define而不像const。取一個enum的地址不合法,所以可以防止pointer或reference指向你的某個整數常量。
2 ?模板元編程的基礎技術
?Template Inline代替宏
#define CALL_WITH_MAX(a,b) f((a) > (b)) ? (a) :(b)) int a = 5,b = 0 CALL_WITH_MAX(++a,b); //a被累加兩次 CALL_WITH_MAX(++a,b+10);//a被累加一次? ?對應的替代方案就是采用inline函數來替換:
template<typename T> inline void callWithMax(cosnt T &a, cosnt T &b) {f(a > b ? a : b); }? ? ? ?其中用到了template模板函數,之所以用引用時為了自定義的類型,如果只是內置類型,可以不需要引用!- 對于單純常量,最好以const對象或enums替換#defines;
- 對于形似函數的宏,最好改用inline函數替換#defines。
條款三:盡量的使用const
1.const對于基本內置類型的約束,主要指的是指針類型。
const int * pi; int * const pi;
在STL中,迭代器也是一種指針,const可以對迭代器進行修飾,對應的也有兩種修飾的方式:
const std::vector<int>::iterator iter; std::vector<int>::const_iterator iter;
? ? ? ?此外在函數的應用中,也常用到const關鍵字,主要是兩點,一是對于函數的形式參數的修飾上,如果參數在函數內部不被修改那么一般情況下都要用const將參數修飾下,這樣當函數接口暴露出去的時候,別人能很容的看清楚,還有一種比較少見的用法就是對函數返回值得修飾上,這個主要是防止最函數返回值進行賦值操作,例如下面:class Ration{}; const Ration operator*(const Ration& lhs,const Ration* rhs);
2.const成員函數
class Ration{ private:int n_; public:int getn(){return n;}int getn() const{return m;}void setn(int i) const{n = i;} };? ? ? ?在C++中有函數重載的概念,對同名的函數,如果函數的參數類型或者個數不相同,就可以作為不同的函數,這個主要是通過在編譯源代碼過程中對不同的函數重新命名來實現,對于const修飾的函數,不能對對象的任何成員進行修改,并且const修飾的對象只能調用對象的const成員函數,其中const對象主要是作為函數的參數進行傳遞的!
class Ration{ private:int n_; public:int getn(){return n;}int getn() const{return m;}void setn(int i) const{n = i;} };? ? ? ?定義一個const Ration test,則test調用getn()函數的時候只能調用const的get函數,不能調用普通的成員函數,如果沒有const的成員函數,將報錯,對應的例子中的setn函數定義為const函數,但是它卻對成員n進行了賦值,因此是不允許的,編譯也不會通過,如果想讓setn()函數編譯通過,我們可以借助關鍵詞mutable,將n定義為mutable int n,這樣即使在const函數中也可以對n進行修改!咱們一般的應用中很少直接定義一個const的對象,一般const的對象是用在函數的形式參數中出現的!
? ? ? ?當const成員函數與非const成員函數功能相同的時候,我們一般不會定義兩個成員函數,其中一個只是比另一個多了一個const的修飾,我們的解決辦法是讓非const的成員函數調用const的成員函數,其中const的成員函數正常定義,此時可能用到C++中的強制類型轉換例如static_cast/const_cast等!
條款四:確定對象在使用前已經初始化
? ? ? ?對于內置類型以外的任何其他東西,初始化責任落在構造函數(constructors)身上。確保每一個構造函數都將對象的每一個成員初始化。
? ? ? ?C++規定,對象的成員變量的初始化動作發生在進入構造函數本體之前。
? ? ? ?初始化列表免于先調用 default構造函數然后再調用賦值操作符,只需調用一次拷貝構造函數。更高效。
? ? ? ?構造函數的最佳寫法是,使用 member initialization list(成員初始化表)如:
ABEntry::ABEntry(char&name,char& address,list &phones):theName(name),theAddress(address),thePhones(phones) { ……. }
編譯器會為用戶自定義類型(user-definedtypes)之成員變量自動調用default構造函數--- 如果那些成員變量在“成員初始化列表”中沒有被指定初值的話。
成員變量是 const 或references,它們就一定需要初值,不能被賦值。
C++有著十分固定的“成員初始化次序”。Base classes 更早于其derived classes 被初始化,而class的成員變量總是以其聲明次序被初始化。
Static 對象,其有效時間從被構造出來直到程序結束為止,因此stack和heap-based對象被排除。
注意:
為內置對象進行手工初始化,因為C++不保證初始化它們;
構造函數最好使用成員初始化列表,而不要在構造函數本體內使用賦值操作。初始化列表列出的成員變量,其排列次序應該和它們在類中的聲明次序相同;
為免除“跨編譯單元之初始化次序”問題,請以local static對象替換non-local static對象。
轉載于:https://www.cnblogs.com/wangfengju/p/6172478.html
總結
以上是生活随笔為你收集整理的Effective C++ ——让自己习惯C++的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 封面人物丨“有味道”的学校什么样?她用2
- 下一篇: 中考分流毁掉孩子?这位家长的血泪教训,揭