最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++六大默認(rèn)成員函數(shù)的實現(xiàn)

 更新時間:2025年02月07日 08:57:08   作者:落水 zh  
C++中的六大默認(rèn)成員函數(shù)包括默認(rèn)構(gòu)造函數(shù)、默認(rèn)析構(gòu)函數(shù)、默認(rèn)拷貝構(gòu)造函數(shù)、默認(rèn)拷貝賦值運算符、移動構(gòu)造函數(shù)和移動賦值運算符,本文就來介紹一下這些函數(shù)的使用,感興趣的可以了解一下

C++中的六大默認(rèn)成員函數(shù)是編譯器在特定條件下自動生成的成員函數(shù),用于管理對象的生命周期和資源操作。它們分別是:

默認(rèn)構(gòu)造函數(shù)

  • 作用:初始化對象,當(dāng)類沒有顯式定義任何構(gòu)造函數(shù)時生成。

  • 生成條件:用戶未定義任何構(gòu)造函數(shù)。

  • 注意:若類有其他構(gòu)造函數(shù)(如帶參數(shù)的構(gòu)造函數(shù)),需顯式使用 = default 聲明默認(rèn)構(gòu)造函數(shù)。

class Person
{
public:
	//Person()
	//{

	//} 不寫的話默認(rèn)自動生成
	void GetAge()
	{
		std::cout << _age << std::endl;
	}
private:
	int _age;
};

int main()
{
	Person p;
	p.GetAge();
}

其特征如下:

函數(shù)名與類名相同

無返回值。

對象實例化時編譯器自動調(diào)用對應(yīng)的構(gòu)造函數(shù)。

構(gòu)造函數(shù)可以重載。

如果類中沒有顯式定義構(gòu)造函數(shù),則C++編譯器會自動生成一個無參的默認(rèn)構(gòu)造函數(shù),一旦用戶顯式定義編譯器將不再生成。

編譯器生成默認(rèn)的構(gòu)造函數(shù)會對自定類型成員調(diào)用的它的默認(rèn)成員
函數(shù)。C++11 中針對內(nèi)置類型成員不初始化的缺陷,又打了補丁,即:內(nèi)置類型成員變量在類中聲明時可以給默認(rèn)值。

默認(rèn)析構(gòu)函數(shù)

  • 作用:釋放對象資源,默認(rèn)析構(gòu)函數(shù)調(diào)用成員變量的析構(gòu)函數(shù)。

  • 生成條件:用戶未定義析構(gòu)函數(shù)。

  • 注意:若類管理動態(tài)資源(如堆內(nèi)存),需自定義析構(gòu)函數(shù)以避免內(nèi)存泄漏

class Person
{
public:
	//Person()
	//{

	//} 不寫的話默認(rèn)自動生成
	void GetAge()
	{
		std::cout << _age << std::endl;
	}

	~Person()
	{

	}
private:
	int _age;
};

int main()
{
	Person p;
	p.GetAge();
}

RAII技術(shù)

RAII(Resource Acquisition Is Initialization,資源獲取即初始化)是C++中一種管理資源的編程技術(shù)。它通過將資源的生命周期與對象的生命周期綁定在一起,利用C++的構(gòu)造函數(shù)和析構(gòu)函數(shù)來自動管理資源,從而避免了手動分配和釋放資源可能帶來的問題,如內(nèi)存泄漏、資源未正確釋放等。

RAII的核心思想

  • 資源在對象構(gòu)造時獲取:當(dāng)一個對象被創(chuàng)建時,它的構(gòu)造函數(shù)負責(zé)獲取所需的資源(例如,動態(tài)內(nèi)存分配、文件打開、網(wǎng)絡(luò)連接等)。
  • 資源在對象銷毀時釋放:當(dāng)對象離開作用域或被顯式刪除時,其析構(gòu)函數(shù)會自動釋放之前獲取的資源。

優(yōu)點

  • 異常安全性:由于資源管理由構(gòu)造和析構(gòu)函數(shù)自動處理,即使程序中拋出了異常,也能確保資源得到正確釋放。
  • 簡化代碼:開發(fā)者不需要手動跟蹤每個資源的狀態(tài),并且可以在不使用顯式的try-finally塊的情況下保證資源的釋放。
  • 防止資源泄露:只要對象被正確地創(chuàng)建并最終銷毀,資源就會被正確釋放。

示例

以下是一個簡單的例子,展示了如何使用RAII來管理動態(tài)分配的內(nèi)存:

#include <iostream>

class ResourceHandler {
private:
    int* data;
public:
    // 構(gòu)造函數(shù):資源獲取
    ResourceHandler() {
        data = new int(10); // 分配資源
        std::cout << "Resource acquired." << std::endl;
    }

    // 析構(gòu)函數(shù):資源釋放
    ~ResourceHandler() {
        delete data; // 釋放資源
        std::cout << "Resource released." << std::endl;
    }

    void showData() const {
        std::cout << "Data: " << *data << std::endl;
    }
};

void useResource() {
    ResourceHandler handler;
    handler.showData();
    // 不需要手動釋放資源,handler離開作用域時會自動調(diào)用析構(gòu)函數(shù)
}

int main() {
    useResource();
    return 0;
}

在這個例子中,ResourceHandler類負責(zé)管理一個整數(shù)類型的動態(tài)分配內(nèi)存。構(gòu)造函數(shù)在對象創(chuàng)建時分配資源,而析構(gòu)函數(shù)在對象銷毀時釋放這些資源。這樣就確保了無論函數(shù)useResource如何退出(正常結(jié)束或因異常退出),資源都會被正確釋放。

應(yīng)用場景

RAII不僅限于內(nèi)存管理,還可以應(yīng)用于其他資源類型,如文件句柄、網(wǎng)絡(luò)套接字、數(shù)據(jù)庫連接等。標(biāo)準(zhǔn)庫中的智能指針(如std::unique_ptr、std::shared_ptr)、鎖機制(如std::lock_guard、std::unique_lock)都是RAII原則的實際應(yīng)用案例。通過使用這些工具,可以有效地減少資源管理錯誤,提高代碼的安全性和可靠性。

默認(rèn)拷貝構(gòu)造

  • 聲明形式:ClassName(const ClassName&)

  • 作用:通過已有對象初始化新對象,默認(rèn)執(zhí)行淺拷貝。

  • 生成條件:用戶未定義拷貝構(gòu)造函數(shù)。

  • 注意:若類包含指針或動態(tài)資源,需自定義深拷貝防止重復(fù)釋放。

class Person
{
public:
	Person()
	{

	}

	Person(const Person& person)
	{
		this->_age = person._age;
	}

	~Person()
	{

	}

	void GetAge()
	{
		std::cout << _age << std::endl;
	}
private:
	int _age;
};

int main()
{
	Person p;
	p.GetAge();
}

深拷貝和淺拷貝

class Stack
{
public:
	//初始化
	Stack()
	{
		_array = new int[20];
	}

	//默認(rèn)生成拷貝構(gòu)造

	//析構(gòu)
	~Stack()
	{
		delete[] _array;
	}
private:
	int* _array;
	size_t _size;
	size_t _capacity;
};

int main()
{
	Stack s1;

	Stack s2(s1);
}

這里我沒有寫實際的拷貝構(gòu)造函數(shù),這里s2調(diào)用的默認(rèn)的拷貝構(gòu)造,所以s2_array的地址就是s1中_array的地址,這就叫淺拷貝:

在這里插入圖片描述

這樣代碼就會有問題,因為一個地址會被析構(gòu)兩次:

在這里插入圖片描述

正確的方法應(yīng)該是給s2的array開辟一塊新的空間:

class Stack
{
public:
	//初始化
	Stack()
	{
		_array = new int[20];
	}

	Stack(const Stack& st)
	{
		_array = new int[10];
		_size = st._size;
		_capacity = st._capacity;
	}

	//析構(gòu)
	~Stack()
	{
		delete[] _array;
	}
private:
	int* _array;
	size_t _size;
	size_t _capacity;
};

int main()
{
	Stack s1;

	Stack s2(s1);
}

在這里插入圖片描述

這樣的拷貝我們稱為深拷貝,再次運行程序:

在這里插入圖片描述

默認(rèn)拷貝賦值運算符

  • 聲明形式:ClassName& operator=(const ClassName&)

  • 作用:將已有對象的值賦給另一個對象,默認(rèn)淺拷貝。

  • 生成條件:用戶未定義拷貝賦值運算符。

  • 注意:需處理自賦值問題,并在資源管理時實現(xiàn)深拷貝。

class Stack
{
public:
	//初始化
	Stack()
	{
		_array = new int[20];
	}

	Stack(const Stack& st)
	{
		_array = new int[10];
		_size = st._size;
		_capacity = st._capacity;
	}

	Stack& operator=(const Stack& st)
	{
		if (this != &st)
		{
			_array = new int[10];
			_size = st._size;
			_capacity = st._capacity;
		}

		return *this;

	}

	//析構(gòu)
	~Stack()
	{
		delete[] _array;
	}
private:
	int* _array;
	size_t _size;
	size_t _capacity;
};

int main()
{
	Stack s1;

	Stack s2;

	s2 = s1;
}

在這里插入圖片描述

移動構(gòu)造函數(shù)(C++11起)

  • 聲明形式:ClassName(ClassName&&)

  • 作用:通過右值引用“竊取”資源,避免深拷貝開銷。

  • 生成條件:用戶未定義拷貝操作、移動操作或析構(gòu)函數(shù)。

  • 注意:移動后源對象應(yīng)處于有效但未定義狀態(tài)(如空指針)。

class Stack
{
public:
	//初始化
	Stack()
	{
		_array = new int[20];
	}

	Stack(const Stack& st)
	{
		_array = new int[10];
		_size = st._size;
		_capacity = st._capacity;
	}

	Stack& operator=(const Stack& st)
	{
		if (this != &st)
		{
			_array = new int[10];
			_size = st._size;
			_capacity = st._capacity;
		}

		return *this;

	}

	void swap(Stack& st)
	{
		std::swap(_array, st._array);
		std::swap(_size, st._size);
		std::swap(_capacity, st._capacity);
	}

	//移動構(gòu)造函數(shù)
	Stack(Stack&& st):_array(nullptr), _size(0), _capacity(0)
	{
		swap(st);
	}

	//析構(gòu)
	~Stack()
	{
		delete[] _array;
	}
private:
	int* _array;
	size_t _size;
	size_t _capacity;
};

int main()
{
	Stack s1;

	Stack s2(std::move(s1));
}

在這里插入圖片描述

默認(rèn)移動賦值運算符(C++11起)

  • 聲明形式:ClassName& operator=(ClassName&&)

  • 作用:通過右值引用轉(zhuǎn)移資源所有權(quán)。

  • 生成條件:同移動構(gòu)造函數(shù)。

  • 注意:需正確處理自移動賦值。

class Stack
{
public:
	//初始化
	Stack()
	{
		_array = new int[20];
	}

	Stack(const Stack& st)
	{
		_array = new int[10];
		_size = st._size;
		_capacity = st._capacity;
	}

	Stack& operator=(const Stack& st)
	{
		if (this != &st)
		{
			_array = new int[10];
			_size = st._size;
			_capacity = st._capacity;
		}

		return *this;

	}

	void swap(Stack& st)
	{
		std::swap(_array, st._array);
		std::swap(_size, st._size);
		std::swap(_capacity, st._capacity);
	}

	//移動構(gòu)造函數(shù)
	Stack(Stack&& st):_array(nullptr), _size(0), _capacity(0)
	{
		swap(st);
	}

	//移動復(fù)制構(gòu)造
	Stack& operator=(Stack&& st)
	{
		swap(st);

		st._array = nullptr;
		st._size = 0;
		st._capacity = 0;

		return *this;
	}

	//析構(gòu)
	~Stack()
	{
		delete[] _array;
	}
private:
	int* _array;
	size_t _size;
	size_t _capacity;
};

int main()
{
	Stack s1;

	Stack s2;

	s2 = std::move(s1);
}

在C++中,前置++和后置++運算符可以通過成員函數(shù)或非成員函數(shù)的形式進行重載。兩者的主要區(qū)別在于參數(shù)列表和返回值:

  • 前置++:增加對象的值,并返回增加后的對象引用。
  • 后置++:首先保存當(dāng)前對象的狀態(tài),然后增加對象的值,最后返回之前保存的對象的副本。

取地址及const取地址操作符重載

在C++中,取地址操作符(&)和常量取地址操作符(const &)通常不需要顯式地重載,因為編譯器提供了默認(rèn)的實現(xiàn),它們分別返回對象或常量對象的內(nèi)存地址。然而,在某些特定情況下,你可能想要自定義這些操作符的行為。

取地址操作符重載

當(dāng)你重載取地址操作符時,你通常是為了改變其默認(rèn)行為,例如返回一個代理對象的地址而不是原始對象的地址。不過這種情況非常少見,大多數(shù)時候并不需要這樣做。

常量取地址操作符重載

類似地,重載常量版本的取地址操作符也是為了提供特定的行為,但同樣,這并不是常見的需求。

示例代碼

盡管不常見,這里還是給出如何重載這兩種操作符的基本示例:

#include <iostream>

class MyClass {
private:
    int value;
public:
    MyClass(int val) : value(val) {}

    // 重載取地址操作符
    int* operator&() {
        std::cout << "非const取地址操作符被調(diào)用" << std::endl;
        return &value;
    }

    // 重載const取地址操作符
    const int* operator&() const {
        std::cout << "const取地址操作符被調(diào)用" << std::endl;
        return &value;
    }
};

int main() {
    MyClass obj(10);
    const MyClass constObj(20);

    int* addr = &obj;       // 調(diào)用非const版本
    const int* constAddr = &constObj; // 調(diào)用const版本

    std::cout << "*addr: " << *addr << std::endl;
    std::cout << "*constAddr: " << *constAddr << std::endl;

    return 0;
}

輸出結(jié)果

非const取地址操作符被調(diào)用
const取地址操作符被調(diào)用
*addr: 10
*constAddr: 20

在這個例子中,我們?yōu)?code>MyClass類重載了取地址操作符和常量取地址操作符。當(dāng)通過非常量對象調(diào)用operator&()時,會調(diào)用非常量版本的操作符,并打印一條消息。而當(dāng)通過常量對象調(diào)用operator&()時,則調(diào)用常量版本的操作符,并打印另一條不同的消息。

注意事項

  • 謹(jǐn)慎使用:一般情況下,不需要也不建議重載這兩個操作符,除非有特別的需求。這是因為它們改變了標(biāo)準(zhǔn)語義,可能會導(dǎo)致混淆或者不可預(yù)期的行為。
  • 保持一致性:如果你決定重載這些操作符,請確保它們的行為符合邏輯且一致,避免引入錯誤。
  • 理解限制:需要注意的是,即使你重載了取地址操作符,也無法阻止使用內(nèi)置的取地址操作來獲取對象的實際地址。例如,&obj總是可以獲得obj的實際地址,除非你完全隱藏了對象的訪問方式。

總的來說,重載取地址操作符和常量取地址操作符是一種高級技巧,適用于特定場景下的特殊需求。在大多數(shù)日常編程任務(wù)中,這種重載是不必要的。

擴展:前置++和后置++重載

重載規(guī)則

  • 前置++只需要一個參數(shù)(即調(diào)用該運算符的對象本身),并且通常返回一個指向修改后的對象的引用。
  • 后置++需要兩個參數(shù):第一個是調(diào)用該運算符的對象本身,第二個是一個int類型的占位參數(shù),用于區(qū)分前置和后置形式。后置++返回的是操作前對象的一個副本(通常是通過值返回)。
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

class Count
{
public:
	//重載后置++
	Count operator++()
	{
		++_count;
		return *this;
	}

	//后置++
	Count operator++(int)
	{
		Count temp = *this;
		++_count;
		return temp;
	}

	int getCount() const {
		return _count;
	}
private:
	int _count = 0;
};

int main()
{
	Count myCounter;

	std::cout << "Initial count: " << myCounter.getCount() << std::endl;

	++myCounter; // 調(diào)用前置++
	std::cout << "After prefix increment: " << myCounter.getCount() << std::endl;

	Count d;
	d = myCounter++; // 調(diào)用后置++
	std::cout << "After postfix increment: " << d.getCount() << std::endl;

	return 0;
}

到此這篇關(guān)于C++六大默認(rèn)成員函數(shù)的實現(xiàn)的文章就介紹到這了,更多相關(guān)C++ 默認(rèn)成員函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • C語言實現(xiàn)萬年歷效果

    C語言實現(xiàn)萬年歷效果

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)萬年歷效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • C語言中輸入輸出流與緩沖區(qū)的深入講解

    C語言中輸入輸出流與緩沖區(qū)的深入講解

    一般情況下,由鍵盤輸入的字符并沒有直接送入程序,而是被存儲在一個緩沖區(qū)當(dāng)中。下面這篇文章主要給大家介紹了關(guān)于C語言中輸入輸出流與緩沖區(qū)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2018-09-09
  • C++圖像加載之libpng、FreeImage、stb_image詳解

    C++圖像加載之libpng、FreeImage、stb_image詳解

    libpng、FreeImage、stb_image都是圖像解析的開源庫,這篇文章主要為大家詳細介紹了這三者的使用方法,文中的示例代碼講解詳細,需要的可以參考一下
    2023-06-06
  • C語言 sizeof 函數(shù)詳情

    C語言 sizeof 函數(shù)詳情

    這篇文章主要介紹了C語言 sizeof 函數(shù),在 C 語言中,char 字符串也是一種非常重要的數(shù)據(jù)類型,我們除了使用 sizeof 函數(shù)獲取字符串長度之外,使用 sizeof 函數(shù)同樣也可以完成字符串長度的獲取,下面文章內(nèi)容具體描述該內(nèi)容,需要的朋友可以參考以下
    2021-10-10
  • 在C++項目中使用SQLite3數(shù)據(jù)庫的全過程

    在C++項目中使用SQLite3數(shù)據(jù)庫的全過程

    本文檔介紹如何在 C++ 項目中使用 SQLite3 數(shù)據(jù)庫,假設(shè)通過 vcpkg 安裝了 SQLite3,因本機為Windows環(huán)境,為方便,用了本機的Visual Studio 2022 創(chuàng)建cmake項目,需要的朋友可以參考下
    2025-11-11
  • Linux?C/C++實現(xiàn)顯示NIC流量統(tǒng)計信息

    Linux?C/C++實現(xiàn)顯示NIC流量統(tǒng)計信息

    NIC流量統(tǒng)計信息是由操作系統(tǒng)維護的,當(dāng)數(shù)據(jù)包通過NIC傳輸時,操作系統(tǒng)會更新相關(guān)的計數(shù)器,通過讀取這些計數(shù)器,我們可以獲得關(guān)于網(wǎng)絡(luò)流量的信息,下面我們就來學(xué)習(xí)一下如何通過C/C++實現(xiàn)顯示NIC流量統(tǒng)計信息吧
    2024-01-01
  • 詳解C++中的數(shù)據(jù)抽象

    詳解C++中的數(shù)據(jù)抽象

    這篇文章主要介紹了詳解C++中的數(shù)據(jù)抽象,數(shù)據(jù)抽象是指,只向外界提供關(guān)鍵信息,并隱藏其后臺的實現(xiàn)細節(jié),即只表現(xiàn)必要的信息而不呈現(xiàn)細節(jié),需要的朋友可以參考下
    2023-05-05
  • Qt實現(xiàn)密碼框

    Qt實現(xiàn)密碼框

    這篇文章主要為大家詳細介紹了Qt實現(xiàn)密碼框,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • sigsetjmp的用法總結(jié)

    sigsetjmp的用法總結(jié)

    sigsetjmp()會保存目前堆棧環(huán)境,然后將目前的地址作一個記號,而在程序其他地方調(diào)用siglongjmp()時便會直接跳到這個記號位置,然后還原堆棧,繼續(xù)程序的執(zhí)行
    2013-09-09
  • C++11中union的使用方法示例

    C++11中union的使用方法示例

    這篇文章主要給大家介紹了關(guān)于C++11中union的使用方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09

最新評論

清河县| 高阳县| 西峡县| 福安市| 哈巴河县| 灌南县| 吴桥县| 甘南县| 曲靖市| 沈阳市| 木里| 枣阳市| 滦平县| 渝中区| 台南县| 平泉县| 平顶山市| 黑水县| 乐清市| 宣威市| 桦甸市| 象州县| 灵武市| 康马县| 黔西| 古浪县| 湛江市| 宜章县| 新密市| 新沂市| 太谷县| 乌兰察布市| 江口县| 卫辉市| 云和县| 抚远县| 朔州市| 崇义县| 赫章县| 兴文县| 南丹县|