首頁 > 軟體

C++類別中三大函數詳解(構造、解構和拷貝)

2023-03-31 06:01:10

前言

今天和大家分享一下C++中在建立類的時候編譯器會提供給一個類至少三個函數,分別是預設建構函式,解構函式,拷貝建構函式。

一.建構函式

1.建構函式的作用

我們在建立好類的物件之後,首先對它的每一個成員屬性賦值之後再對它們進行輸出操作,如果不賦值就輸出,這些值就會是垃圾值。而為了程式碼的簡介,一次性為所有成員屬性初始化,C++的類別提供了這樣的一個函數—建構函式。

2.建構函式的語法 類名(){}

1)建構函式,沒有返回值也不寫void

2) 函數名稱與類名相同

3)建構函式可以有引數,因此可以發生過載

4)程式在呼叫物件時候會自動呼叫構造,無須手動呼叫,而且只會呼叫一次

二.解構函式

1.解構函式的作用

解構函式的作用與建構函式相反,一般是執行物件的清理工作,當物件的生命週期結束的時候,會自動的呼叫。解構函式的作用並不是刪除物件,在物件復原它所佔用的記憶體之前,做一些清理的工作。清理之後,這部分記憶體就可以被系統回收再利用了。在設計這個類的時候,系統也會預設的提供一個解構函式。在物件的生命週期結束的時候,程式就會自動執行解構函式來完成這些工作。同建構函式,使用者自己定義,系統自動呼叫。

2.解構函式的語法~類名(){}

1)解構函式,沒有返回值也不寫void

2) 函數名稱與類名相同,在名稱前加上符號 ~

3)解構函式不可以有引數,因此不可以發生過載

4) 程式在物件銷燬前會自動呼叫解構,無須手動呼叫,而且只會呼叫一次

程式碼演示:

class Person
{
  public:
  //建構函式
  Person()
 {
  cout << "Person的建構函式呼叫" << endl;
 }
//解構函式
~Person()
 {
   cout << "Person的解構函式呼叫" << endl;
 }
};
void test01()
{
  Person p;
}
int main()
 {
   test01();
   system("pause");
   return 0;
 }

三.建構函式的分類及呼叫

1.兩種分類方式:

按引數分為: 有參構造和無參構造

按型別分為: 普通構造和拷貝構造

2.三種呼叫方式:

括號法

顯示法

隱式轉換法

//1、建構函式分類
// 按照引數分類分為 有參和無參構造 無參又稱為預設建構函式
// 按照型別分類分為 普通構造和拷貝構造
class Person {
public:
 
//無參(預設)建構函式
Person() {
cout << "無參建構函式!" << endl;
}
 
//有參建構函式
Person(int a) {
age = a;
cout << "有參建構函式!" << endl;
}
 
//拷貝建構函式
Person(const Person& p) {
age = p.age;
cout << "拷貝建構函式!" << endl;
}
 
//解構函式
~Person() {
cout << "解構函式!" << endl;
}
 
public:
int age;
};
 
//2、建構函式的呼叫
//呼叫無參建構函式
void test01() {
Person p; //呼叫無參建構函式
}
 
//呼叫有參的建構函式
void test02() {
//2.1 括號法,常用
Person p1(10);
//注意1:呼叫無參建構函式不能加括號,如果加了編譯器認為這是一個函數宣告
//Person p2();
 
//2.2 顯式法
Person p2 = Person(10);
Person p3 = Person(p2);
//Person(10)單獨寫就是匿名物件 當前行結束之後,馬上解構
 
//2.3 隱式轉換法
Person p4 = 10; // Person p4 = Person(10);
Person p5 = p4; // Person p5 = Person(p4);
//注意2:不能利用 拷貝建構函式 初始化匿名物件 編譯器認為是物件宣告
//Person p5(p4);
}
int main() {
test01();
//test02();
system("pause");
return 0;
}

四.拷貝建構函式呼叫時機

C++中拷貝建構函式呼叫時機通常有三種情況

1.使用一個已經建立完畢的物件來初始化一個新物件

2.值傳遞的方式給函數引數傳值

3.以值方式返回區域性物件

class Person {
public:
Person() {
cout << "無參建構函式!" << endl;
mAge = 0;
}
Person(int age) {
cout << "有參建構函式!" << endl;
mAge = age;
}
Person(const Person& p) {
cout << "拷貝建構函式!" << endl;
mAge = p.mAge;
}
//解構函式在釋放記憶體之前呼叫
~Person() {
cout << "解構函式!" << endl;
}
public:
int mAge;
};
//1. 使用一個已經建立完畢的物件來初始化一個新物件
void test01() {
Person man(100); //p物件已經建立完畢
Person newman(man); //呼叫拷貝建構函式
Person newman2 = man; //拷貝構造
//Person newman3;
//newman3 = man; //不是呼叫拷貝建構函式,賦值操作
}
//2. 值傳遞的方式給函數引數傳值
//相當於Person p1 = p;
void doWork(Person p1) {}
void test02() {
Person p; //無參建構函式
doWork(p);
}
//3. 以值方式返回區域性物件
Person doWork2()
{
Person p1;
cout << (int *)&p1 << endl;
return p1;
}
void test03()
{
Person p = doWork2();
cout << (int *)&p << endl;
}
int main() {
//test01();
//test02();
test03();
system("pause");
return 0;
}

五.建構函式呼叫規則

預設情況下,c++編譯器至少給一個類新增3個函數

1.預設建構函式(無參,函數體為空)

2.預設解構函式(無參,函數體為空)

3.預設拷貝建構函式,對屬性進行值拷貝

建構函式呼叫規則如下:

如果使用者定義有參建構函式,c++不在提供預設無參構造,但是會提供預設拷貝構造

如果使用者定義拷貝建構函式,c++不會再提供其他建構函式

class Person {
public:
//無參(預設)建構函式
Person() {
cout << "無參建構函式!" << endl;
}
//有參建構函式
Person(int a) {
age = a;
cout << "有參建構函式!" << endl;
}
//拷貝建構函式
Person(const Person& p) {
age = p.age;
cout << "拷貝建構函式!" << endl;
}
//解構函式
~Person() {
cout << "解構函式!" << endl;
}
public:
int age;
};
void test01()
{
Person p1(18);
//如果不寫拷貝構造,編譯器會自動新增拷貝構造,並且做淺拷貝操作
Person p2(p1);
cout << "p2的年齡為: " << p2.age << endl;
}
void test02()
{
//如果使用者提供有參構造,編譯器不會提供預設構造,會提供拷貝構造
Person p1; //此時如果使用者自己沒有提供預設構造,會出錯
Person p2(10); //使用者提供的有參
Person p3(p2); //此時如果使用者沒有提供拷貝構造,編譯器會提供
//如果使用者提供拷貝構造,編譯器不會提供其他建構函式
Person p4; //此時如果使用者自己沒有提供預設構造,會出錯
Person p5(10); //此時如果使用者自己沒有提供有參,會出錯
Person p6(p5); //使用者自己提供拷貝構造
}
int main() {
test01();
system("pause");
return 0;
}

六.深拷貝與淺拷貝

淺拷貝:簡單的賦值拷貝操作

深拷貝:在堆區重新申請空間,進行拷貝操作

範例:

class Person {
public:
//無參(預設)建構函式
Person() {
cout << "無參建構函式!" << endl;
}
//有參建構函式
Person(int age ,int height) {
cout << "有參建構函式!" << endl;
m_age = age;
m_height = new int(height);
cout << "拷貝建構函式!" << endl;
//如果不利用深拷貝在堆區建立新記憶體,會導致淺拷貝帶來的重複釋放堆區問題
m_age = p.m_age;
m_height = new int(*p.m_height)
}
//拷貝建構函式
Person(const Person& p) {
;
}
//解構函式
~Person() {
cout << "解構函式!" << endl;
if (m_height != NULL)
{
delete m_height;
}
}
public:
int m_age;
int* m_height;
};
void test01()
{
Person p1(18, 180);
Person p2(p1);
cout << "p1的年齡: " << p1.m_age << " 身高: " << *p1.m_height << endl;
cout << "p2的年齡: " << p2.m_age << " 身高: " << *p2.m_height << endl;
}
int main() {
test01();
system("pause");
return 0;
}

總結:

如果屬性有在堆區開闢的,一定要自己提供拷貝建構函式,防止淺拷貝帶來的問題

到此這篇關於C++類別中三大函數(構造、解構和拷貝)的文章就介紹到這了,更多相關C++類別的三大函數內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com