# 题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数。
class CMyString
{
public:
CMyString(char* pData = nullptr);
CMyString(const CMyString& str);
~CMyString(void);
private:
char* m_pData;
};
## 注意点
1.*连续赋值*:函数返回实例自身的引用(*this);
2.*形参为常量引用*:const保证传入的实例不可修改,引用可以节省内存消耗,提高代码效率;
3.*赋值之前释放已有内存*:此为赋值操作,此前被赋值实例中的m_pData已经初始化(即使m_pData指向的是空字符串),为了避免内存泄漏,在分配新内存之前要释放自身已有的空间;
4.*自身不能进行赋值*:结合第3点,在赋值之前释放了已有内存。若自身赋值给自身,则赋值时将找不到相应的内存(被释放了),因此要先进行判断;
##知识总结
1.初始化时的赋值调用的是拷贝构造函数;非初始化时的赋值调用的是赋值运算符函数;
如果对象在申明的同时马上进行的初始化操作,则称之为拷贝运算;
如果对象在申明之后,在进行的赋值运算,我们称之为赋值运算
如:
CMyString str2=str1;//调用拷贝构造函数
CMyString str3(str1);//调用拷贝构造函数
CMyString str4;
str4=str1//调用赋值运算符函数
2.深拷贝与浅拷贝
- 浅拷贝:简单的地址赋值,在进行delete释放内存时可能会发生同一块内存的重复释放;
- 深拷贝:先new出新的内存,在新的内存地址进行内容赋值;
默认的拷贝构造函数和赋值运算符函数是以浅拷贝的方式进行的。
3.赋值运算符函数(返回左值的引用)
格式:
A A::operator=(A &a)
{ //……
return *this;
}
问题:返回自身就可实现连续赋值,为何要返回自身的引用?
-赋值返回引用
x = y = z 先执行y = z,返回y的引用,执行x = y
-赋值不返回引用
x = y = z 先执行y = z,返回用y初始化的临时对象(注意临时对象都是常对象),再执行x = y的临时对象(要求operator=(const X&) ),返回用x初始化的临时对象(此处要求拷贝构造函数必须为X(const X&) )。
即每返回一次临时对象时需要调用一次拷贝构造函数和一次析构函数。
*所以也并非必须返回引用,返回引用的好处既可以于赋值的原始语义已知,又可避免拷贝构造函数和析构函数的调用。*
4.使用strlen()是返回的长度是不包含'\0'的,如果要使用strcpy(str1,str2)进行复制时,
str1的长度应该要为strlen(str2)+1,即预留一个空字符位。
源代码:https://github.com/zhedahht/CodingInterviewChinese2/tree/master
#include<cstring>
#include<cstdio>
class CMyString
{
public:
CMyString(char* pData = nullptr);
CMyString(const CMyString& str);
~CMyString(void);
CMyString& operator = (const CMyString& str);
void Print();
private:
char* m_pData;
};
CMyString::CMyString(char *pData)
{
if(pData == nullptr)
{
m_pData = new char[1];
m_pData[0] = '\0';
}
else
{
int length = strlen(pData);
m_pData = new char[length + 1];
strcpy(m_pData, pData);
}
}
CMyString::CMyString(const CMyString &str)
{
int length = strlen(str.m_pData);
m_pData = new char[length + 1];
strcpy(m_pData, str.m_pData);
}
CMyString::~CMyString()
{
delete[] m_pData;
}
CMyString& CMyString::operator = (const CMyString& str)
{
if(this == &str)
return *this;
delete []m_pData;
m_pData = nullptr;
m_pData = new char[strlen(str.m_pData) + 1];
strcpy(m_pData, str.m_pData);
return *this;
}
// ====================测试代码====================
void CMyString::Print()
{
printf("%s", m_pData);
}
void Test1()
{
printf("Test1 begins:\n");
char* text = "Hello world";
CMyString str1(text);
CMyString str2;
str2 = str1;
printf("The expected result is: %s.\n", text);
printf("The actual result is: ");
str2.Print();
printf(".\n");
}
// 赋值给自己
void Test2()
{
printf("Test2 begins:\n");
char* text = "Hello world";
CMyString str1(text);
str1 = str1;
printf("The expected result is: %s.\n", text);
printf("The actual result is: ");
str1.Print();
printf(".\n");
}
// 连续赋值
void Test3()
{
printf("Test3 begins:\n");
char* text = "Hello world";
CMyString str1(text);
CMyString str2, str3;
str3 = str2 = str1;
printf("The expected result is: %s.\n", text);
printf("The actual result is: ");
str2.Print();
printf(".\n");
printf("The expected result is: %s.\n", text);
printf("The actual result is: ");
str3.Print();
printf(".\n");
}
int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
return 0;
}