复制构造函数
《老九学堂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; // 需要写复制构造函数
}