你最需要注意的11條要點for C++ (轉)
這裡的要點不僅僅是解釋怎樣寫出更好的程式碼,更多的是展現出語言規則裡面的東西。很顯然,它們對C++程式設計師來說是永久的好資料。我相信這一篇文章會使你收穫不小。
首先,我把一些由不同層次的C++程式設計師經常問的問題歸到一起。我驚奇的發現有很多是有的程式設計師都還沒意識到 .h 符號是否還應該出現在標準頭中。
要點1:
很多C++程式設計師還在使用
因為這些實質上的不同,你不能在一個程式中混淆使用這兩個庫。做為一種習慣,在新的程式碼中一般使用
要點2:用引用傳遞引數時應注意的地方
在用引用傳遞引數時,最好把引用宣告為const型別。這樣做的好處是:告訴程式不能修改這個引數。在下面的這個例子中f()就是傳遞的引用:
void f(const int & i);
int main()
{
f(2); /* OK */
}
這個程式傳遞一個引數2給f()。在執行時,C++建立一個值為2的int型別的臨時變數,並傳遞它的引用給f().這個臨時變數和它的引用從f()被開始被建立並存在直到函式返回。返回時,就被馬上刪除。注意,如果我們不在引用前加上const限定詞,則函式f()可能會更改它引數的值,更可能會使程式產生意想不到的行為。所以,別忘了const。
這個要點也適用於定義的。你可以給臨時物件也加上引用如果是const型別:
struct A{};
void f(const A& a);
int main()
{
f(A()); // OK,傳遞的是一個臨時A的const引用
}
要點3:“逗號分離”表達形式
“逗號分離”表達形式是從C繼承來的,使用在for-和while-迴圈中。當然,這條語法規則被認為是不直觀的。首先,我們來看看什麼是“逗號分離”表達形式。
一個由一個或多個其它表示式構成,由逗號分開,如:
if(++x, --y, cin.good()) //三個表示式 這個if條件包含了三個由逗號分離的表示式。C++會計算每個表示式,但完整的“逗號分離”表示式的結果是最右邊表示式的值。因此,僅當cin.good()返回true時,if條件的值才是true。下面是另一個例子: int j=10;
int i=0;
while( ++i, --j)
{
//直到j=0時,迴圈結束,在迴圈時,i不斷自加
}
要點4,使用全域性物件的建構函式在程式啟動前呼叫函式
有一些應用程式需要在主程式啟動前呼叫其它函式。如:轉態過程函式、登記功能函式都是必須在實際程式執行前被呼叫的。最簡單的辦法是透過一個全域性物件的建構函式來呼叫這些函式。因為全域性物件都是在主程式開始前被構造,這些函式都將會在main()之前返回結果。如:
class Logger
{
public:
Logger()
{
activate_log();//譯者注:在建構函式中呼叫你需要先執行的函式
}
};
Logger log; //一個全域性例項
int main()
{
record * prec=read_log();//譯者注:讀取log檔案資料
//.. 程式程式碼
}
全域性物件log在main()執行之前被構造,log呼叫了函式activate_log()。從而,當main()開始執行時,它就可以從log檔案中讀取資料。
毫無疑問地,在C++中管理是最複雜和最容易出現的地方。直接訪問原始記憶體、動態分配和最大限度的發揮C++指令,都使你必須盡力避免有關記憶體的bug。
要點5:避免使用複雜構造的指向函式的指標
指向函式的指標是C++中可讀性最差的語法之一。你能告訴我下面語句的意思嗎?
要點6:指向成員的指標
一個類有兩種基本的成員:函式成員和資料成員。同樣的,指向成員的指標也有兩種:指向函式成員的指標和指向資料成員的指標。後則其實並不常用,因為類一般是不含有公共資料成員的,僅當用在繼承用C寫的程式碼時協調結構(struct)和類(class)時才會用到。
指向成員的指標是C++語法中最難以理解的構造之一,但是這也是一個C++最強大的特性。它可以讓你呼叫一個類的函式成員而不必知道這個函式的名字。這一個非常的呼叫工具。同樣的,你也可以透過使用指向資料成員的指標來檢查並改變這個資料而不必知道它的成員名字。
指向資料成員的指標
儘管剛開始時,指向成員的指標的語法會使你有一點點的迷惑,但你不久會發現它其實同普通的指標差不多,只不過是*號的前面多了::符號和類的名字,例:定義一個指向int型的指標:
{
public:
int num;
int x;
};
int A::*pmi = & A::num; 上面的程式碼是宣告一個指向類A的一個int型的num成員並將它初始化為這個num成員的地址.透過在pmi前面加上*你就可以使用和更改類A的num成員的值: A a1, a2;
int n=a1.*pmi; //把a1.num賦值給n
a1.*pmi=5; // 把5賦值給a1.num
a2.*pmi=6; // 把6賦值給6a2.num
如果你定義了一個指向類A的指標,那麼上面的操作你必須用 ->*運算子代替: A * pa=new A;
int n=pa->*pmi;
pa->*pmi=5;
指向函式成員的指標
它由函式成員所返回的資料型別構成,類名後跟上::符號、指標名和函式的引數列表。舉個例子:一個指向類A的函式成員(該函式返回int型別)的指標:
class A
{
public:
int func ();
};
int (A::*pmf) ();
上面的定義也就是說pmf是一個指向類A的函式成員func()的指標.實際上,這個指標和一個普通的指向函式的指標沒什麼不同,只是它包含了類的名字和::符號。你可以在在任何使用*pmf的地方呼叫這個函式 func():pmf=&A::func;
A a;
(a.*pmf)(); //呼叫a.func() 如果你先定義了一個指向物件的指標,那麼上面的操作要用->*代替: A *pa=&a;
(pa->*pmf)(); //呼叫pa->func()
指向函式成員的指標要考慮多型性。所以,當你透過指標呼叫一個虛擬函式成員時,這個呼叫將會被動態回收。另一個需要注意的地方,你不能取一個類的建構函式和解構函式的地址。
要點7、避免產生記憶體碎片
經常會有這樣的情況:你的應用程式每執行一次時就因為程式自身缺陷而產生記憶體而洩漏記憶體,而你又在週期性地重複著你的程式,結果可想而知,它也會使崩潰。但怎樣做才能預防呢?首先,儘量少使用動態記憶體。在大多數情況下,你可能使用靜態或自動儲存或者是STL容器。第二,儘量分配大塊的記憶體而不是一次只分配少量記憶體。舉個例子:一次分配一個陣列例項所需的記憶體,而不是一次只分配一個陣列元素的記憶體。
要點8、是delete還是delete[]
在程式設計師中有個荒誕的說法:使用delete來代替delete[]刪除陣列型別時是可以的!
舉個例子吧:
delete p; //錯誤,應該是:delete[] p
上面的程式是完全錯誤的。事實上,在一個平臺上使用delete代替delete[]的應用程式也許不會造成系統崩潰,但那純粹是運氣。你不能保證你的應用程式是不是會在另一個上編譯,在另一個平臺上執行,所以還是請使用delete[]。
要點9、成員的排列一個類的大小可以被下面的方式改變:
struct A
{
bool a;
int b;
bool c;
}; //sizeof (A) == 12
在我的上sizeof (A) 等於12。這個結果可能會讓你吃驚,因為A的成員總數是6個位元組:1+4+1個位元組。那另6位元組是哪兒來的?編譯器在每個bool成員後面都插入了3個填充位元組以保證每個成員都是按4位元組排列,以便分界。你可以減少A的大小,透過以下方式:
struct B
{
bool a;
bool c;
int b;
}; // sizeof (B) == 8
這一次,編譯器只在成員c後插入了2個位元組。因為b佔了4個位元組,所以就很自然地把它當作一個字的形式排列,而a和c的大小1+1=2,再加上2個位元組就剛好按兩個字的形式排列B。
要點10、為什麼繼承一個沒有虛解構函式的類是危險的?
一個沒有虛解構函式的類意味著不能做為一個基類。如std::string, std::complex, 和 std::vector 都是這樣的。為什麼繼承一個沒有虛解構函式的類是危險的?當你公有繼承建立一個從基類繼承的相關類時,指向新類物件中的指標和引用實際上都指向了起源的物件。因為解構函式不是虛擬函式,所以當你delete一個這樣的類時,C++就不會呼叫解構函式鏈。舉個例子說明:
class A
{
public:
~A() // 不是虛擬函式
{
// ...
}
};
class B: public A //錯; A沒有虛解構函式
{
public:
~B()
{
// ...
}
};
int main()
{
A * p = new B; //看上去是對的
delete p; //錯,B的析構函沒有被呼叫
}
要點11、以友元類宣告巢狀的類
當你以友元類宣告一個巢狀的類時,把友元宣告放在巢狀類宣告的後面,而不前面。
class A
{
private:
int i;
public:
class B //巢狀類宣告在前
{
public:
B(A & a) { a.i=0;};
};
friend class B;//友元類宣告
};
如果你把友元類宣告放在宣告巢狀類的前面,編譯器將拋棄友元類後的其它宣告。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-991827/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 自媒體運營崗位職責有哪些?這幾個要點你要注意!
- 編寫可移植C/C++程式的要點C++
- 應用 Laravel 的軟刪除你需要注意的幾點Laravel
- 企業用好WMS(倉庫管理系統),需要注意的幾個要點
- 測試要點總結(轉帖)
- BI資料分析系統運營要注意這4個要點
- Effective c++條款11:在operator=中處理“自我賦值”C++賦值
- 那些你需要注意的坑
- MySQL的clone(克隆)要注意的點MySql
- 前端學習,除了掌握學習路線之外,必須要注意的知識要點!前端
- 陪玩系統原始碼移動前端開發需要注意的20個要點原始碼前端
- 11個點讓你的Spring Boot啟動更快Spring Boot
- 《刺客信條:英靈殿》可能要讓你失望了
- 寫小說主要注意的點
- 檔案管理,你必須要知道的三個要點
- Java程式設計師微服務架構你必須要掌握的十個要點Java程式設計師微服務架構
- C++中的條件變數C++變數
- 雙11,哪一條評論讓你果斷下單?
- golang split需要注意的一個點Golang
- LeetCode BFS題目以及要注意的點LeetCode
- api介面怎麼對接?你只需要注意這4點API
- 程式設計師生存指南:你必須要掌握的兩點!程式設計師
- 入門Java你需要了解的幾個知識要點!Java
- [c++/gcc] Centos 7.9升級 gcc 4.8.5 到 gcc11 [轉]C++GCCentOS
- C++的特點C++
- JVM筆記--如果你寫JVM,最需要考慮的重要結構是什麼?JVM筆記
- 判斷條件為空時需要注意
- c++ 11 執行緒池---完全使用c++ 11新特性C++執行緒
- Material Design配色難?11條設計資源給你靈感!Material Design
- c++切面條題目C++
- Spring事務需要注意的幾個點Spring
- 演算法要幫你找到真愛有點難演算法
- 選擇香港伺服器需要注意哪些事項?這4點事項要牢記!伺服器
- 為什麼要玩《真·女神轉生3》:它是Atlus成功的原點
- 邦芒面試:11條面試提示將給你帶來成功的契機面試
- 你必須瞭解的微服務架構設計的10個要點!微服務架構
- 【12月11日】真香現場,帶你玩轉 EKS!
- 直播系統開發步驟繁瑣,你需要注意這四個點
- LeetCode Trie常見的題型以及要注意的點LeetCode