C++学习笔记12:赋值运算符‘=’的重载

一世执手 提交于 2020-02-04 03:07:46

1 目的:希望赋值运算符两边的类型可以不匹配

    eg:将int类型变量赋值给一个Complex对象;或者吧一个char*类型的字符串赋值给一个字符串对象。

2 赋值运算符‘=’只能重载为成员函数
3 eg:(见本工程fuzhichongzai.cpp)

/**
 * 赋值运算符‘=’重载例子
 * */
#include <iostream>
#include <cstring>

using namespace std;

class String{
private:
    char* str;  // 私有成员变量  str是一个指针,用来指向动态分配的存储空间,字符串就放在动态分配的存储空间
public:

    // 构造函数  new一个字符数组,只有一个元素,使得指针str指向new出来的存储空间  相当于 char* str = new char[1];
    String()    //:str(new char[1])
    {
        str = new char[1];
        str[0] = 0; // 初始化后str指向一个空字符串
        cout << "调用无参构造函数" << endl;
    }

    const char* c_str()
    {
        return str;
    }

    // 对赋值运算符进行重载,接收的参数是 const char*  返回值为String&
    String& operator=(const char* s);

    // 析构函数
    ~String()
    {
        cout << "调用析构函数" << endl;
        delete[] str;
    }

};

String& String::operator= (const char *a) {
    // 重载‘=’使得obj = "hello"能够成立   obj是String对象,
    delete[] str;   // 删除String对象中为str成员变量分配的内存空间
    // 为str重新分配存储空间  加1的目的 存放\0
    str = new char[strlen(a) + 1];
    // 将a指针指向的内容copy到str指针指向的内容,此时String对象中str指向的内容就是a指向的内容
    strcpy(str, a);
    return *this;   // 返回这个已修改str指向内容的String对象的引用
}


int main()
{
   String s;
   s = "Good Luck,";    // 等价于 s.operator= ("Good Luck,");
   cout << s.c_str() << endl;
   // String s2 = "hello!"; //这条语句要是不注释就会出错 原因,该语句是初始化语句而不是赋值语句,初始化语句的话,要求该函数用构造函数初始化,构造函数参数必须是char 或const char型
   s = "Shenzhou 8!";   // 等价于s.operator = ("Shenzhou 8!");
   cout << s.c_str() << endl;
   return 0;
}

4 浅拷贝和深拷贝

    在3中的例子中,希望执行以下语句
    String S1, S2;
    S1 = "this";
    S2 = "that";
    S1 = S2;    // 希望达到的目的是S1里放置的字符串和S2中放置的字符串一样。
    对于S1 = S2;这条语句,如果使用的是原生的等号,则会产生问题
    问题如下
        S1  str ------> this\0      // 执行S1 = "this";   S1中str指向this\0
        S2  str ------> that\0      // 执行S2 = "that";   S2中str指向that\0
        // 执行 S1 = S2; 此时的等号没有经过重载
        // 则没有指针指向 this\0 存储空间,该空间没有机会被delete掉,造成内存垃圾
                        this\0
        // S1和S2中str都指向 that\0 存储空间
        // 如果S1对象消亡,析构函数将释放S1.str指向的空间,则S2消亡时还要释放一次,不妥。
        S1  str ------>
                        that\0
        S2  str ------>
    // 另外,如果再执行S1 = "other"; 会导致S2.str指向的地方被delete
    因此,解决以上问题的方法是在class String 里面添加成员函数 String& operator= (cosnt String& s);见3中例子。

还有需要改进的地方:

        如下语句: String s; s = "Hello";    s = s; 就会出现错误。
        改进方法:
            String& operator= (const String& s){
                // 判断当前对象与s是否为同一个  this指针代表的是个地址
                if(this == &s)
                    return *this;
                delete[] str;
                str = new char[strlen(s.str) + 1];
                strcpy(str, s.str);
                return *this;
            }

对operator=返回值的讨论

        void好不好?
        String好不好?
        为啥是String&?
        原因:对运算符进行重载的时候,好的风格应该尽量保留运算符原本的特性
        如果重载运算符返回void,由于b = c返回void  a = void错误,因此不能维持连等特性 a = b = c

        如果重载运算符返回String ,考虑(a = b) = c, 由于在C++中,赋值运算符的返回值是等号左边那个变量的引用,所以(a = b)的返回值是a的引用 将a的引用付给c,效果是a的值和c的值一样,跟b没有关系。

        考虑: a = b = c;      等价于 a.operator=(b.operator=(c));
              和(a = b) = c; 会修改a的值  等价于 (a.operator=(b)).operator=(c);
        在C++中,赋值运算符的返回值是等号左边那个变量的引用

目前String类还有什么问题?

        为String类编写复制构造函数时候,会面临和不重载的=同样的问题,用同样的方法处理
        String(String& s)
        {
            str = new char[strlen(s.str) + 1];
            strcpy(str, s.str);
        }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!