• 《剑指offer》面试题1:为类CMyString添加赋值运算符函数——C++拷贝构造函数与赋值函数


    题中已给出CMyString的类定义,要求写赋值运算符函数。

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 
     5 class CMyString
     6 {
     7 public:
     8     CMyString(char* pdata = NULL);
     9     CMyString(const CMyString& rstring);
    10     CMyString& operator = (const CMyString& rstring);
    11     void Show();
    12     ~CMyString();
    13 private:
    14     char* m_pdata;
    15 };
    16 
    17 CMyString::CMyString(char* pdata) //这里不能写char* pdata=NULL,一般如果函数声明和定义分开,则默认参数值在声明时                      //写,定义时不用再写了
    18 {
    19     /*m_pdata = pdata; 不能直接这样赋值:如果这样赋值,则新创建的m_pdata和pdata指向同一内存,m_pdata的操作直接影
    20     影响pdata*/
    21 
    22     if(pdata == NULL)
    23     {
    24         m_pdata = NULL;
    25         return;
    26     }
    27     int len = strlen(pdata);
    28     m_pdata = new char[len + 1];
    29     strcpy(m_pdata,pdata);
    30 }
    31 CMyString::CMyString(const CMyString& rstring)
    32 {
    33     int len = strlen(rstring.m_pdata);  //这里可以访问rstring的私有成员m_pdata
    34     m_pdata = new char[len + 1];
    35     strcpy(m_pdata, rstring.m_pdata);
    36 }
    37 CMyString& CMyString::operator = (const CMyString& rstring)
    38 {
    39     if(this == &rstring)
    40         return *this;
    41     delete []m_pdata;
    42     m_pdata = NULL;
    43     m_pdata = new char[strlen(rstring.m_pdata)+1];
    44     strcpy(m_pdata,rstring.m_pdata);
    45 }
    46 CMyString::~CMyString()
    47 {
    48     delete []m_pdata;
    49 }
    50 void CMyString::Show()
    51 {
    52     cout<<m_pdata<<endl;
    53 }
    54 int main()
    55 {
    56     char* pa = "abcde";
    57     char* pb = "qperwdfaafda";
    58     CMyString a(pa);
    59     a.Show();
    60     CMyString b(pb);
    61     b.Show();
    62     CMyString c(b);
    63     c.Show();
    64     a = c;
    65     a.Show();
    66     return 0;
    67 }    

    关于拷贝构造函数:
    定义:
    拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。例如:类X的拷贝构造函数的形式为X(X& x)。

    调用情况:
    当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。也就是说,当类的 对象需要拷贝时,拷贝构造函数将会被调用。以下情况都会调用拷贝构造函数:
    (1)一个对象以值传递的方式传入函数体
    (2)一个对象以值传递的方式从函数返回
    (3)一个对象需要通过另外一个对象进行初始化。
    例如:

    String a(“hello”);
    String b(“world”);
    String c(a); //用已初始化过的a去初始化新对象c,调用拷贝构造函数
    c = b; // 调用了赋值函数

    拷贝构造函数中为什么可以调用参数的私有成员:
    成员访问控制符public、private、protected都是基于类而言的,如果一个类标记了private访问权限,其意思是——这个类以外的其他类(友元类除外)无法访问被private修饰的本类成员,但是本类自身是不受成员访问符限制的。
    class my;
    my类中有一个private的成员num,其意思是——成员num对于my类以外的其他类(友元类除外)都不可见(或不可访问),但my类自己并不受限于访问权限。
    拷贝构造函数的参数是同类的引用,属于“本类”的范围。

    关于赋值函数:
    赋值函数4步实现:
    首先注意传入的参数是const CMyString& rstring,常引用:
    为什么是引用:如果参数不是引用而是实例,则从形参到实参相当于用已有对象去初始化一个新对象,要调用复制构造函数,造成不必要开销。
    为什么是const:因为赋值函数内不会改变传入参数的状态,因此应该为传入的参数加上const。
    (1)检查自赋值:判断传入的参数和当前实例(*this)是否为同一个,如果是同一个则直接返回。没有这一步的后果:一旦传入的是自身,则在第二步会delete自己,一旦释放自己的内存,参数也被释放了(自杀后不能复制自己),因此找不到需要复制的内容了。
    (2)用delete 释放原有的内存资源。如果现在不释放,以后就没机会了,将造成内存泄露。
    (3)分配新的内存资源,并复制字符串。
    (4)返回本对象的引用:目的是为了实现stra = strb = strc这样的连续赋值,如果是void则不能实现连续赋值。另外返回引用而不是实例也是为了避免调用拷贝构造函数。

     参考:

    http://www.cnblogs.com/BlueTzar/articles/1223313.html  C++拷贝构造函数(深拷贝,浅拷贝)

    http://blog.chinaunix.net/uid-25808509-id-354211.html   C++ 拷贝构造函数 赋值构造函数 

  • 相关阅读:
    VUE中引入zTree
    如何获取别人提供的接口,获取他接口里面的数据。
    com.fasterxml.jackson.databind.exc.InvalidDefinitionException
    2.Elasticsearch环境安装配置
    1.Elasticsearch概述
    Java中如何操作Redis
    基于Redis实现分布式锁
    Mybatis插件--数据库读写分离
    Mybatis插件--自定义分页
    7. Mybatis日志
  • 原文地址:https://www.cnblogs.com/CnZyy/p/3263695.html
Copyright © 2020-2023  润新知