日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++析構函數內部工作機制詳解_C 語言

作者:北冥有魚丶丶 ? 更新時間: 2023-06-21 編程語言

我們主要從三個方面來學習析構函數的工作原理:

  • 析構函數的內部工作機制
  • 默認析構函數的內部工作機制
  • 析構函數的調用

1、析構函數的內部工作機制

眾所周知,在對象的生命周期結束時會自動調用析構函數用于清理對象所申請的資源,那么它是如何清理的呢?

析構函數會調用delete函數釋放對象中new出來的空間,即析構函數通過delete函數來清理對象所申請的資源,當然如果對象沒有申請資源,那么就無需調用delete函數

由于是new出來的對象是在堆上分配空間的,即使離開了作用域,其依然存在,我們必須在析構函數中主動delete來釋放new出來的在堆上的空間,否則對象消亡后,離開了作用域后,指向該空間的數據成員(指針)就會消失,我們失去了對這片空間的控制權,別人也無法使用這片空間,這就會造成內存泄漏。

如果對象是new出來的,那么它就是一個堆對象,不會被 操作系統自動回收,需要我們手動調用delete函數釋放該堆對象,在delete函數中會先調用析構函數釋放該對象所申請的資源,那么析構函數如何釋放對象所申請的資源呢,就是前面所說的,析構函數又會調用delete函數來釋放對象所申請的資源,當然如果對象沒有申請資源,那么就無需調用delete函數。

#include <iostream>
using namespace std;
class Person {
public:
    Person() {
        cout <<  "調用了Person的構造函數" << endl;
    }
    ~Person() {
        cout << "調用了Person的析構函數" << endl;
    }
private:
    int name;
};
int main() {
    Person* person = new  Person();
    delete person;
    return 0;
}

2、默認析構函數的內部工作機制

我們清楚了析構函數的內部工作機制后,繼續思考一個問題,默認析構函數它的內部是怎么工作的呢?

我們先來看看下面這段代碼

class Time
{
public:
	~Time()
	{
		cout << "~Time()" << endl;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	// 基本類型(內置類型)
	int _year = 1970;
	int _month = 1;
	int _day = 1;
	// 自定義類型
	Time _t;
};
int main()
{
	Date d;
	return 0;
}

程序運行結束后輸出:~Time(),在main方法中根本沒有直接創建Time類的對象,為什么最后會調用Time類的析構函數?

這就涉及到默認析構函數的內部工作機制了。

默認析構函數,對于基本類型成員不做處理,對于自定義類型成員會去調用它的析構函數。

總結: 默認構造函數對基本類型不做處理,對自定義類型會調用它的默認構造函數,默認拷貝構造函數對基本類型是按照字節方式直接拷貝的,對自定義類型是調用其拷貝構造函數完成拷貝的,默認析構函數對基本類型不做處理,對自定義類型會調用它的析構函數。默認賦值運算符對基本類型成員變量以值的方式逐字節拷貝。而對自定義類型成員變量需要調用對應類的賦值運算符重載完成賦值。

默認構造函數只有一個,析構函數只有一個,拷貝構造函數只有一個,賦值運算符重載只有一個

如果類中沒有申請資源時,析構函數可以不寫,直接使用編譯器生成的默認析構函數,什么事都不會干,比如Date類;有資源申請時,一定要寫,否則會造成資源泄漏

3、析構函數的調用

析構函數在對象消亡時被調用,以清理對象所申請的資源,那具體它在何時被調用呢?

析構函數主要在以下4種情況下會被調用:

對象生命周期結束,此時會自動調用析構函數。

#include<iostream>
using namespace std;
class Person {
public:
    Person() {
        cout << "調用了Person的構造函數" << endl;
    }
    ~Person() {
        cout << "調用了Person的析構函數" << endl;
    }
private:
    int name;
};
int main() {
    Person person;
    return 0;
}

運行結果如下圖所示:

該運行結果說明,在對象的生命周期結束后,會自動調用對象的析構函數。

成員關系:對象car是對象person的成員,person的析構函數被調用時,對象car的析構函數也被調用。

#include <iostream>
using namespace std;
class Car {
public:
    Car() {
        cout << "調用了Car的構造函數" << endl;
    }
    ~Car() {
        cout << "調用了Car的析構函數" << endl;
    }
private:
    int name;
};
class Person {
public:
    Person() {
        cout << "調用了Person的構造函數" << endl;
    }
    ~Person() {
        cout << "調用了Person的析構函數" << endl;
    }
private:
    int name;
    Car car;
};
int main() {
    Person person;
    return 0;
}

先調用的是包含類的析構函數,然后調用的是成員對象的析構函數

繼承關系:當Person是Student的父類,調用Student的析構函數,會調用Person的析構函數。

#include <iostream>
using namespace std;
class Person {
public:
    Person() {
        cout << "調用了Person的構造函數" << endl;
    }
    ~Person() {
        cout << "調用了Person的析構函數" << endl;
    }
private:
    int name;
};
class Student :public Person {
public:
    Student() {
        cout << "調用了Student的構造函數" << endl;
    }
    ~Student() {
        cout << "調用了Student的析構函數" << endl;
    }
private:
    int name;
    string no;
};
int main() {
    Student student;
    return 0;
}

先調用的是派生類的析構函數釋放派生類的資源,然后調用的才是父類的析構函數釋放父類成員所指向的資源

值得注意的是,如果派生類對象是new出來的對象,基類指針指向一個new生成的派生對象,通過delete銷毀基類指針指向的派生類對象時,有以下兩種情況:

1、 如果基類析構函數不是虛析構函數,則只會調用基類的析構函數,派生類的析構函數不被調用,此時派生類中申請的資源不被回收。

2、 如果基類析構函數為虛析構函數,則釋放基類指針指向的對象時會調用基類及派生類析構函數,派生類對象中的所有資源被回收。

原文鏈接:https://blog.csdn.net/weixin_44049823/article/details/127928420

  • 上一篇:沒有了
  • 下一篇:沒有了
欄目分類
最近更新