C++隱式構造與顯式構造
阿新 • • 發佈:2018-11-17
<一>
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;
}