少說話。。
程序題鏈接:https://www.cnblogs.com/aoru45/p/9898691.html
14級試題---選擇題
1. 引用在聲明時必須對其初始化,以綁定某個已經存在的變量(或對象),在該引用的生命期內,該綁定不能被更改。 (√)
解析:
引用在聲明的時候,必須告訴程序引用的是誰,所以需要在聲明的時候對其初始化;而在其引用的生命周期內,引用綁定是不能被更改的,這是因為,引用的聲明的時候,相當於給被引用的對象起了個別名,如果你把這個別名叫在別人身上,那就不對了,比如,你把李白叫成小白,你再把小白這個名號安在趙四頭上,這就說不通了嘛。。
補充點知識點:
引用的類型和他綁定的對象之間的類型必須是嚴格匹配的,但是有兩種情況除外,一是初始化常量引用時,允許任意表達式作為初始值,只要該表達式的結果可以轉化成引用類型就可以了。二是可以將常量引用綁定到非const對象上。
//對第一點有如下引用方式是對的 double a = 1.3; const int &b = a; //對第二點有如下引用方式是對的 const double PI = 3.14; double cc= 999; const double &p1 = PI;//完全匹配的方式 const double &p2 = (12+3);//表達式上 const double &p3 = cc;//非常量引用
2.指針變量在定義時必須對其初始化,以鎖定某個已經存在的目標變量(或對象),在該指針變量的生命期內,該指向不能被更改。(×)
解析:
指針變量在定義的時候可以不初始化,這個很明顯嘛。在指針變量的聲明周期內,你當然可以改指針的指向,不然鏈表怎么實現。
//指針變量只聲明不定義 int *p;
知識點補充:
可以定義指針的引用,但是由於引用不是對象,因此不能有指向一個引用的指針。
//指針的引用 int *p = NULL; int *&a = p; //其實就是給指針p起個別名a
3.值返回的函數(如:double sqrt(double);)的調用表達式,如:sqrt(2.0))代表一個無名的臨時變量(或對象),一般不將其用作左值。 (√)
解析:
值返回函數調用返回的是一個無名變量,其生命周期很短,也就是說,當調用的表達式執行完了之后,這個無名變量就銷毀了。如果你要把他作為左值的話,那么在下一句話中他就銷毀 了,而且你給他賦值也沒意義,你又不知道他存儲在那里怎么拿到他的值。。
補充:
函數可以引用返回,而引用返回可以作為左值。比如我們重載的<<運算符,將其作為左值,就可以對其連續賦值(好像沒說明白,看代碼吧)。
//假裝我在某個類里面 friend ostream & operator<<(ostream &out,const Myclass &myclass){ out<<myclass.value; return out; } //假裝我在類外 cout<<myclass1<<myclass2; //就這樣連續輸出
4. 引用返回的函數,可以返回該函數中值傳遞的形參變量(或對象)。 (×)
解析:
函數返回時引用返回,那么一定要返回比這個函數的生命周期要長的變量,否則返回一個已經銷毀的變量沒有意義。這個題中,傳值傳進來的變量的生命周期是跟這個函數一起的,顯然生命周期並沒有長於這個函數,因此不能返回。
5. 任何類都有構造函數、復制構造函數、析構函數、賦值運算符函數。 (√)
解析:
任何類都有,有時候我們要自己定義,但一般情況下系統會幫我們自動定義好,只是沒有顯式定義而已,但其實他是有的。
6. 有靜態數據成員的類,一般地應該考慮為其設計復制構造函數、析構函數。 (√)
解析:
這個題是這樣的,由於我們課本上學靜態數據成員的時候呢,拿學生人數統計當的例子,所以按照老師的意思,每次創建一個新的學生對象,在構造時人數要加一,也就是靜態變量值加一,析構的時候自然減一了。題出的不是很好,說實話。。
7. 將用於輸出的插入運算符函數operator<<設計成友元函數的根本原因是因為進行輸出操作時需要訪問對象的內部數據成員。 (×)
解析:
首先這個函數並不是重載<<操作符,如果不設計為友元函數,那么這個函數就是一個重載函數,我們知道這個重載函數一定有一個參數是this指針,也就是說左操作數一定是this指針,這樣的話,我們就無法將要輸出的數據輸出到cout里面了。我再仔細解釋下,<<會匹配他左邊的值和右邊的值作為左操作數和右操作數,然后這兩個操作數傳參到你重載的函數里面,由於你的參數有一個默認的this指針,因此他會被作為默認的左操作數,也就是說,如果匹配的不是這個類的對象,就報錯了。所以你想輸出到cout里,就必須設置為友元函數。
代碼還是上面的代碼,理解下:
//假裝我在某個類里面 friend ostream & operator<<(ostream &out,const Myclass &myclass){ out<<myclass.value; return out; } //假裝我在類外 cout<<myclass1<<myclass2; //就這樣連續輸出
8. 在C++程序中,操作符new的功能與calloc函數的功能完全一樣。 (×)
解析:
new是calloc的升級版,顯然兩者的功能不是完全一樣的。具體差別為:calloc函數只管動態申請空間,不會管怎么釋放,而new的對象在delete的時候會調用其析構函數釋放掉其基本空間的數據。
9.創建一個C++字符串對象(如:string str;),則sizeof(str)的值等於str.length()的值。其中成員函數length為返回字符串的長度。 (×)
解析:
首先str沒有定義,只是進行的聲明,所以sizeof(str)的結果就是8(我測試的是8,在不同編譯器下是不同的請注意),也就是對應的string對象所占的基本空間,不隨字符串長度變化而改變,而str.length()返回的就是字符串實打實的長度了,這個沒什么可說的。
#include <iostream> using namespace std; int main() { string a; cout << sizeof(a)<< endl; cout<<a.length()<<endl; return 0; } //結果 8 0
10.基類的私有數據成員在派生類中是存在的,但不可直接訪問,需要用從基類繼承下來的函數訪問。(√)
解析:
基類的私有成員在派生類中確實是存在的,派生類會從基類中繼承下來其私有成員,但是不能直接訪問,想要訪問他,就需要通過調用基類的接口函數來訪問。
知識點補充:
public、protected、private區別和繼承方式區別
public:public表明該數據成員、成員函數是對所有用戶開放的,所有用戶都可以直接進行調用
private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用。
protected:protected對於子女、朋友來說,就是public的,可以自由使用,沒有任何限制,而對於其他的外部class,protected就變成private。
15級試題---選擇題
1. 類的構造函數的函數名與類名相同,可以重載構造函數。 (√)
解析:
類的構造函數名於類名相同,嗯。構造函數是有參數的,可以被重載,對。
知識點補充:
冒號語法
我們在類的構造函數后面加上:可以在進入函數體之前初始化某些成員。
class B{ public: B(int n){ b = n; } private: int b; }; class A{ public: A(int n):bb(n){ a = n; } private: int a; B bb; };
2. 類的析構函數可以被重載。 (×)
解析:
類的析構函數是不能被重載的,因為類的析構函數並沒有參數,也就意味着他沒有參數表,而函數的重載是通過參數表對應得到的,所以沒有辦法對析構函數進行重載。
3. 重載運算符函數不能改變運算符的操作數個數、優先級和結合方向。 (√)
解析:
運算符重載函數其運算符的優先級、結合性、操作數個數和語法結構保持不變。
4. 引用在聲明時必須對其初始化,以綁定某個已經存在的變量(或對象),在該引用的生命期內,該綁定不能被更改。 (√)
解析:
上面解析過了。
5.指針變量在定義時必須對其初始化,以鎖定某個已經存在的目標變量(或對象),在該指針變量的生命期內,該指向不能被更改。(×)
解析:
上面解析過了。
6.類的非靜態成員函數均有一個隱含的形式參數this指針常量,用於指向調用該函數的對象。函數體中不能改變該指針常量的指向(即鎖定調用該函數的對象)。 (√)
解析:
類的非靜態成員函數里都有this指針常量,都已經說了是指針常量了,着就意味着他的指向在定義的那一刻就不能修改了。
知識點補充:
指針常量和常量指針
常量指針:指向常量的指針,例如const int *p = &a,可以改變p的指向,但是指向的必須是常量。
指針常量:就是常指針,例如int * const p = & a ,可以修改p指向的變量的值,但是p的指向改不了。
7.派生類繼承了基類的所有數據成員,並且在派生類的成員函數中都能直接訪問基類的訪問屬性為private的成員。 (×)
解析:
上面解析過了,不能直接訪問。
8.構造派生類對象時,先調用基類的構造函數,后執行派生類的構造函數。析構派生類對象時,先調用基類的析構函數,后執行派生類的析構函數。 (×)
解析:
構造派生類對象的時候,先調用基類構造函數,然后調用派生類構造函數,這是對的。但是在析構的時候呢,要遵從先構造的后析構,后構造的函數先析構的原則,因此析構順序應該是相反的。
9.含純虛函數的類稱為抽象類,不能創建抽象類的對象,不能定義抽象類的指針變量,不能聲明抽象類的引用。 (×)
解析:
有純虛函數的類是抽象類,抽象類是不能創建對象的。但是我們是可以定義抽象類的指針變量的,當然也可以聲明他的引用。為什么?
抽象類不能創建對象,這個是個規定。
可以定義抽象類的指針變量,我們知道,創建一個對象,就會為對象分配具體的內存空間,但是定義指針變量並不會分配具體的內存空間,而是只需要4字節的存儲指針變量的空間就可以了,剩下的其實什么也沒做。
而定義抽象類的引用,理解起來就更簡單了,只不過是給這個類起了個別名,起個名字而已,也沒分配具體的內存空間,應該也可以吧,哈哈。
10.引用返回的函數可以作左值,也避免了函數值返回時創建與返回類型相同的臨時無名對象。(√)
解析:
引用返回的函數可以作為左值,因為函數返回的是一個引用,而引用的對象是可以作為左值的。這樣確實避免了無名對象這樣的尷尬。
16級試題---選擇題
1. 創建對象意味着給對象分配內存空間。在對象的基本空間中存放了該對象的非靜態數據成員。 (√)
解析:
創建對象,也就是實例化,就是分配具體的內存空間,這話沒毛病。對象的基本空間中存放的是該對象的非靜態數據成員,其他的數據成員都在堆空間或者全局數據區里面放着。
2.運算符sizeof能夠測量對象的基本空間及對象的資源空間所占用的內存單元字節數的總和。 (×)
解析:
sizeof測量的是對象的基本空間所占的內存空間,是不能測量其堆空間或者全局數據區資源長度的。
3.對於在某函數內創建的多個局部自動對象,當該函數返回而引起這些局部自動對象銷毀時,先創建的對象先析構、后創建的對象后析構。 (×)
解析:
上面講過了,先創建的對象后析構,后創建的對象先析構。
4.類的所有成員函數都有一個隱含傳遞的形參this指針。 (×)
解析:
類的所有成員函數嘛,很容易想到一些特殊的比如靜態成員函數,靜態成員函數沒有this,因為靜態成員函數可以被類的對象共有,也可以被繼承,如果有this,那繼承下來的函數的this指向誰呢?二義性了。這個時候你可能也會想到友元函數,如果友元函數是其他類的成員函數,那他就算是成員函數了(其他類的),有this指針,這個this指針是指向其他類的,而當友元函數是普通函數的時候呢,就沒有this指針了。
5.類的友元函數可以是另一個類的成員函數。甚至另一個類的所有成員函數都是本類的友元函數(友類)。 (√)
解析:
這個應該是書上原話吧,應該不需要解析。
6.常量成員函數不能修改對象的數據成員的值。 (√)
解析:
所謂常量成員函數,就是在函數聲明后面加上const,這個作用跟在函數參數表的每個參數前面加個const的效果是一樣的。
#include <iostream> using namespace std; class A { public: void show(int b,int c) const{ cout<<a<<"-"<<b<<"-"<<c<<endl; } A(int n){a = n;} private: int a; }; int main() { A a(5); a.show(1,2); return 0; } //結果 5-1-2
7.由於前增量、前減量、后增量、后減量運算符皆為單目運算符,故在重載后增量、后減量運算符時需要在其運算符函數聲明及定義時添加一個純形式上的參數int,以示與前增量、前減量運算符函數的區別。 (√)
解析:
前增量前減量、后增量后減量運算符都是的重載運算的區別就在於是否加了形式上的參數int,不加的情況就是前增量運算,如++a,加了就是后增量運算,如a++。
class A{ public: A & oeprator++(){ a++; return &*this; } int operator++(int){ int temp=a; temp++; return temp; } private: int a; }
知識點補充:
前增量前減量運算符和后增量后減量運算符都是單目運算符;前增量和前減量運算符的返回的是引用返回(++a),而后增量和后見諒運算符返回的是值返回,也就是創建臨時變量。前面也已經解釋了值返回也引用返回的區別,所以到這里就很清楚了。
8.派生類(或稱為子類)的成員函數可以直接訪問其基類(或成為父類)的所有成員,甚至是基類的私有成員。 (×)
解析:
上面解析過,派生類成員函數無法訪問基類private成員,只有掉從基類繼承下來的接口函數才能訪問。
9.含有純虛函數的類被稱為抽象類,可以創建抽象類的對象。 (×)
解析:
上面解析過,抽象類是不能創建對象的。
10.若某個類可能作為基類,則最好將其析構函數設計成虛函數。 (√)
解析:
一個類如果作為基類,就要考慮多態性了。之所以設計成虛函數,是考慮到了基類兼容派生類,即要析構一個由基類構造的派生類成員的時候,如果不設計成虛函數,就會在析構時候出現二義性,實際上只調用了基類的析構函數而沒有調用派生類的虛構函數,這不是我們要的。
知識點補充:
虛函數:“一個接口,多個方法”,這句話概括了虛函數的作用。虛函數實現的作用其實是動態綁定,比如,基類聲明show為虛函數,兩個派生類繼承基類,分別寫該繼承類的show函數的定義,由於基類會兼容派生類,那么基類調用show函數的時候,不能知道調用的是派生類的哪個show函數,實驗后發現調用的其實是基類的show函數,但是基類的show函數我們只聲明了但沒定義。而虛函數恰恰解決了這個問題,函數生命為虛函數之后,調用show 的時候,會根據其數據類型定態綁定show函數,然后調用。