C++的拷贝构造函数、operator=运算符重载,深拷贝和浅拷贝、explicit关键字
1、在C++編碼過程中,類的創建十分頻繁。
簡單的功能,當然不用考慮太多,但是從進一步深刻理解C++的內涵,類的結構和用法,編寫更好的代碼的角度去考慮,我們就需要用到標題所提到的這些內容。
最近,在看單例模式,覺得十分有趣,然而如果想要掌握單例模式,就必須掌握這些內容。下面是我的一些學習總結,參考了很多博客內容。文末將注明出處。
2、先上代碼
// testSingleMode.cpp : 定義控制臺應用程序的入口點。 // #include "stdafx.h" #include <iostream>using namespace std;class Complex { private:double m_real;double m_imag;public:Complex(void){m_real = 0.0;m_imag = 0.0;}Complex(double real, double imag){m_real = real;m_imag = imag;}Complex(const Complex & c){ //這里就是最經典的拷貝構造函數了m_real = c.m_real;m_imag = c.m_imag;}Complex &operator = (const Complex &rhs){ //這里就是最經典的operator=操作符重載了if (this == &rhs){return *this;}this->m_real = rhs.m_real;this->m_imag = rhs.m_imag;return *this;}explicit Complex::Complex(double r){ //explicit的用法,只適用于1個參數的情況m_real = r;m_imag = 0.0;}};int main() {Complex c1, c2; //調用 第15行 默認無參數的構造函數Complex c3(1.0, 2.5); //調用 第20行 具有2個形參的構造函數//Complex c3 = Complex(1.0, 2.5); //和上一行是一個意思,所以這個注釋了c1 = c3; //調用 第30行 重載operator=運算符c2 = c3; //調用 第30行 重載operator=運算符//c2 = 5.2; //隱式轉換,需要去掉41行的explicit關鍵字,才可編譯通過Complex c5(c2); //調用 第25行 拷貝構造函數Complex c4 = c2; //調用 第25行 拷貝構造函數getchar();return 0; }-注1:explicit 只適用于構造函數只含有1個參數的情況,加上這個關鍵字,意味著不支持構造函數隱式轉換,可以避免一些誤解。如果去掉這個關鍵字,那么代碼里面的:c2 = 5.2 ; 就是可以執行的了。
-注2:為什么函數中可以直接訪問對象c的私有成員?
答:(網上)因為拷貝構造函數是放在本身這個類里的,而類中的函數可以訪問這個類的對象的所有成員,當然包括私有成員了。
3、上面代碼的注釋,已經是非常的清楚了
自定義拷貝構造函數是一種良好的編程風格,它可以阻止編譯器形成默認的拷貝構造函數,防止出錯。
淺拷貝:如果自己不寫拷貝構造函數,系統會默認生成一個,而系統的拷貝構造函數是淺拷貝。
深拷貝:自己寫一個拷貝構造函數,系統就不會產生了默認的構造函數了。自己寫的這個拷貝構造函數,當然會有開辟空間的動作,所以是深拷貝。也就是說,如果生成類的實例的時候,調用了自己寫的拷貝構造函數,那么在內存空間上,必然是會開辟新的空間,而不用擔心只是一個指針。很多時候,我們希望得到的類的實例是各自獨立的,各有各的空間。如果希望得到指針,那就不用操心這么多。
在某些狀況下,類內成員變量需要動態開辟堆內存,如果實行淺拷貝,也就是把對象里的值完全復制給另一個對象,如A=B。這時,如果B中有一個成員變量指針已經申請了內存,那A中的那個成員變量也指向同一塊內存。這就出現了問題:當B把內存釋放了(如:析構),這時A內的指針就是野指針了,出現運行錯誤。
4、總結
(1)深拷貝:如果一個類擁有資源,當這個類的對象發生復制過程的時候,資源重新分配,這個過程就是深拷貝。反之,沒有重新分配資源,就是淺拷貝。
(2)什么時候用到拷貝構造函數
a.一個對象以值傳遞的方式傳入函數體;
b.一個對象以值傳遞的方式從函數返回;
c.一個對象需要通過另外一個對象進行初始化。
(3)深拷貝好還是淺拷貝好?
如果實行錢拷貝,也就是把對象里的值完全復制給另一個對象,如A=B。這時,如果B中有一個成員變量指針已經申請了內存,那A中的那個成員變量也指向同一塊內存。這就出現了問題:當B把內存釋放了(如:析構),這時A內的指針就是野指針了,出現運行錯誤。
(4)代碼例子2
#include "stdafx.h" #include <iostream> #include <string.h> #include <stdio.h> #include <stdlib.h> using namespace std;class Person { public:// 構造函數Person(char * pN){cout << "一般構造函數被調用 !\n";m_pName = new char[strlen(pN) + 1];//在堆中開辟一個內存塊存放pN所指的字符串if (m_pName != NULL){//如果m_pName不是空指針,則把形參指針pN所指的字符串復制給它strcpy_s(m_pName, strlen(pN) + 1, pN);}}// 下面自己設計復制構造函數,實現“深拷貝”,即不讓指針指向同一地址,而是重新申請一塊內存給新的對象的指針數據成員Person(Person & chs){cout << "拷貝構造函數被調用 !\n";// 用運算符new為新對象的指針數據成員分配空間m_pName = new char[strlen(chs.m_pName) + 1];if (m_pName){// 復制內容strcpy_s(m_pName, strlen(chs.m_pName) + 1, chs.m_pName);}// 則新創建的對象的m_pName與原對象chs的m_pName不再指向同一地址了} 系統創建的默認復制構造函數,只做位模式拷貝//Person(Person & p)//{// //使兩個字符串指針指向同一地址位置 // m_pName = p.m_pName;//}~Person(){delete m_pName;}void getName(){cout << m_pName << endl;}private:char * m_pName; };void main() {Person man("lujun");man.getName();Person woman(man);woman.getName();getchar(); }程序運行環境: VS2013
輸出結果:
=====
原文地址:https://blog.csdn.net/shine_journey/article/details/53081523
總結
以上是生活随笔為你收集整理的C++的拷贝构造函数、operator=运算符重载,深拷贝和浅拷贝、explicit关键字的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++拷贝构造函数(深拷贝与浅拷贝)
- 下一篇: Qt之创建并使用共享库