C++程式設計基礎(2)變數

ysyouaremyall發表於2018-06-11

注:讀《程式設計師面試筆記》筆記總結

1.知識點

(1)C++變數命名只能包含字母、數字、下劃線,其中開頭不能是數字;大小寫敏感;習慣上變數用小寫字母,常量、巨集定義用大寫字母。

(2)變數的作用域分為區域性變數(函式內部定義),全域性變數(函式外部定義)。

(3)關鍵字extern:在標頭檔案總宣告變數,並在前面加上extern,在原始檔中定義變數,其他檔案使用#include匯入標頭檔案,即可使用該變數。附詳細連結https://blog.csdn.net/chenqiai0/article/details/8490665

 1 //test.h
 2 extern int age;
 3 //test.cpp
 4 #include"test.h"
 5 int age = 10;  //直接使用age=10是不行的
 6 //test1.cpp
 7 #include"test.h"
 8 int main(int argc, char *argv[]) {
 9     cout << age << endl;
10     getchar();
11     return 0;
12 }
13 
14 /*output
15 10
16 */

(4)關鍵字static:靜態變數,首次執行時初始化,其後再執行將不再進行初始化,雖然可能是區域性變數,但其生命週期是整個程式執行過程。

(5)關鍵字const:常量型變數,在標頭檔案中直接定義和宣告(不同於一般全域性變數),其他檔案通過#include使用(多個檔案引用不會造成重複定義),如果在原始檔中定義,則其作用域值是本原始檔。

2.面試題

2.1簡述i++和++i的區別

寫出下面程式碼執行後i,j,m,n的值

1 int i=10,j=10;
2 int m=(i++)+(i++)+(i++);
3 int n=(++j)+(++j)+(++j);

知識點:++i是先自身加一,然後再參與賦值運算,i++是先參與賦值運算,然後再自身加一。

本題的特殊之處是不同的編譯器會產生不同的結果,在VC編譯器中,全部會先完成三個++j,然後再做加法運算,而在gcc編譯器中當有兩個運算元時就會進行加法運算。故結果如下:

1 #VC編譯器
2 i=13,j=13,m=30,n=39//13+13+13=39
3 #gcc編譯器
4 i=13,j=13,m30,n=37;    //12+12+13=37

2.2簡述C++的型別轉換操作符

在C語言中型別轉換隻需要通過變數前面加上變數型別,並且轉換是雙向的,這種方式對於簡單型別可以,複雜資料型別就力不從心了。

C++提供了四種型別轉換操作符:static_cast,dynamic_cast,const_cast,reinterpret_cast。

(1)static_cast可以完全替代C風格型別轉換實現基本型別轉換;

1 int i = 1;
2 double d = 1.5;
3 int d2i = static_cast<int>(d);
4 double i2d = static_cast<double>(i);

同時相關類(如父子關係)可以完成轉換,但是如果父類指標本身指向父類物件,不存在安全問題,如果父類指標本身指向子類物件,則不存在安全問題;

1 class Base {};
2 class Derived:public Base{};
3 Base *b1 = new Base;    //父類指標指向父類物件
4 Base *b2 = new Derived;     //父類指標指向子類物件
5 Derived *b2d1 = static_cast<Derived *>(b1);    //轉換成功(不安全)
6 Derived *b2d2 = static_cast<Derived *>(b2); //轉換成功(安全)

(2)dynamic_cast:只能進行物件指標之間的轉;轉換結果可以使指標也可以是引用;轉換時會進行型別檢查(static_cast不會進行檢查);只有當父類指標指向一個子類物件,並且父類中包含了虛擬函式,轉換才會成功,否則返回空指標,引用的話丟擲異常。

 1 class Base { virtual void dummy() {}; };
 2 class Drived : public Base{};
 3 Base *b1 = new Base;
 4 Base *b2 = new Drived;//父類指標指向子類物件,且父類中包含虛擬函式
 5 //轉換結果為指標
 6 Drived *b2d1 = dynamic_cast<Drived*>(b1);//轉換失敗(返回NULL)
 7 Drived *b2d2 = dynamic_cast<Drived*>(b2);//轉換成功
 8 //轉換結果為引用
 9 Drived &b2d3 = dynamic_cast<Drived &>(*b1);//轉換失敗(丟擲異常)
10 Drived &b2d4 = dynamic_cast<Drived &>(*b2);//轉換成功

(3)const_cast:可以在轉換過程中增加或刪除const屬性。一般情況下,無法將常量指標直接賦值給普通指標,但通過const_cast可以移除常量指標的const屬性,從而實現const指標到非const指標的轉換。

1 class Test{};
2 const Test *t1 = new Test;
3 Test *t2 = const_cast<Test *>(t1);

(4)reinterpret_cast:可以將一種型別的指標直接轉換成另一種型別的指標,無論兩個型別之間是否有繼承關係。此外還可以吧一個指標轉換為一個整數,也可以把一個整數轉換成一個指標。另外還經常用在不同函式指標之間的轉換。

1 class A{};
2 class B{};
3 A *a = new A;
4 B *b = reinterpret_cast<B *>(a);    //轉換成功

2.3簡述靜態全域性變數的概念

(1)在全域性變數前面加上static關鍵字就成為的靜態全域性變數。

(2)靜態全域性變數通常在原始檔中宣告定義,作用域為本檔案,(而全域性變數一般標頭檔案宣告,原始檔定義,通過extern關鍵字,其作用域為整個工程。)

(3)如果在標頭檔案中宣告瞭靜態全域性變數,那麼即使在沒有初始化的情況下,也會被初始化為預設值,即相當於也被定義了,這時其他檔案#include該標頭檔案,相當於拷貝了一份,其初始值相同,後面各個檔案中將互相不影響。

下面是靜態全域性變數的一個例子:

 1 static int sgn;//宣告定義靜態全域性變數
 2 void increaseSG() { sgn++; }
 3 int main(){
 4     sgn = 10;
 5     cout << sgn << endl;
 6     increaseSG();
 7     cout << sgn << endl;
 8         getchar();
 9         return 0;
10 }


相關文章