C++拷貝構(gòu)造函數(shù)中的陷阱
轉(zhuǎn)自微信公眾號(hào):CPP開(kāi)發(fā)前沿
拷貝構(gòu)造函數(shù)大家都比較熟悉,通俗講就是傳入一個(gè)對(duì)象,拷貝一份副本。
不過(guò)看似簡(jiǎn)單的東西,實(shí)際不注意的話(huà)就會(huì)產(chǎn)生問(wèn)題!
#include<iostream>
using namespace std;
class CExample
{
public:
int a,b,c;
char *str;
public:
//構(gòu)造函數(shù)
? ? CExample(int tb)
? ? {
? ? ? ? a = tb;
? ? ? ? b = tb+1;
? ? ? ? c = tb+2;
? ? ? ? str=(char *)malloc(sizeof(char)*10);
strcpy(str,"123456789");
cout<<"creat: "<<endl;
? ? }
?
//析構(gòu)函數(shù)
? ? ~CExample()
? ? {
cout<< "delete: "<<endl;
? ? }
void Show ()
{
cout<<a<<endl;
? ? }
//拷貝構(gòu)造
//CExample(const CExample& C)
//{
// ? ?str=(char *)malloc(sizeof(char)*10);
// ? ?strcpy(str,C.str);
// ? ?cout<<"copy"<<endl;
//}
};
//全局函數(shù),傳入的是對(duì)象
void g_Fun(CExample C)
{
? ? C.a=0;C.b=0;C.b=0;
strcpy(C.str,"aaabbbccc");
cout<<"test"<<endl;
}
int main()
{
CExample test(1);
cout<<"str:"<<test.str<<" a="<<test.a<<" b="<<test.b<<" c="<<test.c<<endl;
? ? g_Fun(test);//傳入對(duì)象
cout<<"str:"<<test.str<<" a="<<test.a<<" b="<<test.b<<" c="<<test.c<<endl;
? ? getchar();
return 0;
}
這個(gè)結(jié)果似乎出乎了我們的預(yù)料,作為形式參數(shù) test對(duì)象被修改了,同時(shí)是test.str的部分被修改了,test的整數(shù)成員變量沒(méi)有被修改!
咱們先了解一下系統(tǒng)默認(rèn)的拷貝構(gòu)造函數(shù),因?yàn)轭?lèi)中沒(méi)有寫(xiě)自己的拷貝構(gòu)造函數(shù),所以調(diào)用的是默認(rèn)的拷貝構(gòu)造函數(shù)。
Thinking in c++:對(duì)于簡(jiǎn)單結(jié)構(gòu),編譯器會(huì)自動(dòng)生成一個(gè)缺省的,就是位拷貝(bitcopy)。
對(duì)于比較復(fù)雜的類(lèi)型,編譯器就會(huì)自動(dòng)生成一個(gè)缺省的拷貝構(gòu)造函數(shù)。
class CExample
{
int a,b,c;
};這就是一個(gè)簡(jiǎn)單結(jié)構(gòu)的類(lèi),位拷貝,就是按對(duì)象在內(nèi)存中的二進(jìn)制進(jìn)行拷貝,對(duì)于不涉及指針等類(lèi)型的時(shí)候,位拷貝是比較不錯(cuò)的拷貝方法。
但是,要是一個(gè)類(lèi)中有指針類(lèi)型的時(shí)候,如:
class CExample
{
int a,b,c;
char *str;
};位拷貝就會(huì)把指針地址拷貝了一下,話(huà)句話(huà)說(shuō),這里只進(jìn)行了“淺拷貝”,一旦副本里涉及到指針的操作,必然就會(huì)影響到原始對(duì)象的成員變量,這就是導(dǎo)致,上面代碼中對(duì)象的整數(shù)變量沒(méi)被修改(對(duì)整數(shù)變量的位拷貝其實(shí)就是一種“深拷貝”),而str所指的對(duì)象被修改的原因。
那么該如何防止對(duì)副本的修改影響原始對(duì)象呢?
答案是用戶(hù)自定義拷貝構(gòu)造函數(shù)!
CExample(const CExample& C)
{
? ? a=C.a;b=C.b;c=C.b;
? ? str=(char *)malloc(sizeof(char)*10);
strcpy(str,C.str);
cout<<"copy"<<endl;
}
這樣就可以正確完成拷貝構(gòu)造的操作了。
總結(jié):對(duì)于簡(jiǎn)單的數(shù)據(jù)類(lèi)型,可以使用系統(tǒng)默認(rèn)的拷貝構(gòu)造函數(shù);但對(duì)于復(fù)雜的數(shù)據(jù)類(lèi)型(如指針),其實(shí)就是深拷貝和淺拷貝的區(qū)別!一般類(lèi)如果包含指針或引用成員,應(yīng)該遵守Rule of Three原則。
@24K純開(kāi)源 指出的三法則:
三法則(英語(yǔ):rule of three,the Law of The Big Three,The Big Three;三法則,三大定律)在 C++ 程序設(shè)計(jì)里,它是一個(gè)以設(shè)計(jì)的基本原則而制定的定律,三法則的要求在于,假如類(lèi)型有明顯地定義下列其中一個(gè)成員函數(shù),那么程序員必須連其他二個(gè)成員函數(shù)也一同編寫(xiě)至類(lèi)型內(nèi),亦即下列三個(gè)成員函數(shù)缺一不可。
析構(gòu)函數(shù)(Destructor)
復(fù)制構(gòu)造函數(shù)(copy constructor)
復(fù)制賦值運(yùn)算符(copy assignment operator)
到此這篇關(guān)于C++拷貝構(gòu)造函數(shù)中的陷阱的文章就介紹到這了,更多相關(guān)拷貝構(gòu)造函數(shù)陷阱內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)學(xué)生管理系統(tǒng)的源碼分享
這篇文章主要為大家詳細(xì)介紹了如何利用C語(yǔ)言實(shí)現(xiàn)學(xué)生管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07
簡(jiǎn)單總結(jié)C語(yǔ)言中的運(yùn)算符優(yōu)先級(jí)
這篇文章主要介紹了C語(yǔ)言中的運(yùn)算符優(yōu)先級(jí),文中簡(jiǎn)單總結(jié)了一些常用運(yùn)算符的優(yōu)先級(jí)順序以及記憶技巧,需要的朋友可以參考下2016-05-05
C語(yǔ)言新建臨時(shí)文件和臨時(shí)文件名的方法
這篇文章主要介紹了C語(yǔ)言新建臨時(shí)文件和臨時(shí)文件名的方法,分別是mkstemp()函數(shù)和mktemp()函數(shù)的使用,需要的朋友可以參考下2015-08-08
C語(yǔ)言fprintf()函數(shù)和fscanf()函數(shù)的具體使用
本文主要介紹了C語(yǔ)言fprintf()函數(shù)和fscanf()函數(shù)的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11
QT委托代理機(jī)制之Model?View?Delegate使用方法詳解
這篇文章主要介紹了QT委托代理機(jī)制之Model?View?Delegate的使用方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08
Java?C++?算法題解leetcode669修剪二叉搜索樹(shù)示例
這篇文章主要為大家介紹了Java?C++?算法題解leetcode669修剪二叉搜索樹(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09

