C++中的拷贝控制操作

简介: C++中的拷贝控制操作

31.jpg

1.拷贝构造函数 vs 赋值运算符重载


      当我们定义一个类时,会显式或隐式地指定了此类的对象在拷贝、赋值和销毁时做什么。一个类通过定义三种特殊的成员函数来控制这些操作,分别是拷贝构造函数、赋值运算符和析构函数。拷贝控制操作:拷贝构造函数被用来以同类型对象初始化自我对象,赋值运算符重载被用来从另一个同类型对象中拷贝其值到自我对象中析构函数定义了此类型的对象销毁时做什么。


注意:如果一个新对象被定义,一定会有个构造函数被调用,不可能调用赋值运算符重载如果没有新的对象被定义,就不会有构造函数被调用,那么就会调用赋值运算符重载


2.三/五法则

由于拷贝控制操作是由三个特殊的成员函数来完成的,所以称此为“C++三法则”。在较新的C++11标准中,为了支持移动语义,又增加了移动构造函数和移动赋值运算符,这样共有五个特殊的成员函数,所以又称为“C++五法则”。也就是说,“三法则”是针对较旧的C++89标准说的,“五法则”是针对较新的C++11标准说的。为了统一称呼,人们把它称为“C++ 三/五法则”。


3.实例演示


1#include <iostream>
  2#include <cstdlib>
  3#include <cstring>
  4
  5using namespace std;
  6
  7
  8class Array
  9{
 10public:
 11    Array(int len);
 12    Array(const Array &arr); // 拷贝构造函数
 13    ~Array();
 14
 15public:
 16    int operator[](int i) const { return m_p[i]; } // 以常成员函数(只读)形式重载[]运算符
 17    int &operator[](int i) { return m_p[i]; }      // 获取元素(写入)
 18    Array &operator=(const Array &arr);            // 重载赋值运算符!!!operator=()的形参类型是const Array &,这样不但能够避免在传参时调用拷贝构造函数,还能够同时接收const类型和非const类型的实参
 19    int length() const { return m_len; }
 20    void show();
 21
 22private:
 23    int m_len;
 24    int *m_p;
 25};
 26
 27// 构造函数的定义
 28Array::Array(int len) : m_len(len)
 29{
 30    m_p = (int *)calloc(len, sizeof(int)); // 动态分配内存空间,使得指针m_p指向新分配的内存空间
 31}
 32// 拷贝构造函数的定义
 33Array::Array(const Array &arr)
 34{
 35    this->m_len = arr.m_len;
 36    this->m_p = (int *)calloc(this->m_len, sizeof(int));
 37    memcpy(this->m_p, arr.m_p, m_len * sizeof(int));
 38}
 39
 40Array::~Array()
 41{
 42    free(m_p);
 43}
 44// 重载赋值运算符
 45Array &Array::operator=(const Array &arr)
 46{ // operator=()的返回值类型是Array &,这样不但能够避免在返回数据时调用拷贝构造函数,还能够达到连续赋值的目的
 47    if (this != &arr)
 48    { // 判断是否是给同一个对象赋值
 49        this->m_len = arr.m_len;
 50        free(this->m_p);
 51        this->m_p = (int *)calloc(this->m_len, sizeof(int));
 52        memcpy(this->m_p, arr.m_p, m_len * sizeof(int));
 53    }
 54    return *this; // 表示返回当前对象
 55}
 56
 57// 普通成员函数的定义
 58void Array::show()
 59{
 60    cout << "我是普通成员函数....\n";
 61}
 62
 63// 打印数组元素
 64void printArray(const Array &arr)
 65{
 66    int len = arr.length();
 67    for (int i = 0; i < len; i++)
 68    {
 69        if (i == len - 1)
 70        {
 71            cout << arr[i] << endl;
 72        }
 73        else
 74        {
 75            cout << arr[i] << ", ";
 76        }
 77    }
 78}
 79
 80int main()
 81{
 82    Array arr1(10);
 83    for (int i = 0; i < 10; i++)
 84    {
 85        arr1[i] = i;
 86    }
 87    cout << "arr1:";
 88    printArray(arr1);
 89
 90    Array arr2(5);
 91    for (int i = 0; i < 5; i++)
 92    {
 93        arr2[i] = i;
 94    }
 95    cout << "arr2:";
 96    printArray(arr2);
 97    cout << "------------------------------------\n";
 98    arr2 = arr1; // 调用operator=()
 99    cout << "将arr1赋值给arr2:";
100    printArray(arr2);
101    arr2[3] = 234; // 修改arr2的数据不会影响arr1,如果把operator=()注释掉,修改arr2的值就会影响arr1的值
102    arr2[7] = 920;
103    cout << "修改arr2的值不会影响arr1:";
104    printArray(arr1);
105    return 0;
106}


32.png


4.参考资料


[1] https://www.cnblogs.com/yongdaimi/p/7121151.html



相关文章
|
2月前
|
安全 编译器 程序员
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
56 2
|
5月前
|
C++ 容器
C++中向量的操作vector
C++中向量的操作vector
|
6月前
|
算法 前端开发 Linux
【常用技巧】C++ STL容器操作:6种常用场景算法
STL在Linux C++中使用的非常普遍,掌握并合适的使用各种容器至关重要!
96 10
|
6月前
|
C++ iOS开发 开发者
C++一分钟之-文件输入输出(I/O)操作
【6月更文挑战第24天】C++的文件I/O涉及`ifstream`, `ofstream`和`fstream`类,用于读写操作。常见问题包括未检查文件打开状态、忘记关闭文件、写入模式覆盖文件及字符编码不匹配。避免这些问题的方法有:检查`is_open()`、显式关闭文件或使用RAII、选择适当打开模式(如追加`ios::app`)以及处理字符编码。示例代码展示了读文件和追加写入文件的实践。理解这些要点能帮助编写更健壮的代码。
73 2
|
6月前
|
C++
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
|
5月前
|
机器学习/深度学习 算法 搜索推荐
|
7月前
|
C++
在C和C++中,指针的算术操作
在C和C++中,指针的算术操作
|
6月前
|
算法 搜索推荐 C++
C++之STL常用算法(遍历、查找、排序、拷贝、替换、算数生成、集合)
C++之STL常用算法(遍历、查找、排序、拷贝、替换、算数生成、集合)
|
6月前
|
算法 C++ 容器
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
C++之vector容器操作(构造、赋值、扩容、插入、删除、交换、预留空间、遍历)
291 0
|
7月前
|
算法 C++ 容器
黑马c++ STL常用算法 笔记(4) 常用拷贝和替换算法
黑马c++ STL常用算法 笔记(4) 常用拷贝和替换算法