构造函数、析构函数、赋值函数是每个类最基本的的函数。每个类只有一个析构函数和一个赋值函数。但是有很多构造函数(一个为复制构造函数,其他为普通构造函数。对于一个类A,如果不编写上述四个函数,c++编译器将自动为A产生四个默认的函数,即:

A(void)                                    //默认无参数构造函数
    A(const A &a)                         //默认复制构造函数
    ~A(void);                                //默认的析构函数
    A & operator = (const A &a); //默认的赋值函数

既然能自动生成函数,为什么还需要自定义?原因之一是“默认的复制构造函数”和"默认的赋值函数“均采用”位拷贝“而非”值拷贝“

位拷贝  v.s.  值拷贝

为便于说明,以自定义String类为例,先定义类,而不去实现。
复制代码

#include <iostream>
using namespace std;

class String  
{
    public:
        String(void);
        String(const String &other);
        ~String(void);
        String & operator =(const String &other);
    private:
 
        char *m_data;
        int val;
};

复制代码

位拷贝拷贝的是地址,而值拷贝拷贝的是内容。

如果定义两个String对象a, b。当利用位拷贝时,a=b,其中的a.val=b.val;但是a.m_data=b.m_data就错了:a.m_data和b.m_data指向同一个区域。这样出现问题:

a.m_data原来的内存区域未释放,造成内存泄露
    a.m_data和b.m_data指向同一块区域,任何一方改变,会影响到另一方
    当对象释放时,b.m_data会释放掉两次

因此

当类中还有指针变量时,复制构造函数和赋值函数就隐含了错误。此时需要自己定义。

结论

有一种特别常见的情况需要自己定义复制控制函数:类具有指针哈函数。
    赋值操作符和复制构造函数可以看成一个单元,当需要其中一个时,我们几乎也肯定需要另一个
    三法则:如果类需要析构函数,则它也需要赋值操作符和复制构造函数

注意

如果没定义复制构造函数(别的不管),编译器会自动生成默认复制构造函数
    如果定义了其他构造函数(包括复制构造函数),编译器绝不会生成默认构造函数
    即使自己写了析构函数,编译器也会自动生成默认析构函数

因此此时如果写String s是错误的,因为定义了其他构造函数,就不会自动生成无参默认构造函数。

复制构造函数  v.s.  赋值函数
复制代码

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

class String  
{
    public:
        String(const char *str);
        String(const String &other);
        String & operator=(const String &other);
        ~String(void);
    private:
        char *m_data;
};

String::String(const char *str)
{
    cout << "自定义构造函数" << endl;
    if (str == NULL)
    {
        m_data = new char[1];
        *m_data = '\0';
    }
    else
    {
        int length = strlen(str);
        m_data = new char[length + 1];
        strcpy(m_data, str);
    }
}

String::String(const String &other)
{
    cout << "自定义拷贝构造函数" << endl;
    int length = strlen(other.m_data);
    m_data = new char[length + 1];
    strcpy(m_data, other.m_data);
}

String & String::operator=(const String &other)
{
    cout << "自定义赋值函数" << endl;

if (this == &other)
    {
        return *this;
    }
    else
    {
        delete [] m_data;
        int length = strlen(other.m_data);
        m_data = new char[length + 1];
        strcpy(m_data, other.m_data);
        return *this;
    }
}

String::~String(void)
{
    cout << "自定义析构函数" << endl;
    delete [] m_data;
}
int main()
{
    cout << "a(\"abc\")" << endl;
    String a("abc");

cout << "b(\"cde\")" << endl;
    String b("cde");
    
    cout << " d = a" << endl;
    String d = a;

cout << "c(b)" << endl;
    String c(b);

cout << "c = a" << endl;
    c = a;

cout << endl;
}

复制代码

执行结果

说明几点

1. 赋值函数中,上来比较 this == &other 是很必要的,因为防止自复制,这是很危险的,因为下面有delete []m_data,如果提前把m_data给释放了,指针已成野指针,再赋值就错了

2. 赋值函数中,接着要释放掉m_data,否则就没机会了(下边又有新指向了)

3. 拷贝构造函数是对象被创建时调用,赋值函数只能被已经存在了的对象调用

注意:String a("hello"); String b("world");  调用自定义构造函数

String c=a;调用拷贝构造函数,因为c一开始不存在,最好写成String c(a);

复制构造函数 与 赋值函数 的区别相关推荐

  1. C++11六大函数(构造函数,移动构造函数,移动赋值操作符,复制构造函数,赋值操作符,析构函数)

    转载自:http://blog.csdn.net/jofranks/article/details/17438955 版权声明:本文为博主原创文章,未经博主允许不得转载. 在C++中,有三大函数复制控 ...

  2. 拷贝构造函数和赋值函数的一些知识

    /*******************拷贝构造函数和赋值运算符重载有以下两个不同之处***************************/ 1.拷贝构造函数生成新的类对象,而赋值运算符不能. 2. ...

  3. 构造函数,拷贝构造函数,赋值函数

        C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法.下面就详细比较下三者之间的区别以及它们的具体实现 1.构造函数 构造函数是一种特殊的类成员函数,是当创建一个 ...

  4. 构造函数、拷贝构造函数、赋值函数和析构函数

    文章目录 一.构造函数 1.认识构造函数 2.初始化列表 二.拷贝构造函数 1.类对象的拷贝 2.浅拷贝和深拷贝 三.赋值函数 四.析构函数 1.认识析构函数 2.销毁,清理? 3.析构函数来阻止该类 ...

  5. 基础备忘:拷贝构造函数和赋值函数

    3.1 拷贝构造函数概述 现在我们来学习一种特殊的构造函数--拷贝构造函数. 对于普通类型的对象来说,他们之间的复制是很简单的,例如: int a = 10; int b =a; 自己定义的类的对象同 ...

  6. 拷贝构造函数和赋值函数(转)

    标签: 无标签 原帖地址:http://www.programfan.com/blog/article.asp?id=10944 现在我们来学习一种特殊的构造函数--拷贝构造函数. 对于普通类型的对象 ...

  7. 拷贝构造函数和赋值函数

    3.1 拷贝构造函数概述 现在我们来学习一种特殊的构造函数--拷贝构造函数. 对于普通类型的对象来说,他们之间的复制是很简单的,例如: int a = 10; int b =a; 自己定义的类的对象同 ...

  8. js 中的构造函数,构造函数作用,构造函数和普通函数的区别

    函数的定义方式: 1.声明式函数定义: function 函数名 (){}:这种定义方式,会将函数声明提升到该函数所在作用域的最开头,也是就无论你在这个函数的最小作用域的那儿使用这种方式声明的函数,在 ...

  9. C++——拷贝构造函数和赋值函数的注意点

    每个类只有一个赋值函数,由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数有些轻视. 1.如果不主动编写拷贝构造函数和赋值函数,编译器将以"位拷贝"的方式自动 ...

最新文章

  1. [JS] 闭包与内存泄漏
  2. (28)SpringBoot启动时的Banner设置【从零开始学Spring Boot】
  3. 谈谈Team Foundation Server Proxy
  4. 【机器学习】算法大全
  5. Scala变量介绍及入门示例
  6. 循环语句until和while
  7. 字节跳动EB级HDFS的七年演进与实践
  8. _WIN32_WCE有什么用
  9. 【C#桌面应用】第一节:使用C#开发桌面应用的准备
  10. Oracle中别名长度也限得这么死!!!
  11. WPF窗体隐藏鼠标光标的方法
  12. 架构师必备!分布式高并发都不会还做Java程序员
  13. SHELL中如何获得指定字符的位置及正确的截取动作
  14. linux 中两个文档怎么对比内容是否一致
  15. 【联盛德W806上手笔记】九、DMA
  16. 策略路由(Policy-Based-Route)
  17. Tips: Disk Performance On FreeBSD
  18. 石大师装机大师怎么重装系统
  19. 团队任务3每日立会(2018-10-24)
  20. 让你的发动机与NXP Kinetis汽车套件一起运行---凯利讯半导体

热门文章

  1. SVM学习(四):为何需要核函数
  2. Java 守护线程概述
  3. [Google Guava] 2.1-不可变集合
  4. Vue.js 单元测试
  5. TCP/UDP,SOCKET,HTTP,FTP协议简析
  6. Latex论文排版技巧再总结
  7. 【年度技术观点合集】计算机视觉,自然语言,机器学习…看看顶级科学家们怎么说
  8. 图像检索中BOW和LSH的一点理解
  9. 无监督特征学习——Unsupervised feature learning and deep learning
  10. 趣味编程:函数式链表的快速排序