C++類與對象——拷貝構造與運算符重載

拷貝構造函數和賦值運算符重載就是C++類默認六個函數之二。

拷貝構造函數:

如果?個構造函數的第?個參數是自身類類型的引用,且任何額外的參數都有默認值,則此構造函數 也叫做拷貝構造函數,也就是說拷貝構造是?個特殊的構造函數。

拷貝構造函數的特點:

  1. 拷貝構造函數是構造函數的?個重載。
  2. 拷貝構造函數的第?個參數必須是類類型對象的引?,使?傳值?式編譯器直接報錯,因為語法邏輯上會引發?窮遞歸調?。 拷貝構造函數也可以多個參數,但是第?個參數必須是類類型對象的引用,后?的參數必須有缺省值。
  3. C++規定自定義類型對象進?拷貝?為必須調?拷貝構造,所以這?自定義類型傳值傳參和傳值返回都會調?拷貝構造完成。
  4. 若未顯式定義拷貝構造,編譯器會?成?動?成拷貝構造函數。?動?成的拷貝構造對內置類型成 員變量會完成值拷貝/淺拷貝(?個字節?個字節的拷?),對?定義類型成員變量會調?他的拷貝構造。
  5. 傳值返回會產??個臨時對象調?拷貝構造,傳引?返回,返回的是返回對象的別名(引?),沒有產?拷貝。但是如果返回對象是?個當前函數局部域的局部對象,函數結束就銷毀了,那么使?引?返回是有問題的,這時的引?相當于?個野引?,類似?個野指針?樣。傳引?返回可以減少拷貝,但是?定要確保返回對象,在當前函數結束后還在,才能?引?返回。

?這是正確的拷貝構造函數,如果參數不是引用的話,首先傳參的時候就要進行拷貝,會調用拷貝構造,拷貝構造有會調用拷貝構造,就這樣無窮遞歸下去了,所以編譯器會直接報錯。

深拷貝與淺拷貝?

?淺拷貝就是一個字節一個字節的拷貝,一般情況下也沒有什么問題,但是當有動態開辟的內存時,如果使用淺拷貝的方式寫拷貝構造,那么當拷貝構造了對象時就會導致內存重復釋放的問題。

上面的類中就是淺拷貝,會導致內存重復釋放,

兩個對象,aa,bb中的a指向的都是同一塊堆內存,析構的時候,bb先析構,把這塊內存釋放了,aa析構的時候又釋放了一次,這就會報錯。

解決辦法就是深拷貝:

?就只要把a也進行動態開辟內存就行了。

就和前面的析構函數,只要類的成員中有動態開辟的成員,就要自己寫析構,寫拷貝構造并且是深拷貝。 沒有動態開辟的成員,就可以不寫析構函數和拷貝構造函數,默認提供的就可以了。

賦值運算符重載:

運算符重載:

  1. 當運算符被?于類類型的對象時,C++語?允許我們通過運算符重載的形式指定新的含義。C++規定類類型對象使用運算符時,必須轉換成調?對應運算符重載,若沒有對應的運算符重載,則會編譯報錯。
  2. 運算符重載是具有特殊名字的函數,他的名字是由operator和后?要定義的運算符共同構成。和其他函數?樣,它也具有其返回類型和參數列表以及函數體。
  3. 重載運算符函數的參數個數和該運算符作?的運算對象數量?樣多。?元運算符有?個參數,?元運算符有兩個參數,?元運算符的左側運算對象傳給第?個參數,右側運算對象傳給第?個參數
  4. 如果?個重載運算符函數是成員函數,則它的第?個運算對象默認傳給隱式的this指針,因此運算符重載作為成員函數時,參數比運算對象少?個
  5. 運算符重載以后,其優先級和結合性與對應的內置類型運算符保持?致。
  6. 不能通過連接語法中沒有的符號來創建新的運算符,比如:operator@.
  7. 有五個運算符是不能重載的.* ,? ::? ?,sizeof ,? ?:?.
  8. 重載操作符?少有?個類類型參數,不能通過運算符重載改變內置類型對象的含義,如: int operator+(int x, int y)
  9. ?個類需要重載哪些運算符,是看哪些運算符重載后有意義,?如Date類重載operator-就有意 義,但是重載operator+就沒有意義。
  10. 重載++運算符時,有前置++和后置++,運算符重載函數名都是operator++,?法很好的區分。 C++規定,后置++重載時,增加?個int形參,跟前置++構成函數重載,方便區分。
  11. 重載 << 和 >> 時,需要重載為全局函數,因為重載為成員函數,this指針默認搶占了第?個形參位置,第?個形參位置是左側運算對象,調?時就變成了 對象 << cout ,不符合使用習慣和可讀性。重載為全局函數把ostream/istream放到第?個形參位置就可以了,第?個形參位置當類類型對象。

下面以Date類為例,展示運算符重載

?頭文件

#pragma once
#include<iostream>
using namespace std;class Date
{
public://友元函數friend ostream& operator<<(ostream& cout, const Date& d);// 獲取某年某月的天數int GetMonthDay(int year, int month){static int d[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };int day = d[month];if (month == 2 && (year % 4 == 0 && year % 100 != 0 || year % 400 == 0))day++;return day;}// 全缺省的構造函數Date(int year = 1900, int month = 1, int day = 1);// 拷貝構造函數// d2(d1)Date(const Date& d);// 賦值運算符重載// d2 = d3 -> d2.operator=(&d2, d3)Date& operator=(const Date& d);// 析構函數//~Date();// 日期+=天數Date& operator+=(int day);// 日期+天數Date operator+(int day);// 日期-天數Date operator-(int day);// 日期-=天數Date& operator-=(int day);// 前置++Date& operator++();// 后置++Date operator++(int);// 后置--Date operator--(int);// 前置--Date& operator--();// >運算符重載bool operator>(const Date& d);// ==運算符重載bool operator==(const Date& d);// >=運算符重載bool operator >= (const Date& d);// <運算符重載bool operator < (const Date& d);// <=運算符重載bool operator <= (const Date& d);// !=運算符重載bool operator != (const Date& d);// 日期-日期 返回天數int operator-(const Date& d);private:int _year;int _month;int _day;
};

源文件?

#include"test.h"ostream& operator<<(ostream& cout, const Date& d)
{cout << d._year << "/" << d._month << "/" << d._day << endl;return cout;
}//全缺省構造函數
Date::Date(int year, int month, int day)//聲明和定義只能一個寫缺省值
{_year = year;_month = month;_day = day;
}// 拷貝構造函數
Date::Date(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;
}// 賦值運算符重載
Date& Date::operator=(const Date& d)
{_year = d._year;_month = d._month;_day = d._day;return *this;
}// 日期+=天數
Date& Date::operator+=(int day)
{if (day < 0)return *this -= -day;_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month == 13){_year++;_month = 1;}}return *this;
}// 日期+天數
Date Date::operator+(int day)
{Date tmp = *this;tmp += day; // 復用 += 運算符return tmp;
}// 日期-天數
Date Date::operator-(int day)
{Date tmp = *this;tmp -= day; // 復用 -= 運算符return tmp;
}// 日期-=天數
Date& Date::operator-=(int day)
{if (day < 0)return *this += -day;_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetMonthDay(_year, _month);}return *this;
}// 前置++
Date& Date::operator++()
{*this += 1; // 復用+=return *this;
}// 后置++
Date Date::operator++(int)
{Date tmp = *this;*this += 1;//復用+=return tmp;
}// 后置--
Date Date::operator--(int)
{Date tmp = *this;*this -= 1;//復用-=return tmp;
}// 前置--
Date& Date::operator--()
{*this -= 1;//復用-=return *this;
}//大量的復用
// >運算符重載
bool Date::operator>(const Date& d)
{if (_year != d._year)return _year > d._year;if (_month != d._month)return _month > d._month;return _day > d._day;
}// ==運算符重載
bool Date::operator==(const Date& d)
{return (_year == d._year&& _month == d._month&& _day == d._day);
}// >=運算符重載
bool Date::operator >= (const Date& d)
{return (*this > d) || (*this == d);
}// <運算符重載
bool Date::operator < (const Date& d)
{return !(*this >= d);
}// <=運算符重載
bool Date::operator <= (const Date& d)
{return !(*this > d);
}// !=運算符重載
bool Date::operator != (const Date& d)
{return !(*this == d);
}// 日期-日期 返回天數
int Date::operator-(const Date& d)
{Date maxd = *this;Date mind = d;//防止改變原數據int n = 0;int flag = 1;if (*this < d){maxd = d;mind = *this;flag = -1;}while (mind != maxd){mind += 1;n++;}return n * flag;
}

補充:

	Date d2(2025, 3, 15);Date d3 = d2;

上面的d3雖然用的是 = ,但是,實際上是調用拷貝構造函數,不是賦值重載!?只有原本就已經實例化了的對象才能用賦值重載,沒有實例化的就是構造函數。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/72449.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/72449.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/72449.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

破碎的誓言

破碎的誓言 在秋風的呢喃中&#xff0c;落葉輕嘆&#xff0c; 昔日的誓言&#xff0c;如煙消散。 你的眼眸&#xff0c;曾是我星辰的指引&#xff0c; 如今&#xff0c;卻成了最深的迷惘。 欺騙的利刃&#xff0c;刺穿了信任的堡壘&#xff0c; 我的心&#xff0c;如裂開…

AD畫板學習

AD畫板 01 課程簡介及學習目標 &#xff08;1&#xff09;能熟練的新建項目文件、原理圖文件、PCB文件且修改文件名&#xff0c;并知道文件保存的位置&#xff1b; &#xff08;2&#xff09;會設置原理圖編輯器的工作環境&#xff0c;會自底向上繪制層次原理圖&#xff1b; …

Linux:進程程序替換

目錄 前言 一 進程程序替換的概念 二 進程程序替換的原理 三 為什么需要進行進程程序替換 四 如何進行進程程序替換 1. 進程替換函數 ? execl()函數 ?execv()函數 ?execlp()函數 ?execle()函數 ?execve()* 前言 一般情況下&#xff0c;對應的語言寫的程序只…

基于變分推理與 Best?of?N 策略的元 Prompt 自動生成與優化框架

摘要 本文提出了一種融合變分推理與 Best?of?N 策略的元 Prompt 自動生成與優化框架&#xff0c;通過高度參數化的模板、隨機擾動采樣及多指標評分機制&#xff0c;實現從初始提示生成到最終輸出的動態優化。同時&#xff0c;針對實際應用中對自適應參數調整、深層語義理解、…

Umi-OCR 全家桶

介紹&#xff1a; 下載 訪問官網地址 https://github.com/hiroi-sora/umi-ocrhttps://github.com/hiroi-sora/umi-ocr 點擊下載&#xff08;.exe 文件 安裝即可&#xff09; 桌面使用 安裝完畢后去安裝路徑下點擊 Umi-OCR.exe &#xff08;默認不會生成桌面的快捷方式&…

2023南京理工大學計算機復試上機真題

2023南京理工大學計算機復試上機真題 2023南京理工大學計算機復試機試真題 歷年南京理工大學計算機復試上機真題 在線評測&#xff1a;傳送門&#xff1a;pgcode.cn 括號匹配二 題目描述 苗苗今天剛剛學會使用括號&#xff0c;不過他分不清小括號&#xff0c;中括號&#…

Conda 常規用法指南

Conda 常規用法指南 1. Conda 簡介 Conda 是一個開源的包管理和環境管理系統&#xff0c;主要用于 Python 和其他編程語言的開發環境。它能夠方便地安裝、更新和管理依賴項&#xff0c;使得不同項目可以使用不同的 Python 版本和庫。 2. Conda 環境管理 2.1 創建新的環境 conda…

非零初始條件系統的傳遞函數分析

非零初始條件系統的傳遞函數分析 在傳遞函數的定義中&#xff0c;通常假設系統滿足零初始條件。然而在實際應用中&#xff0c;很多系統需要處理非零初始狀態。為了探討這一問題&#xff0c;我們以一個一階微分方程為例進行分析。 一、一階系統的分析 考慮以下一階微分方程&a…

centos7安裝時采用的默認分區(比如:/dev/sda3的對應掛載點是/),如何對系統擴容?

?非LVM分區擴容方案? 若 /dev/sda3 是?非LVM分區?且存儲重要數據&#xff0c;可通過 ?直接擴展分區容量? ?調整文件系統? 實現擴容&#xff0c;無需重建LVM或格式化分區?。以下是具體步驟&#xff1a; ?1. 擴展物理磁盤&#xff08;虛擬機場景&#xff09;? ?關…

Axios簡單說明,快速上手

Ajax&#xff1a;異步的JavaScript和XML 作用&#xff1a; 數據交換異步交互 Axios&#xff1a;就是對原生Ajax進行封裝&#xff0c;簡化書寫&#xff0c;快速開發 使用邏輯&#xff1a; 首先要安裝Axios&#xff0c;可以通過npm在項目中安裝&#xff1a; 打開命令行工具…

模型評估——acc、P、R、F值、交叉驗證、K折交叉驗證

模型評估&#xff1a;對預測函數地預測精度的評估。 多重回歸&#xff1a;涉及三個及其以上的變量的回歸問題。 評估模型的方法&#xff1a; 交叉驗證&#xff1a;將數據集分成測試集和訓練集&#xff0c;可以采用3&#xff1a;7或者2&#xff1a;8的比例方式進行劃分&#xff…

【Godot】Window類

&#xff08;參考自deepseek回答&#xff09; 在 Godot 引擎中&#xff0c;Window 是一個用于管理應用程序窗口的類。它是 Godot 4.0 引入的新特性&#xff0c;取代了舊版本中的 OS 類對窗口的管理功能。Window 提供了對窗口大小、位置、標題、模式等屬性的控制&#xff0c;使開…

JVM 2015/3/15

定義&#xff1a;Java Virtual Machine -java程序的運行環境&#xff08;java二進制字節碼的運行環境&#xff09; 好處&#xff1a; 一次編寫&#xff0c;到處運行 自動內存管理&#xff0c;垃圾回收 數組下標越界檢測 多態 比較&#xff1a;jvm/jre/jdk 常見的JVM&…

git submodule

git submodule git submodule 的作用是將一個 git 倉庫&#xff0c;最為另一個 git 倉庫的子模塊 比如 A 倉庫地址&#xff1a;gitgithub.com:xxxxxxx/A.git B 倉庫地址&#xff1a;gitgithub.com:xxxxxxx/B.git 一、克隆 A 倉庫 打開拉取的 A 項目根目錄 在 A 項目中添加 …

Compose 實踐與探索九 —— DrawModifier 解析

本篇講解 DrawModifier 的基本用法與代碼原理&#xff0c;介紹原理的目的在于可以判斷繪制與繪制的關系&#xff0c;繪制與布局的關系。知道達成某種繪制效果應該怎么寫&#xff0c;面對復雜的 Modifier 鏈時對效果有大致預判。 DrawModifier 管理繪制&#xff0c;需要以負責管…

華為手機助手輸入連接碼時光標亂跳

問題復現&#xff1a;輸入12345678&#xff0c;光標自動跳轉導致連接碼出現亂序情況。 千萬別試著找出規律&#xff0c;已試動態規律非大牛誤輕試 問題原因&#xff1a; 想啥呢&#xff1f;華哥的軟件又不是我開發我要Know Why干啥 我只需關心解決方案 &#xff08;可能時輸入…

《DeepSeek 開源 DeepGEMM:開啟AI計算新時代的密鑰》:此文為AI自動生成

《DeepSeek 開源 DeepGEMM&#xff1a;開啟AI計算新時代的密鑰》&#xff1a;此文為AI自動生成 引言&#xff1a;AI 計算的新曙光 在當今科技飛速發展的時代&#xff0c;人工智能&#xff08;AI&#xff09;無疑是最為耀眼的領域之一。從語音助手到自動駕駛&#xff0c;從圖像…

Windows 11 安裝Docker Desktop環境

1、確認CPU開啟虛擬化 打開任務管理器&#xff0c;切換到“性能”選項卡&#xff0c;查看 CPU 信息。若“虛擬化”狀態顯示為“已啟用”&#xff0c;則表示虛擬化已開啟&#xff1b;若顯示為“已禁用”&#xff0c;則需要在啟動時進入 BIOS 開啟虛擬化設置&#xff08;若顯示已…

STM32如何精準控制步進電機?

在工業自動化、機器人控制等場合&#xff0c;步進電機以其高精度、開環控制的特性得到了廣泛應用。而在嵌入式系統中&#xff0c;使用STM32進行步進電機的精確控制&#xff0c;已成為開發者的首選方案之一。 本文將從嵌入式開發者的角度&#xff0c;深入探討如何基于STM32 MCU…

【 <一> 煉丹初探:JavaWeb 的起源與基礎】之 JavaWeb 項目的部署:從開發環境到生產環境

<前文回顧> 點擊此處查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、開發環境…