C++big three(构造函数、拷贝构造函数,拷贝赋值函数)

       一个类中只要带有指针类型的成员,就必须自己写出big three(构造函数、拷贝构造函数,拷贝赋值函数),如果没有指针类型的成员,大部分情况下可以用默认的。

       字符串类是一个经典的例子:

#ifndef __MYSTRING__
#define __MYSTRING__

#include <cstring>
#include <iostream>
using namespace std;

class String
{
public:                                 
   String(const char* cstr=0);  //构造函数,加const表示不修改*cstr的值                   
   String(const String& str);   //拷贝构造函数,加const表示不修改str指向的值,用&只占用4个字节的内存                 
   String& operator=(const String& str);   //拷贝赋值函数,加const表示不修改str指向的值,用&只占用4个字节的内存
   ~String();                                    
   char* get_c_str() const { return m_data; }
private:
   char* m_data;
};

inline
String::String(const char* cstr)
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   
      m_data = new char[1];
      *m_data = '\0';
   }
}

inline
String::~String()
{
   delete[] m_data;  //由于构造函数是new了一个数组,所以析构函数也需要使用delete []
}

//返回值为String&类型,&表示要赋值的目的端已经存在,即s1 = s2; s1已存在
//并且有时候会连续赋值,s1 = s2 = s3; 所以需要返回值为String&类型
inline
String& String::operator=(const String& str)
{
   if (this == &str)  //检测自我赋值,这一步必须有,本行的&str和形参的&str意义不一样。如果s1 = s2;则形参&str == s2,本行&str == &s2
      return *this;

   delete[] m_data;
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
   return *this;
}

inline
String::String(const String& str)
{
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
}


//输出字符串操作符重载,不能是一个成员函数,否则使用的时候方向要相反,即需要这样用 s1 << cout
ostream& operator<<(ostream& os, const String& str)
{
   os << str.get_c_str();
   return os;
}

#endif

1.构造函数、析构函数和拷贝构造函数

inline
String::String(const char* cstr)  //构造函数
{
   if (cstr) {
      m_data = new char[strlen(cstr)+1];
      strcpy(m_data, cstr);
   }
   else {   
      m_data = new char[1];
      *m_data = '\0';
   }
}
inline
String::~String()  /析构函数
{
   delete[] m_data;  //由于构造函数是new了一个数组,所以析构函数也需要使用delete []
}
inline
String::String(const String& str)  //拷贝构造函数
{
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
}

       根据代码规范,不超过10行的函数可以定义为内联函数,所以在构造和析构函数前都加了inline,上面构造函数超过了10行,但是内联不内联是由编译器决定的,所以加上inline也没啥毛病。
       构造函数中,如果传入的参数有效的话则new一个strlen(cstr)+1大小的数组给成员变量,并将参数拷贝到成员变量中;
       如果传入的参数无效,则将’\0’传给成员变量,当然,也需要new一个字节的空间来保存。
       构造函数的使用:

  String s1();  //参数无效 
  String s2("world");  //参数有效

       对于析构函数,由于构造函数是new了一个数组,所以析构函数也需要使用delete []。

       拷贝构造函数的参数类型就是类的类型,初始化步骤如代码所示。
       拷贝构造函数的使用:

String s2("world");
String s3(s2);

2.拷贝赋值函数

//返回值为String&类型,&表示要赋值的目的端已经存在,即s1 = s2; s1已存在
//并且有时候会连续赋值,s1 = s2 = s3; 所以需要返回值为String&类型
inline
String& String::operator=(const String& str)
{
   if (this == &str)  //检测自我赋值,这一步必须有,本行的&str和形参的&str意义不一样。如果s1 = s2;则形参&str == s2,本行&str == &s2
      return *this;

   delete[] m_data;
   m_data = new char[ strlen(str.m_data) + 1 ];
   strcpy(m_data, str.m_data);
   return *this;
}

       ①拷贝赋值函数的返回值类型应是by reference(传引用),因为拷贝赋值函数是将一个对象赋值给另一个对象,即要复制的目的端已经存在,所以可以用引用;还有一个原因是调用拷贝赋值函数是有可能是连续赋值的,如s1 = s2 = s3; ,这也需要返回值类型为引用才可以。
       ②拷贝赋值函数必须要有检测自我赋值这一步,检测自我赋值一个好处是当是自我赋值时后面的几步不需要再执行,从而节省了时间。另一个必要原因就是如果没有检测自我赋值这一步,并且遇到自我赋值时,代码逻辑会出错。
构造函数在赋值前会delete自己的成员变量,如果是自我赋值的话,会清空当前对象的值,后面赋值时对象已经被delete了,所以对象中保存的内容已经不能确定是什么了。

关于返回值类型必须使用值传递的函数的问题

       如下面的程序:

class complex
{
public:
  complex (double r = 0, double i = 0): re (r), im (i) { }
  double real () const { return re; }   //加const表示不会改变数据内容,尽量加上const
  double imag () const { return im; }
private:
  double re, im;
};

inline double
imag (const complex& x)
{
  return x.imag ();
}

inline double
real (const complex& x)
{
  return x.real ();
}

inline complex
operator + (const complex& x, const complex& y)  //返回值不能用by reference,因为如果是c1 + c2;这一句执行完后c1 + c2的值在函数结束后就被释放了,
                                                 //如果用by reference,会返回错误的东西
{
  return complex (real (x) + real (y), imag (x) + imag (y));
}

       上面的“+”操作符重载函数的返回值就必须使用值传递,因为当函数返回后,函数中的变量就会随着函数返回,其生命周期也就随之结束,如果返回类型使用引用的话,那么引用指向的内存也是不存在的,所以这种函数的返回类型不能使用引用传递。
       注:上面的“+”操作符重载函数应该有三个,此处只写了一个。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值