目录
15.1MyString实现
class MyString
{
private:
char* pstr;
public:
MyString(const char* p=nullptr)
{
if (p != nullptr)
{
int len = strlen(p) + 1;
pstr = new char[len];
strcpy_s(pstr, len, p);
}
else
{
pstr = new char[1];
*pstr = '\0';
}
cout << "Create MyString " << this << endl;
}
~MyString()
{
delete[]pstr;//在删除时不需要判空,因为delete和free内部存在判空
cout << "destroy MyString " << this << endl;
}
MyString(const MyString& s):pstr(nullptr)
{
int len = strlen(s.pstr) + 1;
pstr = new char[len];
strcpy_s(pstr, len, s.pstr);
cout << &s << " copy MyString " << this << endl;
}
MyString(MyString&& s)//移动拷贝构造
{
pstr = s.pstr;
s.pstr = nullptr;
cout << &s << " move copy create " << this << endl;
}
MyString& operator=(const MyString& s)
{
if (this != &s)
{
int len = strlen(s.pstr) + 1;
delete[]pstr;
pstr = new char[len];
strcpy_s(pstr, len, s.pstr);
cout << &s << " operator= " << this << endl;
}
return *this;
}
MyString& operator=(MyString&& s)//移动赋值运算符重载
{
if (this != &s)
{
delete[]pstr;
pstr = s.pstr;
s.pstr = nullptr;
cout << &s << " move operator= " << this << endl;
}
return *this;
}
void Print()const
{
if (pstr != nullptr)
{
cout << "string:" << pstr << endl;
}
}
};
15.2值、指针、引用与返回值
class Complex
{
private:
int real;
int image;
public:
Complex(int r=0,int i=0):real(r),image(i)
{
cout<<"Create Complex "<<this<<endl;
}
~Complex()
{
cout<<"Destroy Complex "<<this<<endl;
}
Complex(const Complex & x):real(x.real),image(x.image)
{
cout<<"Copy Complex "<<this<<endl;
}
Complex& operator=(const Complex& x)//赋值运算符重载函数
{
if(this==&x)return *this;//防止出现自赋值情况
real=x.real;
image=x.image;
cout<<this<<" operator= "<<&x<<endl;
return *this;
}
void Print()
{
cout << "real:" << real << " image:" << image << endl;
}
};
Complex get_a()
{
Complex tmp(2,3);
return tmp;
}
Complex& get_b()//错误的方式,但可以运行
{
Complex tmp(2,3);
return tmp;
}
Complex* get_c()//错误的方式,但可以运行
{
Complex tmp(2,3);
return &tmp;
}
int main()
{
Complex c1=get_a();
Complex& c2=get_b();
Complex* p=get_c();
c1.Print();
c2.Print();
p->Print();
return 0;
}
对于指针在函数结束时会拿到函数中局部变量的地址,当函数结束栈帧被系统回收释放,但指针依然指向被系统回收那块空间,读取里面存放的数据就是随机值。引用在底层也是指针,所以原因相同。
什么时候可以以引用或指针作为函数的返回值:
答:当对象的生存期不受函数影响(即函数结束该对象依然存在),就可以以引用或者指针返回其地址。比如:全局变量,静态变量,堆区变量等。
Complex& fun(Complex& x)//返回引用参数也可以
{
return x;
}
15.3运算符重载之返回值问题
class Complex
{
private:
int real;
int image;
public:
Complex(int r = 0, int i = 0) :real(r), image(i)
{
cout << "Create Complex " << this << endl;
}
~Complex()
{
cout << "Destroy Complex " << this << endl;
}
Complex(const Complex& x) :real(x.real), image(x.image)
{
cout << &x << " Copy Create Complex " << this << endl;
}
Complex& operator=(const Complex& x)
{
if (this != &x)
{
real = x.real;
image = x.image;
cout << &x << " operator= " << this << endl;
return *this;
}
}
void Print() const
{
cout << "Real: " << real << "Image: " << image <<" "<< this << endl;
}
//加法运算符重载函数有四种方法:
//方法一:返回值为值类型
Complex operator+(const Complex& c)const
{
Complex tmp(real + c.real, image + c.image);
return tmp;
}
//方法二:返回值为一引用类型,这种存在问题
Complex& operator+(const Complex& c)const
{
Complex tmp(real + c.real, image + c.image);
return tmp;
}
//方法三:以值的方式直接返回构造函数构造的不具名将亡值对象
Complex operator+(const Complex& c)const
{
return Complex(real + c.real, image + c.image);
}
//方法四:error,以引用的方式直接返回构造函数构造的不具名将亡值,无法编译通过
Complex& operator+(const Complex& c)const
{
return Complex(real + c.real, image + c.image);
//error C2440: “return”: 无法从“Complex”转换为“Complex &”
// message : 非常量引用只能绑定到左值
}
};
//主函数存在两种方案:
//第一种,定义c3对象之后再对c3进行赋值
int main()
{
Complex c1(1, 2), c2(2, 3);
Complex c3;
c3 = c1 + c2;
return 0;
}
//第二种,定义c3对象时并对c3进行赋值
int main()
{
Complex c1(1, 2), c2(2, 3);
Complex c3 = c1 + c2;
return 0;
}
15.3.1主函数第一种方案
使用方法一:
使用方法二:
使用方法三:
此处的无名对象就是将亡值
15.3.2主函数第二种方案
使用方法一:
使用方法二:
使用方法三:
15.4总结
第一种运算符重载方法在使用过程中会构造两个对象,一个是局部对象tmp,另一个是将亡值对象,多次的构造和销毁对象会造成程序效率降低;而方法二只构建一个tmp对象,并将其以引用形式返回,这样存在问题,就是不能将局部变量以引用或者指针的形式返回(在15.2中介绍)。但第三种方法在使用过程中就只构建一次对象。针对主函数的方案不同,第一种是先构造对象,再进行赋值,这样会调用调用构造函数和赋值运算符重载函数,第二种是构建并进行初始化,此处会直接调用拷贝构造函数