C++ 当类的构造函数中使用new关键字时,注意使用复制(拷贝)构造函数,进行深复制

所谓深复制,通俗的解释就是:不仅仅是复制数据的地址,更要复制数据本身
先来看一个不完善的类,如下:

#include<iostream>
#include<string>
using namespace std;
class StringBad
{
private:
	char *str;//指向字符串的指针
	int len;//当前字符串的长度
	static int num;//记录创建的对象数量
public:
    StringBad(const char*s);//自定义构造函数
    StringBad(const StringBad& st);//复制构造函数
	~StringBad();//析构函数
	StringBad & operator=(const StringBad &st);//赋值运算符重载函数
};

StringBad::StringBad(const char*s)//自定义构造函数
{
		len= strlen(s);
		str = new char[len + 1];//当类中包含了使用new初始化的指针成员,应该定义一个复制构造函数(深复制)
		strcpy(str, s);
		num++;
}

StringBad::~StringBad()//析构函数
{
		num--;
		delete[]str;   //析构函数中释放开辟的空间
};
int StringBad::num=0;

然后我们要清楚知道,程序什么时候调用复制(拷贝)构造函数通常有5种情况

①用已知对象作为实参,来初始化新对象

StringBad S1("Mike");
StringBad S2(S1);//此时会调用复制构造函数

②在创建对象的同时,用已知对象初始化。注意是同一时间

StringBad S1("Mike");
StringBad S2=S1;//在创建新对象S2的同时,进行初始化。这是最常见的,会调用复制构造函数的情况

** 需要区分:如果两个对象都已经存在,赋值的时候,调用的就是赋值运算符(重载)函数,如下

StringBad S1("Mike");
StringBad S2("Jerry");
S1=S2;//此时调用的运算符的重载函数,此时同样需要进行深复制

函数方面:
③将一个对象作为实参传递给一个非引用类型的形参

void Show(StringBad S){......};
StringBad S1("Mike");
Show(S1);//实参对象将会传进来,以赋值的方式传递给形参,此时就会调用复制构造函数

④调用一个返回类型为非引用类型的函数,返回一个对象

另外
⑤在使用stl容器时,进行push、insert操作时,会进行拷贝初始化

那么问题就来了,StringBad类的复制构造函数应该怎么写?
众所周知,系统自动生成的,类的默认构造函数仅仅是简单的赋值,如下

StringBad(StringBad &S)
{
      this->str=S.str;
      this->len=S.len;
      this->num=S.num;
}

不难看到,如此简单地将所有数据成员复制一遍,不仅没有把static类型变量数值更新,也没有把数据真正复制到新对象上来

所以,StringBad类正确的复制构造函数应该这样写

StringBad::StringBad(const StringBad&st)
{
     this->str=new char[strlen(st.str)+1];//开辟与原对象长度一样空间,并用this->str指向
     strcpy(this->str,st.str);//最关键一步,通过strcpy()函数进行数据的复制
     this->len=st.len;
     this->num++;//更新num变量数值
     cout<<"调用了复制构造函数"<<endl;
}

同样需要注意“深复制”的,还有运算符重载函数:

StringBad& StringBad::operator=(const StringBad &st)
{
     this->str=new char[strlen(st.str)+1];//开辟与原对象长度一样空间,并用this->str指向
     strcpy(this->str,st.str);//最关键一步,通过strcpy()函数进行数据的复制
     this->len=st.len;
     cout<<"调用了运算符重载函数"<<endl;
     return *this;//记得返回对象
     
}

主函数:

void main()
{
    StringBad S0("Mike");//已知对象S0
    StringBad S1("Jerry");//已知对象S1
    StringBad S2(S0);//第一次调用复制构造函数
    StringBad S3=S0;//第二次调用复制构造函数
    S1=S0;//调用运算符重载函数
}

运行结果如下:
在这里插入图片描述
总结:
在构造函数中使用new,应该特别注意以下几点:
①new和delete必须对应,特别是要在析构函数中使用delete释放空间
②应该定义一个复制构造函数,进行深复制
③应该定义一个赋值运算符重载函数,进行深复制,返回调用对象的引用

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值