C++中值傳遞時(shí)觸發(fā)拷貝構(gòu)造函數(shù)的完整過(guò)程
當(dāng)函數(shù)的參數(shù)是類的對(duì)象(而非指針/引用)時(shí),調(diào)用函數(shù)傳遞參數(shù)的過(guò)程就是值傳遞,此時(shí)編譯器會(huì)自動(dòng)調(diào)用拷貝構(gòu)造函數(shù),創(chuàng)建一個(gè)實(shí)參的“副本”作為函數(shù)的形參。
一、值傳遞觸發(fā)拷貝構(gòu)造函數(shù)的完整過(guò)程
可以把這個(gè)過(guò)程想象成“復(fù)制粘貼”
1、你準(zhǔn)備把一個(gè)已存在的對(duì)象(實(shí)參)傳給函數(shù)
2、因?yàn)槭侵祩鬟f,函數(shù)不會(huì)直接使用原對(duì)象,而是需要一個(gè)"獨(dú)立的副本"
3、編譯器會(huì)調(diào)用該類的拷貝構(gòu)造函數(shù),用原對(duì)象(實(shí)參)為模板,創(chuàng)建一個(gè)新的對(duì)象(形參);
4、函數(shù)內(nèi)部操作的是這個(gè)“副本”,函數(shù)執(zhí)行完畢后,副本會(huì)被銷毀(調(diào)用析構(gòu)函數(shù))
5、原對(duì)象不受函數(shù)內(nèi)操作的影響
二、代碼示例
#include <iostream>
#include <string>
using namespace std;
class Person {
public:
string name;
// 帶參構(gòu)造函數(shù)
Person(string n) : name(n) {
cout << "[構(gòu)造] 創(chuàng)建對(duì)象:" << name << endl;
}
// 拷貝構(gòu)造函數(shù)(核心:值傳遞時(shí)會(huì)調(diào)用)
Person(const Person& other) {
this->name = other.name + "(副本)"; // 給副本加標(biāo)記,方便識(shí)別
cout << "[拷貝構(gòu)造] 為值傳遞創(chuàng)建副本:" << this->name << endl;
}
// 析構(gòu)函數(shù)
~Person() {
cout << "[析構(gòu)] 銷毀對(duì)象:" << name << endl;
}
// 成員函數(shù):修改名字(僅影響副本)
void changeName(string newName) {
this->name = newName;
cout << "[函數(shù)內(nèi)] 修改副本名字為:" << this->name << endl;
}
};
// 函數(shù)參數(shù)為值傳遞(Person對(duì)象,而非指針/引用)
void testValuePass(Person p) {
p.changeName("修改后的副本");
}
int main() {
// 1. 創(chuàng)建原對(duì)象
Person p1("原對(duì)象-張三");
cout << "------------------------" << endl;
// 2. 調(diào)用函數(shù),值傳遞參數(shù) → 觸發(fā)拷貝構(gòu)造
testValuePass(p1);
cout << "------------------------" << endl;
// 3. 查看原對(duì)象:未被修改
cout << "[主函數(shù)] 原對(duì)象名字:" << p1.name << endl;
return 0;
}
控制臺(tái)
[構(gòu)造] 創(chuàng)建對(duì)象:原對(duì)象-張三
------------------------
[拷貝構(gòu)造] 為值傳遞創(chuàng)建副本:原對(duì)象-張三(副本)
[函數(shù)內(nèi)] 修改副本名字為:修改后的副本
[析構(gòu)] 銷毀對(duì)象:修改后的副本
------------------------
[主函數(shù)] 原對(duì)象名字:原對(duì)象-張三
[析構(gòu)] 銷毀對(duì)象:原對(duì)象-張三三、關(guān)鍵細(xì)節(jié)拆解
1、觸發(fā)時(shí)機(jī)
執(zhí)行testValuePass(p1)時(shí),編譯器發(fā)現(xiàn)參數(shù)是值傳遞(Person p),立即調(diào)用Person(const Person& other);
拷貝構(gòu)造函數(shù)的參數(shù)other就是原對(duì)象p1,函數(shù)內(nèi)創(chuàng)建的p是p1的副本。
2、為什么必須是拷貝構(gòu)造?
如果沒(méi)有顯式定義拷貝構(gòu)造函數(shù),編譯器會(huì)生成默認(rèn)的淺拷貝構(gòu)造函數(shù),依然會(huì)觸發(fā)(只是沒(méi)有日志輸出);
只有參數(shù)是const 類名&的構(gòu)造函數(shù),才是拷貝構(gòu)造函數(shù),這是 C++ 的語(yǔ)法規(guī)則。
3、對(duì)比:避免拷貝構(gòu)造的方式
如果不想觸發(fā)拷貝構(gòu)造(提升性能,避免深拷貝開(kāi)銷),可以把參數(shù)改成引用傳遞
// 引用傳遞:直接操作原對(duì)象,不觸發(fā)拷貝構(gòu)造
void testRefPass(Person& p) {
p.changeName("修改原對(duì)象");
}
調(diào)用testRefPass(p1)時(shí),不會(huì)調(diào)用拷貝構(gòu)造函數(shù),函數(shù)內(nèi)修改的是原對(duì)象p1。四、常見(jiàn)誤區(qū)澄清
×誤區(qū):“值傳遞只是把對(duì)象的值復(fù)制過(guò)去,和拷貝構(gòu)造無(wú)關(guān)”;
√正解:C++ 中,類對(duì)象的 “值復(fù)制” 本質(zhì)就是通過(guò)拷貝構(gòu)造函數(shù)完成的,這是面向?qū)ο蟮暮诵囊?guī)則。
五、總結(jié)
1、觸發(fā)條件:函數(shù)參數(shù)為類對(duì)象(值傳遞)時(shí),編譯器會(huì)自動(dòng)調(diào)用拷貝構(gòu)造函數(shù),創(chuàng)建實(shí)參的副本作為形參。
2、過(guò)程本質(zhì):值傳遞的 “復(fù)制” = 拷貝構(gòu)造函數(shù)的調(diào)用 + 新對(duì)象(副本)的創(chuàng)建。
3、優(yōu)化建議:如果不需要修改原對(duì)象,用const 類名&(const 引用)傳遞參數(shù),既不觸發(fā)拷貝構(gòu)造,又能防止函數(shù)內(nèi)修改原對(duì)象。
到此這篇關(guān)于C++中值傳遞時(shí)觸發(fā)拷貝構(gòu)造函數(shù)的完整過(guò)程的文章就介紹到這了,更多相關(guān)c++值傳遞觸發(fā)拷貝構(gòu)造函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C++函數(shù)三種傳參形式(指針傳遞、引用傳遞、值傳遞)
- C++之值傳遞&指針傳遞&引用傳遞的示例詳解
- 解析C/C++值傳遞和址傳遞的區(qū)別
- C++小知識(shí):C/C++中不要按值傳遞數(shù)組
- java及C++中傳值傳遞、引用傳遞和指針?lè)绞降睦斫?/a>
- C++拷貝構(gòu)造函數(shù)和賦值運(yùn)算符重載詳解
- 詳解C++中構(gòu)造函數(shù),拷貝構(gòu)造函數(shù)和賦值函數(shù)的區(qū)別和實(shí)現(xiàn)
- 詳解C++ 編寫String 的構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、析構(gòu)函數(shù)和賦值函數(shù)
- C++中拷貝構(gòu)造函數(shù)的應(yīng)用詳解
相關(guān)文章
關(guān)于C語(yǔ)言 const 和 define 區(qū)別
這篇文章主要介紹了關(guān)于C語(yǔ)言 const 和 define 區(qū)別 的相關(guān)資料,需要的朋友可以參考下面文章內(nèi)容2021-09-09
ros項(xiàng)目調(diào)試:vscode下配置開(kāi)發(fā)ROS項(xiàng)目的詳細(xì)教程
這篇文章主要介紹了ros項(xiàng)目調(diào)試:vscode下配置開(kāi)發(fā)ROS項(xiàng)目,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Java?C++題解leetcode1598文件夾操作日志搜集器
這篇文章主要為大家介紹了Java?C++題解leetcode1598文件夾操作日志搜集器示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
你知道C語(yǔ)言函數(shù)調(diào)用常用的2種方式嗎
本篇博客會(huì)講解C語(yǔ)言函數(shù)調(diào)用的2種方式,分別是:傳值調(diào)用和傳址調(diào)用。這2種函數(shù)調(diào)用方式有什么區(qū)別呢?為什么會(huì)有不同的效果呢?分別有哪些用途呢?下面就來(lái)一一展開(kāi)2023-04-04
C++ Boost MultiIndex使用詳細(xì)介紹
Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱2022-11-11
C語(yǔ)言動(dòng)態(tài)內(nèi)存管理深入探討
動(dòng)態(tài)內(nèi)存是相對(duì)靜態(tài)內(nèi)存而言的。所謂動(dòng)態(tài)和靜態(tài)就是指內(nèi)存的分配方式。動(dòng)態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存,本文帶你深入探究C語(yǔ)言中動(dòng)態(tài)內(nèi)存的管理2022-06-06
淺談CMake配置OpenCV 時(shí)靜態(tài)鏈接與動(dòng)態(tài)鏈接的選擇
下面小編就為大家?guī)?lái)一篇淺談CMake配置OpenCV 時(shí)靜態(tài)鏈接與動(dòng)態(tài)鏈接的選擇。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01

