1. 程式人生 > >C++隱式構造與顯式構造

C++隱式構造與顯式構造

<一> 

class Stock
{
private:
    string _company;
    long _share;
    double  _val;
};

C++提供了兩種使用建構函式來初始化物件的方法。第一種是顯式的呼叫建構函式:

Stock food = Stock("hello",12,20.5);

這將food物件的_company成員設定為字串"hello",將_share成員設定為12,以此類推。

另一種是隱式地呼叫建構函式:

Stock garment("world",13,2.5);

這種呼叫更緊湊,它與下面的顯示呼叫等價:

Stock garment = Stock("world",13,2.5);

每次建立類物件(甚至使用new動態分配記憶體)時,C++都使用類建構函式。下面是將建構函式與new一起使用的方法:

Stock *pstock =  new Stock("google",15,22.5);

這條語句建立了一個Stock物件,將其初始化為引數提供的值,並將該物件的地址賦給pstock指標。在這種情況下,物件沒有名稱,但是可以使用指標來管理該物件。

建構函式的使用不同於其他類方法。一般來說,使用物件來呼叫方法:

stock1.show();

但無法使用物件來呼叫建構函式,因為在建構函式構造出物件之前,物件是不存在的。因此建構函式被用來建立物件,而不能同過物件來呼叫。

<二>

class A
{
};

如果在編寫類時沒有顯示的寫出其建構函式,拷貝建構函式,解構函式,以及過載賦值操作符,編譯器會在編譯程式碼時,會為該類加上這些。

其形式大致如下:

class A
{
     A()
     {
     }

     A& operator =(const A& a)
     {
        memcpy(this, &a, sizeof(A));  //此處可能用問題,僅為表明不是淺拷貝
        return *this;
     }

     A(const A& a)
     {
       *this = a; //呼叫了賦值過載函式
     }

      ~A() // 注意在解構函式前不會加上virtual關鍵字
     {
     }
};


下面給出一些示例,註釋部分說明了函式呼叫的情況:

void f()
{
 
   A a;     // A()建構函式被呼叫
   A b(a);  // A(const A& a)建構函式被呼叫 
   A c = a; // A(const A& a)建構函式被呼叫 
   b = c;   // A& operator = (const A& a)賦值操作符過載函式被呼叫 
}
 // 離開f()函式之前,a,b,c的解構函式被呼叫,釋放資源

 

A c = a;

這句程式碼實際呼叫的是拷貝建構函式,而非賦值函式。

因此,我們可以構造出這樣的程式碼。


class A
{
private:
    int *m_data;
    std::string ss;
public:
    A()
    {
        m_data = NULL;
    }
    A(int n)
    {
        m_data = NULL;
        if (n>0)
            m_data = new int[n];
    }
    A& operator =(const A& a)
    {
        memcpy(this, &a, sizeof(A));
        return *this;
    }
    virtual ~A()
    {
        if (NULL!=m_data)
        {
            delete [] m_data;
            m_data = NULL;
        }
    }
};
int main()
{
     A a = 3; // 將整數3賦值給一個物件
     return 0;
}

將整數3賦值給一個A型別物件a,然而以上程式碼可以編譯通過。 -- 有點不合常理

這是由於“單引數建構函式”被自動型別轉換(這是一個隱式轉換)。

可以通過explicit關鍵字,阻止“以賦值語法進行帶有轉型操作的初始化”。如下所示:


class A
{
private:
     int *m_data;
     std::string ss;
public:
     A()
     {
         m_data = NULL;
     }
     explicit A(int n)
     {
         m_data = NULL;
         if (n>0)
             m_data = new int[n];
     }
     A& operator =(const A& a)
     {
     memcpy(this, &a, sizeof(A));
     return *this;
     }
     virtual ~A()
     {
         if (NULL!=m_data)
         {
              delete [] m_data;
              m_data = NULL;
         }
     }
 };
int main()
{
     // A a = 3; // 編譯無法通過
     A b(3); // 可以編譯通過
     return 0;
}