復制構造函數
《老九學堂C++課程》《C++ primer》學習筆記。《老九學堂C++課程》詳情請到B站搜索《老九零基礎學編程C++入門》
-------------簡單的事情重復做,重復的事情用心做,用心的事情堅持做(老九君)---------------
包裝基本類,封裝一些算法。
需求說明:自定義String類,以簡化字符串的操作。
//main.cpp
#include <iostream>
#include "MyString.h"
using namespace std;
void TestString(){String str1("abc");//String str2="abcdefg"; // 尋找帶char * 參數的構造--轉換構造String str2(str1); // 如此指向同一個內存空間,需要復制構造函數cout << str1 << endl;cout << str2 << endl;cout << "對象之間的賦值"<< endl;str1 = str2; // 指向同一個地址,需要重載= 預算符// 為啥他把地址也給打出來了cout << str1 << endl;cout << str2 << endl;
}
int main() {//TestIntefer();TestString();return 0;
}
//MyString.h
//
// Created by 陳瑩瑩 on 2021/3/4.
// 自定義的字符串包裝類#ifndef CHAPTER12_MYSTRING_H
#define CHAPTER12_MYSTRING_H
#include <iostream>
#include <cstring>using namespace std;class String {
public:String();String(char * str);String(const String & str); // 參數是引用,所以是復制構造/拷貝構造~String();friend ostream & operator<<(ostream & out, const String & str);// 重載復制運算符,將數組中的每個元素都進行復制,而不是只復制數組指針const String & operator=(const String & str);
private:int m_length; // 字符串的實際長度-不包括\0char * m_value; // 實際存儲字符的字符數組,指針好用};#endif //CHAPTER12_MYSTRING_H
//MyString.cpp
//
// Created by 陳瑩瑩 on 2021/3/4.
//#include "MyString.h"
String::String() :m_length(0)
{this->m_value = new char[m_length + 1];this->m_value[0] = '\0';// 等價于// char * str = ""; 長度為0,但實際的字符數組中會存在唯一元素:\0--結束符號
}
String::String(char * str) {if(NULL == str){this->m_value = new char[m_length + 1];this->m_value[0] = '\0';return;}// 將傳入的字符串str的值賦給當前對象中的m_valuem_length = strlen(str); // 要復制字符串的長度m_value = new char[m_length + 1];strcpy(m_value, str);
}
String::String(const String & str){// 重載復制運算符,就一定要拷貝構造m_length= str.m_length;m_value = new char[m_length + 1];strcpy(m_value, str.m_value);
}
ostream & operator<<(ostream & out, const String & str)
{out << str.m_value<<"\n";// out << "m_value的長度:" << strlen(str.m_value);out << "m_value的長度:" << str.m_length;return out;
}
// 當重載賦值運算符,務必確定將一個對象中的所有數據都復制到另一對象中(特別是有指針時)
// 如果包含多個成員,那么每個成員都需要復制到內存對象中-深復制
// 如果一個類擁有指針類型的成員,那么大部分情況下都需要深賦值,才能將指針指向的內容復制一份出來,讓原來的額對象和新對象相互獨立
// 如果類的成員沒有指針,一般淺賦值即可
const String & String::operator=(const String & str){if(this == &str) return *this;delete[] m_value; // 首先要釋放字符串原始空間m_length = str.m_length;m_value = new char[m_length + 1];strcpy(m_value, str.m_value);return *this;
}
String::~String()
{// 析構時,釋放字符數組所指向的空間delete[] m_value;
}
情況1:不重載運算符,對象str1的內容直接復制到新對象str2中,對于沒有指針的簡單類來說,這就足夠了。當成員包含指針時,逐字節的復制將會把指針從一個對象復制給另一個對象,兩個指針就指向同一個內存
解決方案:重載賦值運算符號
String str1 = "愛吃新紅柿";
String str2;
str2 = str1;
情況2:使用一個類對象去初始化另一個對象,也會出現兩個指針指向同一塊內存地址的問題。
解決方案:復制構造函數(以對象為引用為參數的構造函數)
xxx::xxx(xxx & xxxptr);
xxx::xxx(const xxx & xxxptr); // const 保證復制過程中不會改變被復制對象
String str1("愛吃新紅柿");
String str2(str1);
str2 = str1;
需要使用復制構造函數的三種情況
- 當類對象被初始化為同一類的另一個對象時
- 當對象被作為參數傳遞給一個函數時
- 當函數返回一個對象時
String str = "abc";
test(str); // 按副本傳遞,默認調用復制構造,如果沒有實現復制構造的話,會調用淺復制(指向同一塊內存地址)
viod test(String str){}
String test(String str){ String str1 = "abc";return str1; // 需要寫復制構造函數
}