C++對象定義方法匯總
1. 棧上定義方式
1.1 調用無參構造函數的定義方式
無參構造函數有兩種:
- 默認無參構造函數
Demo(){}
- 默認值列表構造函數。
Demo():a{1},b{2}{} // 使用初始化列表實現
對象定義方式:
Demo d;
Demo d1{};
// 以下定義方式還調用了拷貝構造函數
Demo d2 = Demo();
Demo d3 = Demo{};
🚫 注意事項:
- 一個類只能有一個無參構造函數:無參構造函數的參數列表都為空,無法實現函數重載。
- 不能使用
對象名()
調用無參構造函數。 - 可以使用
類名()
的方式創建對象。 - 推薦使用花括號定義對象。
示例
class Demo1{
public:// 無參構造函數Demo(){cout << "無參構造函數"}
}class Demo2{
private:int a;int b;
public:// 默認值列表構造函數Demo():a{1},b{2}{cout << "默認值列表構造函數"<< endl;}
}int main()
{// 棧變量Demo1 d1; // 調用無參構造函數Demo2 d2{}; // 調用無參構造函數Demo1 d3 = Demo1();Demo2 d4 = Demo2{};// Demo2 d3(); // 錯誤
}
1.2 調用有參構造函數的定義方式
有參構造函數通過不同的參數列表進行重載。一個類中可以存在多個有參構造函數。
有參構造函數也可以使用參數默認值簡化重載。包括兼并無參構造函數。
有參構造函數定義:
Demo(int a, int b):a(a),b(b){}
帶默認值的有參構造函數定義:
Demo(int a = 1):a(a),b(1){}
此有參構造函數兼并無參構造函數,若定義了無參構造函數則會起沖突。
對象定義方式:
調用有參構造函數的對象定義通過()
或{}
來傳遞參數。
主流推薦使用{}
。
Demo d(2);
Demo d1{2, 3};
// 以下定義方式還調用了拷貝構造函數
Demo d2 = Demo(2, 3);
Demo d3 = Demo{2};
示例:
#include <iostream>
using namespace std;class Demo{
private:int a;int b;
public:// 帶默認值的有參構造函數,可替代無參構造函數Demo(int a = 1):a{a},b{2}{cout << "帶默認值的有參構造函數"<< endl;}// 初始化列表構造函數Demo(int a, int b):a{a},b{b}{cout << "初始化列表構造函數"<< endl;}
};int main()
{// 棧變量Demo d1; // 有參構造函數Demo d2{3}; // 有參構造函數Demo d3{3, 4}; // 初始化列表構造函數Demo d4(3, 4); // 初始化列表構造函數Demo d5 = Demo(2); // 有參構造函數Demo d6 = Demo{2}; // 有參構造函數Demo d7 = Demo(2,6); // 初始化列表構造函數Demo d8 = Demo{2,6}; // 初始化列表構造函數return 0;
}
1.3 調用拷貝構造函數的定義方式
拷貝構造函數是在用同類對象來定義新對象時調用。已經規定死了它的函數名和參數列表,所以不存在重載,一個類也只有一個拷貝構造函數。
拷貝構造函數定義:
Demo(const Demo& d):a{d.a},b{d.b}{}
對象定義方式:
拷貝構造函數是一種有參構造函數,遵循有參構造函數的對象定義方式。也有一種獨特的定義方式:=
Demo d1; // 要先存在一個用來拷貝的對象
Demo d2(d1);
Demo d3{d1};
Demo d4 = d1; // 對象定義時,= 號調用的是拷貝構造函數
Demo d4 = Demo(); // 通過臨時對象來定義新對象
示例:
#include <iostream>
using namespace std;class Demo{
private:int a;int b;
public:// 帶默認值的有參構造函數,可替代無參構造函數Demo(int a = 1):a{a},b{2}{cout << "帶默認值的有參構造函數"<< endl;}// 拷貝構造函數Demo(const Demo& d):a{d.a},b{d.b}{cout << "拷貝構造函數"<< endl;}
};int main()
{// 棧變量Demo d1; // 有參構造函數// 拷貝構造函數Demo d11(d1);Demo d12{d1};Demo d13 = d1;Demo d2 = Demo(2); // 有參構造函數Demo d3 = Demo{2}; // 有參構造函數return 0;
}
2. 堆上定義方式
堆上定義對象主要通過堆操作符new
來實現,它返回一個對象指針。
1.1 調用無參構造函數的定義方式
Demo *pd = new Demo; // 無參構造函數Demo *pd10 = new Demo[2]; // 無參構造函數,返回對象數組Demo *pd2 = new Demo(); // 無參構造函數Demo *pd3 = new Demo{}; // 無參構造函數
1.2 調用有參構造函數的定義方式
Demo *pd4 = new Demo(1); // 有參構造函數
Demo *pd5 = new Demo{1}; // 有參構造函數
1.3 調用拷貝構造函數的定義方式
Demo d1;
Demo *pd1 = new Demo(d1);
Demo *pd2 = new Demo{d1};
3. 總結
對象定義方式有兩大類:
- 對象名:
類名 對象名
; - 類名:
類名()
;
對象定義的三小類: - 無參構造:可無符號、可帶
()
和{}
。變量名不能帶()
,類名可以帶()
- 有參構造:可通過
()
、{}
傳遞參數。 - 拷貝構造:由
()
、{}
、=
傳遞同類對象參數。
對象定義是指對象第一次創建,構造函數只會在對象第一次創建的時候調用,若是已有對象使用了與對象定義相似的格式,必定不會調用構造函數。
4. 綜合示例
#include <iostream>
using namespace std;class Demo{
private:int a;int b;
public:// 無參構造函數
// Demo(){cout << "無參構造函數"}// 默認值列表構造函數Demo():a{1},b{2}{cout << "無參構造函數"<< endl;}// 有參構造函數Demo(int a):a{a},b{2}{cout << "有參構造函數"<< endl;}// 初始化列表構造函數Demo(int a, int b):a{a},b{b}{cout << "初始化列表構造函數"<< endl;}// 拷貝構造函數Demo(const Demo& d):a{d.a},b{d.b}{cout << "拷貝構造函數"<< endl;}// 賦值運算符重載Demo& operator=(const Demo& d){cout << "賦值運算符重載"<< endl;if(this == &d) return *this;a = d.a;b = d.b;return *this;}
};int main()
{// 棧變量Demo d; // 無參構造函數Demo d1{}; // 無參構造函數Demo d2{3}; // 有參構造函數Demo d3{3, 4}; // 初始化列表構造函數Demo d4(3, 4); // 初始化列表構造函數Demo d5 = Demo(); // 無參構造函數Demo d6 = Demo{}; // 無參構造函數Demo d7 = Demo(2); // 有參構造函數Demo d8 = Demo{2}; // 有參構造函數Demo d9 = Demo(2,6); // 初始化列表構造函數Demo d10 = Demo{2,6}; // 初始化列表構造函數// 堆變量Demo *pd = new Demo; // 無參構造函數Demo *pd10 = new Demo[2];Demo *pd2 = new Demo(); // 無參構造函數Demo *pd3 = new Demo{}; // 無參構造函數Demo *pd4 = new Demo(1); // 有參構造函數Demo *pd5 = new Demo{1}; // 有參構造函數Demo *pd6 = new Demo(1, 2); // 初始化列表構造函數Demo *pd7 = new Demo{1, 2}; // 初始化列表構造函數// 拷貝構造函數Demo d11(d4);Demo d12{d4};Demo d13 = d3;Demo *pd8 = new Demo(d4);Demo *pd9 = new Demo{d4};// 賦值運算符重載d11 = d3;*pd9 = d4;return 0;
}