天天看點

C++部分——C++面向對象(3)

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 ;
}
           

先看程式輸出結果:

C++部分——C++面向對象(3)

代碼第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的析構函數。

輸出結構如下:

C++部分——C++面向對象(3)

7.複制構造函數是什麼?什麼是深複制和淺複制

(複制構造函數是什麼?什麼情況下用到它?什麼是深複制什麼是淺複制?)

複制構造函數是一種特殊的構造函數。它由編譯器調用來完成一些基于同一類的其他對象的構件及初始化。

如果在類中沒有顯式地聲明一個複制構造函數,那麼,編譯器會私下裡制定一個函數來進行對象之間的位複制。這個隐含的複制構造函數簡單地關聯了所有的類成員。

淺複制是指讓新舊兩個對象指向同一外部的内容,而深複制是指為新對象制作了外部對象的獨立複制。

8.編譯器與預設的copy constructor

(什麼時候編譯器會生成預設的copy constructor?如果已經寫了一個構造函數,編譯器還會生成copy constructor?)

如果使用者沒有自定義複制構造函數,并且代碼中用到了複制構造函數,那麼編譯器就會生成預設的複制構造函數;但如果使用者定義了複制構造函數,那麼編譯器就不會生成複制構造函數。

如果使用者定義了一個構造函數,且不是複制構造函數,而此時在代碼中用到了複制構造函數,那麼編譯器也還會生成預設的複制構造函數;如果沒有使用,則編譯器就不會生成預設的複制構造函數。

繼續閱讀