1.構造函數explicit與普通構造函數有什麼差別?
(explicit構造函數的作用)
explicit構造函數是用來防止隐式轉換的。
代碼如下:
class Test1
{
public:
Test1(int n){num=n};//普通構造函數
private:
int num;
};
class Test2
{
public:
explicit Test2(int n){num=n;}//explicit(顯式)構造函數
private:
int num;
};
int main()
{
Test1 t1=;//隐式調用其構造函數,成功
Test2 t2=;//編譯錯誤,不能隐式調用其構造函數
Test2 t3();//顯示調用成功
return ;
Test1的構造函數帶一個int型的參數,代碼Test1 t1=12;會隐式轉換成調用Test1的這個構造函數。而Test2的構造函數被聲明為explicit(顯式),這表示不能通過隐式轉換來調用這個構造函數,是以Test2 t2=12;會出現編譯錯誤。
是以,普通構造函數能夠被隐式轉換,而explicit構造函數隻能顯示調用。
2.explicit構造函數的作用
下面的程式f()被調用時,輸出是什麼?
#include<iostream>
#include<string>
using namespace std;
class Number
{
public:
string type;
Number():type("void"){}
explicit Number(short):type("short");
Number(int):type("int"){}
};
void Show(const Number& n){cout<<n.type;}
void main()
{
short s=;
Show(s);
}
A.void
B.short
C.int
D.None of above
(1)Show(s)中的s為short類型,其值為42,是以首先檢查參數為short的構造函數能否被隐式轉換。由于代碼第10行的構造函數被聲明為顯示調用(explicit),是以不能隐式轉換。于是進行下一步。
(2)42自動轉換為int類型。
(3)檢查參數為int的構造函數能否被隐式轉換。由于代碼第11行參數為int的構造函數沒有被聲明為顯示調用,是以調用此構造函數構造出一個臨時對象。
(4)列印上一步臨時對象的type成員,即“int”。
3.C++中虛析構函數的作用是什麼
大家知道,析構函數時為了在對象不被使用之後釋放它的資源,虛函數是為了實作多态。那麼,把析構函數聲明為virtual有什麼作用呢?請看下面的代碼:
#include<iostream>
using namespace std;
class Base
{
public:
Base(){};//Base的構造函數
~Base()//Base的析構函數
{
cout<<"Output from the destructor of class Base!"<<endl;
};
void Dosomething()
{
cout<<"Do something in class Base!"<<endl;
};
};
class Derived:public Base
{
public:
Derived() {};//Derived的構造函數
~Derived()//Derived的析構函數
{
cout<<"output from the destructor of class Derived!"<<endl;
};
void Dosomething()
{
cout<<"Do something in class Derived!"<<endl;
};
};
int main()
{
Derived *pTest1=new Derived();//Derived類的指針
pTest1->Dosomething();
delete pTest1;
cout<<endl;
Base *pTest2=new Derived();//Base類的指針
pTest2->Dosomething();
delete pTest2;
return ;
}
先看程式輸出結果:
代碼第36行,可以正常釋放pTest1資源,而代碼第42行沒有正常釋放pTest2的資源,因為從結果看,Derived的析構函數沒有被調用。通常情況下,類的析構函數裡面都是釋放記憶體資源的,而析構函數不被調用的話就會造成記憶體洩漏。原因是指針pTest2是Base類型的指針,釋放pTest2時隻進行Base類的析構函數。在代碼第8行前面加上virtual關鍵字,由于Base的析構函數時virtual的。就會先找到并執行Derived類的析構函數,然乎執行Base類的析構函數,資源正常釋放,避免了記憶體洩漏。
是以,隻有當一個類被用來作為基類的時候,才會把析構函數寫成虛函數。
4.看代碼寫結構——析構函數的執行順序
#include<iostream.h>
class A
{
private:
int a;
public:
A(int aa){a=aa;};
~A(){cout<<"Destructor A!"<<a<<endl;};
};
class B:public A
{
private:
int b;
public:
B(int aa=,int bb=):A(aa) {b=bb;};
~B(){cout<<"Destructor B!"<<b<<endl;};
};
void main()
{
B obj1(),obj2(,);
return;
}
本題考查的是析構函數的執行順序。析構函數的執行順序與構造函數的執行順序相反。
main()函數中定義了兩個類B的對象,它們的基類是A。由于這兩個對象都是棧中配置設定的,當main()函數退出時會發生析構,又因為obj1比obj2先聲明,是以obj2先析構。它們析構的順序是首先執行B的析構函數,然後執行A的析構函數。
輸出結構如下:
7.複制構造函數是什麼?什麼是深複制和淺複制
(複制構造函數是什麼?什麼情況下用到它?什麼是深複制什麼是淺複制?)
複制構造函數是一種特殊的構造函數。它由編譯器調用來完成一些基于同一類的其他對象的構件及初始化。
如果在類中沒有顯式地聲明一個複制構造函數,那麼,編譯器會私下裡制定一個函數來進行對象之間的位複制。這個隐含的複制構造函數簡單地關聯了所有的類成員。
淺複制是指讓新舊兩個對象指向同一外部的内容,而深複制是指為新對象制作了外部對象的獨立複制。
8.編譯器與預設的copy constructor
(什麼時候編譯器會生成預設的copy constructor?如果已經寫了一個構造函數,編譯器還會生成copy constructor?)
如果使用者沒有自定義複制構造函數,并且代碼中用到了複制構造函數,那麼編譯器就會生成預設的複制構造函數;但如果使用者定義了複制構造函數,那麼編譯器就不會生成複制構造函數。
如果使用者定義了一個構造函數,且不是複制構造函數,而此時在代碼中用到了複制構造函數,那麼編譯器也還會生成預設的複制構造函數;如果沒有使用,則編譯器就不會生成預設的複制構造函數。