1、標識符命名規則!
標識符不能包含兩個連續的下劃線,也不能以下劃線開頭后面緊跟一個大寫字母。有些標識符(在函數外定義的標識符)不能以下劃線開頭。
但是在G++編譯器和VC編譯器下,二者均可正確編譯!


2、跨平臺編譯程序!
這里不是要講解如何跨平臺編譯程序,也不是告訴你如何更好地編寫通用平臺的程序規則,那可能涉及到很多的宏定義以及硬件相關特性。這里僅為使用示例代碼提供一種精簡的方式。
用Eclipse+MinGW的方式默認會很精簡,所以把它當作一種目標!
用Visual Studio 2008創建的程序會讓你引入預編譯頭stdafx.h(這通常發生在使用Visual Studio創建Win32控制臺應用程序,并直接點擊“完成”后),這將導致你無法將在Eclipse上編寫的程序直接運行在Visual Studio上。這時你應該通過修改項目屬性來獲得這種精簡的方式:(選擇項目,右鍵屬性,選擇配置屬性->C/C++->預編譯頭->創建/使用預編譯頭,選擇“不使用預編譯頭”->“確定”后再次編譯即可!)
3、變量命名習題
//測試變量命名!
//error C2632: “int”后面的“double”非法
//int double = 3.14159;
//-------------------------------------------------
char _='a';
std::cout<<_<<std::endl;
//-------------------------------------------------
//warning C4091: “”: 沒有聲明變量時忽略“bool”的左側
//error C2059: 語法錯誤: “-”
//bool catch-22;
//-------------------------------------------------
//error C2059: 語法錯誤: “數字上的錯誤后綴”
//char 1_or_2 = '1';
//-------------------------------------------------
float Float=3.14f;
std::cout<<Float<<std::endl;
4、在C++中,“初始化不是賦值”
初始化指創建變量并給它賦初始值,而賦值則是擦除對象的當前值并用新值代替。
int ival(1024); //直接初始化
int ival = 1024; //復制初始化
直接初始化語法更靈活,效率更高!
對內置類型來說,復制初始化和直接初始化幾乎沒有差別。
對類類型來說,有些初始化僅能用直接初始化完成。要想理解其中緣由,需要初步了解類是如何控制初始化的。
例如:
也可以通過一個計數器和一個字符初始化string對象。這樣創建的對象包含重復多次的指定字符,重復次數由計數器指定:
std::string all_nines(10, ‘9’); //all_nines = “9999999999”;
本例中,初始化all_nines的唯一方法是直接初始化。有多個初始化式時不能使用復制初始化。(V注:這里的初始化式即為構造函數的多個重載;這里所謂的“不能使用”應該是“功能有所不及”的意思!)
5、變量初始化規則
使用未初始化的變量經常導致錯誤,而且十分隱蔽。問題出在未初始化的變量事實上都有一個值。編譯器把該變量放到內存中的某個位置,而把這個位置的無論哪種位模式都當成是變量初始的狀態。當被解釋成整型值時,任何位模式都是合法的值——雖然這個值不可能是程序員想要的。因為這個值合法,所以使用它也不可能導致程序崩潰。可能的結果是導致程序錯誤執行和/或錯誤計算。
//在Eclipse中運行沒有出現錯誤!
//在Visual Studio中運行出現運行時錯誤!
int ival; //沒有初始化!
std::cout<<ival<<std::endl;
6、聲明和定義
為了能讓多個文件訪問相同的變量,C++區分了聲明和定義。簡單地說就是可以用extern關鍵字來聲明,任何有分配內存行為的聲明都是定義。定義也是聲明。聲明:標明變量的類型和名字;定義:為變量分配存儲空間,還可以為變量指定初始值。
舉例說明:
extern double pi; //聲明
double pi; //定義,聲明了pi同時定義了pi
extern double pi = 3.14159; //定義,因為它為pi分配了初值。只有當該extern語句
位于函數外部的時候才允許使用初始化式,否則將導致編譯錯誤。
7、變量的隱藏:
std::string s1 = "I am a std::string!";
std::cout<<s1<<std::endl;
for(int s1=3; s1!=0; --s1)
std::cout<<"I am a number(int):"<<s1<<std::endl;
提示:在Visual Studio 2008中使用std::string定義一個變量,再通過std::cout將其輸出,將會得到“error C2679: 二進制“<<”: 沒有找到接受“std::string”類型的右操作數的運算符(或沒有可接受的轉換)”錯誤信息,這時要檢查頭文件中是否包含#include <string>。而在Eclipse中則不用如此設置(具體看編譯器版本)。這與標準庫實現的具體細節有關,在MSVC中,它在文件Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\string中被實現,在GNU中,它在base_string.h中被實現。在使用std::string時,總是包含#include <string>是一個好習慣!
8、const對象默認為文件的局部變量
一般聲明變量后可以在其它文件中通過extern關鍵字聲明并使用該變量:
//文件1:
int counter;
//文件2:
extern int counter;
++counter;
但是如果是const則無法訪問。可以通過顯式指定extern關鍵字使其成為全局可訪問對象:
//文件1:
extern const int bufSize = getBufSize();
//文件2:
extern count int bufSize;
//……使用bufSize
注解:非const變量默認為extern。要使const變量能夠在其他的文件中訪問,必須顯式地指定它為extern。
9、引用
int ival = 1024;
int &refVal = ival;
當引用初始化后,只要該引用存在,就保持綁定到初始化時指向的對象。不可能將引用綁定到另一個對象。
也正因為如此,所以引用比指針的優勢就在于:引用不可以在方法中篡改,這使得方法變量變得安全了。
10、const引用
const int ival = 1024;
const int &refVal = ival;
這里我們要求左側的類型是一致的,包括const!
非const引用只能綁定到與該引用同類型的對象。
const引用則可以綁定到不同但相關的類型的對象或綁定到右值。(具體示例詳見C++Primer v4 P52)
例如:
//錯誤代碼
double dval = 3.14;
const int &ri = dval;
編譯器會將這些代碼轉換成如以下形式的編碼:
int temp = dval;
const int &ri = temp;
如果ri不是const,那么可以給ri賦一新值。這樣做不會修改dval,而是修改了temp。期望對ri的賦值會修改dval的程序員會發現dval并沒有被修改。僅允許const引用綁定到需要臨時使用的值完全避免了這個問題,因為const引用是只讀的。
但是如下代碼可以執行:
int ival = 1024;
const int &refVal = ival;
++ival;
//++refVal; //error C3892: “refVal” 不能給常量賦值
std::cout<<"ival="<<ival<<"\trefVal="<<refVal<<std::endl;
輸出:ival=1025 refVal=1025
const double dval = 3.14;
const int &ri = (int)dval;
std::cout<<ri<<std::endl;
輸出:3