C++深度解析 经典问题解析三 --- 赋值操作符重载 和 拷贝构造函数,string类的疑问(35)

C++深度解析 经典问题解析三 --- 赋值操作符重载 和 拷贝构造函数,string类的疑问(35)

 

 

 

赋值操作符

什么时候需要重载赋值操作符?

编译器是否提供默认的赋值操作?

关于赋值的疑问:

编译器为每个类默认重载了赋值操作符

默认的赋值操作符仅完成浅拷贝

当需要进行深拷贝时必须重载赋值操作符

赋值操作符拷贝构造函数有相同的存在意义。

示例程序:(默认赋值操作符重载)

#include <iostream>
#include <string>

using namespace std;

class Test
{
    int *m_pointer;
public:
    Test()
    {
        m_pointer = NULL;
    }
    
    Test(int i)
    {
        //将指针指向堆空间一个int类型的数据(4个字节)
        m_pointer = new int(i);
    }
    
    //拷贝构造函数,深拷贝
    Test(const Test& obj)
    {
        //向堆空间申请一片内存,取出参数对象的pointer指针所指向的值,赋值新申请的内存空间
        m_pointer = new int(*obj.m_pointer);
    }
    
    //赋值操作符的重载,返回值类型是引用,为了连续赋值
    Test& operator = (const Test& obj)
    {
        //不能自己赋值给自己
        if (this != &obj)
        {
            delete m_pointer;
            //深拷贝
            m_pointer = new int(*obj.m_pointer);
        }
        
        return *this;
    } 
    
    void print()
    {
        //将m_pointer以十六进制输出
        cout << "m_pointer = " << hex << m_pointer << endl;
    }
    
    ~Test()
    {
        delete m_pointer;
    }
};

int main()
{
    //t1类部成员指针将指向堆空间里面的一块内存,并且将内存的值设置为1
    Test t1 = 1;
    //t2类部的指针指向空
    Test t2;

    t2 = t1;
    
    t1.print();
    t2.print();

    return 0;
}

结果如下:

分析:t1和t2所指向的堆空间是不一样,因为代码t2 = t1赋值操作,调用重载赋值操作符函数。赋值操作符和拷贝构造函数具有同等的意义。如果要进行深拷贝,必须提供赋值操作符的重载实现。但凡进行深拷贝,拷贝构造函数和赋值操作符实现都要自定义。

注意:赋值操作符重载函数,需要遵循下面四点

  1. 返回值类型是一个引用,为了连续赋值。
  2. 参数是const引用类型。
  3. 赋值操作,不能自己赋值给自己,当前this对象和参数对象的地址不同。
  4. 返回当前对象。
IntArray& operator = (const IntArray& obj)
{
	if (this != &obj)
	{
		
	}
	
	return *this;
}

 

 

 

编译器默认提供的函数

class Test
{
	//里面是由东西的!!不是空的
};

等价于:

class Test
{
public:
	Test();                        //无参数构造函数
	Test(const Test&);             //拷贝构造函数
	Test& operator=(const Test&);  //赋值操作符重载
	~Test();                       //析构函数
};

分析:编译器会为空的类,提供四个函数的实现:无参数构造函数,拷贝构造函数,赋值操作符重载,析构函数

 

 

 

关于string的疑问

示例程序一:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s = "12345";
    //c_str():返回字符指针,返回一个C语言方式的字符串,混合了C和C++的编程方式
    const char* p = s.c_str();
    
    cout << p << endl;
    
    //重新申请一块堆空间
    s.append("abcde"); // p 成为了野指针
    
    cout << p << endl;
    
    return 0;
}

结果如下:

分析:string的内部有一个字符指针m_cstr。在代码s.append("abced")中,将重新申请一片堆空间,并且把原来的12345和现在的abced一起赋值到新的堆空间里面。不要混合C和C++编程方式。

示例程序二:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    const char* p = "12345";
    string s = "";
    
    //将字符串对象内部的数据指针所指向的堆空间大小变为10个字节
    s.reserve(10);
    
    //不要使用 C语言中的方式操作 C++中的字符串
    for(int i = 0; i < 5; i++)
    {
        s[i] = p[i];
    }
    
    cout << s << endl;
   
    return 0;
}

结果如下:

分析:string类内部的数据指针m_cstr指向堆空间内存,还有一个表示长度的成员变量m_length。数据指针m_cstr指向堆空间的内容发现变化,但是字符串长度的成员变量m_length还是0。

示例程序三:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    const char* p = "12345";
    string s = "";
    
    s = p;
    
    cout << s << endl;
   
    return 0;
}

 

 

 

小结

在需要进行深拷贝的时候必须重载赋值操作符

赋值操作符拷贝构造函数有同等重要的意义。

string类通过一个数据空间保存字符数据。

string类通过一个成员变量保存当前爱你字符串的长度。

C++开发时尽量避开C语言中惯用的编程思想。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值