c++学习记录(十一)

赋值运算符'='的重载

  • 有时会希望赋值运算符两边的类型不匹配,比如把一个int类型变量赋值给一个complex对象,或者把一个char*类型的字符串赋值给一个字符串对象
  • 注意:赋值运算符=只能重载为成员函数
class String{
    private:
        char*str;
    public:
        String():str(new char[1]){str[0]=0;}
        const char* c_str(){return str;}
        String & operator = (const char*s);
        String::~String(){delete[] str;}
};
String & String::operator = (const char*s)
{    //重载使得obj="hello"能够成立
    delete[]str;
    str=new char[strlen(s)+1;
    strcpy(str,s);
    return *this;
}
int main()
{
    String s;
    s="Good Luck,";//等价于s.operator=("Good Luck,");
    cout<<s.c_str()<<endl;
    //String s2="hello";//如果这条语句不注释掉,编译会出错,这是初始化语句,调用的是构造函数
    s="shenzhou";//等价于s.operator=("shenzhou")
    cout<<s.c_str()<<endl;
    return 0;
}
  • 输出
    Good Luck,
    shenzhou

浅拷贝和深拷贝

- 问题

上述代码似乎没有什么问题,但是如果遇到了

    String s1,s2;
    s1="this";
    s2="that";
    s1=s2;

是有问题的

  • 这样的操作输出结果是对的,但是内部的动作却是把s1的str指向了s2的str指向的地方,对于后来的操作是大大不利的
  • 还有一点,如果s1对象消亡,则析构函数将释放s1.str指向的地方,则等价于释放了s2.str的指向地方,后面s2消亡时又会再释放一次s2.str的指向,不妥
  • 另外,如果执行s1="other",会导致s2.str指向的地方被delete

- 解决

  • 在class String里添加成员函数
    String & operator = (const String & s){
        delete[]str;
        str=new char[strlen(s.str)+1];
        strcpy(str,s.str);
        return *this;
}

看似没有问题了,实际上还有问题

- 问题

  • 对于
    String s;
    s="hello";
    s=s;

会有问题,一上来就被delete掉了

- 改进

String & operator = (const String &s){
    if(this==&s)
        return *this;
    delete[]str;
    str=new char[strlen(s.str)+1];
    strcpy(str,s.str);
    return *this;
}
  • 至此,问题基本解决

对operator=的返回值类型的讨论

  • 为什么不用void,String?
  • 因为对运算符重载的时候,好的风格是应该尽量保留运算符原本的特性
  • 如:
    a=b=c;//void不行,先进行b=c返回void,那么a=void
    (a=b)=c;//string不行,a=b返回一个String,变成String=c
原文地址:https://www.cnblogs.com/2002ljy/p/12272427.html