四、C++ 赋值运算符重载

C++ 赋值运算符重载

一、问题的提出

在C++中,虽然两个对象之间可以使用“=”号进行赋值,但这是不够的,因为有时候赋值运算符两边的类型可以不匹配,比如:

  1. 把一个 int类型变量 赋值给一个 Complex对象
  2. 把一个 char * 类型的字符串 赋值给一个 字符串对象

因此,需要重载赋值运算符”=”,赋值运算符”=”只能重载为成员函数。

二、程序示例

编写一个长度可变的字符串类String。

class String {
    private:
        char *str;
    public:
        String():str(NULL) { }
        const char * c_str() { 
            return this->str; 
        }
        char* operator= (const char* s);
        ~String();
};

char * String::operator = (const char * s){
    if(str) delete [] str;
    if(s) { //s不为NULL才会执行拷贝
        str = new char[strlen(s)+1];
        strcpy(str, s);
    }
    else
        str = NULL;
    return str;
}

String::~String( ) {
    if(str) delete [] str;
};

int main(){
    String s;
    s = “Good Luck” ;
    cout << s.c_str() << endl;
    return 0;
}

程序输出结果:

Good Luck

三、赋值运算符重载需要考虑的问题

在上面的程序示例中,有几个地方是没有考虑到的:

1、深复制和浅复制

String s1, s2;
s1 = "hello";
s2 = s1;

这种情况下,s1、s2都会指向同一片内存空间,如果s2的值修改,s1也会被改变,而且s1原本指向的内存空间没有被释放。

2、复制构造函数

String s1;
s1 = “hello”;
String s2(s1);  //相当于 s2 = “hello”

这种情况下,s2会调用String的复制构造函数,但程序中没有定义,因此编译不通过。

3、类型转换构造函数

String s4 = "hahaha";

和第2个问题类型,这种情况下,s2会调用String的类型转换构造函数,但程序中没有定义,因此编译不通过。

四、完善程序

经过修改,正确的程序代码应该是这样的:

class String
{
    private:
        char *str;
    public:
        String():str(NULL) { }
        String(const String &s); //复制构造函数
        String(const char *s);   //类型转换构造函数
        const char * c_str() { 
            return this->str; 
        }
        char* operator= (const char* s);  
        String& operator= (const String &s); //解决浅复制的问题
        ~String();
    friend void setupString(const char *str, String *s);
};

//这个方法中的语句在多个函数中都会用到,因此独立成一个方法
void setupString(const char *str, String *s)
{
    if(str){
        s->str = new char[sizeof(str)+1];
        strcpy(s->str, str);
    }else
        s = NULL; 
}

//复制构造函数
String::String(const String &s)
{
    setupString(s.str, this);
}

//类型转换构造函数
String::String(const char *s)
{
    setupString(s, this);
}

String::~String()
{
    if(str) delete[] str;
}

char* String::operator= (const char* s)
{
    if(str) delete[] str;
    setupString(s, this);

    return str;
}

String & String::operator= (const String &s)
{
    if(str == s.str) return *this;  //考虑s=s的情况
    if(str) delete[] str;
    setupString(s.str, this);

    return *this;
}

int main()
{
    String s1;
    s1 = " hello";

    String s2;
    s2 = s1;
    s2 = ", world";

    String s3 = s1;

    String s4 = "\nhahaha";

    cout<<s1.c_str()<<s2.c_str()<<s3.c_str()<<s4.c_str()<<endl;

    return 0;
}

输出:

hello, world hello
hahaha

五、小结

  1. 重载赋值运算符,使等号两边类型不一致时也能进行赋值操作

  2. 重载赋值运算符时,需要充分考虑浅复制、深复制的问题,返回值类型应为对象的引用

  3. 重载赋值运算符时,需要充分考虑复制构造函数、类型转换构造函数的问题

你可能感兴趣的:(C++,赋值运算符重载)