繼續來學習構造函數的知識,通過前面學習,我們知道一個類中可以有 無參構造,有參構造,拷貝構造,那麼編譯器是如何決定調用這些構造函數,本篇就來學習這個調用規則。
知識點:
默認情況下,C++編譯器至少給一個類添加3個函數
1.默認構造函數(無參,函數體爲空)
2.默認析構函數(無參,函數體爲空)
3.默認拷貝構造函數,對屬性進行值拷貝
構造函數的調用規則如下:
如果用戶定義有參構造函數,c++不再提供默認無參構造,但是會提供默認拷貝構造
如果用戶定義拷貝構造函數,c++不會再提供其他構造函數
下面我們分別用代碼來驗證以上知識點。
1.只要創建一個類,C++編譯器會給這個類至少添加三個函數。
這裏,我們知道編譯器會自動添加無參構造函數,所以我們來代碼證明看看編譯器添加拷貝構造的效果。
#include<iostream>
using namespace std;
class Point
{
public:
//構造函數
Point()
{
cout << "調用了構造函數"<< endl;
}
//有參構造
Point(int x, int y)
{
cout << "調用了有參構造函數" << endl;
X = x;
Y = y;
}
//拷貝構造
Point(const Point &p)
{
cout << "調用了拷貝構造函數" << endl;
//將p的屬性拷貝到當前類的初始化
X = p.X;
Y = p.Y;
}
//析構函數
~Point()
{
cout << "調用了析構函數" << endl;
}
public:
int X;
int Y;
};
void test01()
{
Point p;
p.X = 5;
p.Y = 5;
//利用拷貝構造
Point p1(p);
cout << "p1的X值爲" << p1.X << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
上面代碼我們補全了無參和有參和拷貝構造,運行代碼
這個結果是我們前面一篇就已經知道的效果,現在我們把上面代碼中的拷貝構造函數給註銷,看看編譯器會不會給我們自動加上拷貝構造函數。
註銷這段代碼,然後test01()代碼保持不變,運行
分析:
1)Point p肯定走默認無參構造,然後p對象進行了X和Y的設置值
2)通過右側運行結果,顯示p1的X座標也是5,說明發生了拷貝,而且有兩個析構函數調用的打印
3)第二點說明了,C++編譯器自動給我們運行了拷貝構造,至於這個拷貝代碼是什麼,我們不清楚,但是效果就是,X和Y都進行值的拷貝。
2.證明如果用戶提供有參構造,編譯器不再提供無參構造
我們把上面類代碼改成這樣,不寫無參構造,只留下一個有參構造,然後代碼中特意調用無參構造,看看報什麼錯誤。
#include<iostream>
using namespace std;
class Point
{
public:
//有參構造
Point(int x, int y)
{
cout << "調用了有參構造函數" << endl;
X = x;
Y = y;
}
//析構函數
~Point()
{
cout << "調用了析構函數" << endl;
}
public:
int X;
int Y;
};
void test01()
{
Point p;
}
int main()
{
test01();
system("pause");
return 0;
}
嘗試運行以上代碼
這裏代碼想調用無參構造,但是由於這個規則(用戶寫了有參構造,編譯器不會自動添加無參構造),所以報以上錯誤。這裏雖然不提供無參構造,但是還是會提供拷貝構造,下面代碼改成這樣,運行可以證明
3.證明如果用戶寫了拷貝構造,編譯器不提供其他構造函數
#include<iostream>
using namespace std;
class Point
{
public:
//拷貝構造
Point(const Point &p)
{
cout << "調用了拷貝構造函數" << endl;
//將p的屬性拷貝到當前類的初始化
X = p.X;
Y = p.Y;
}
public:
int X;
int Y;
};
void test01()
{
Point p;
}
int main()
{
test01();
system("pause");
return 0;
}
只有一個拷貝構造,編譯一下,
這個證明了如果用戶提供拷貝構造函數,編譯器不會提供無參構造函數。