0
点赞
收藏
分享

微信扫一扫

C++ ---->大类 ~~ 大对象 (中) __03

各位好友,欢迎来到本期博客 !经过前几期的学习, 类 ~ 对象 ,正变得越来越有滋味 ! 如今,六大默认成员函数 --->还剩下两个重要的函数 --->拷贝复制 与 赋值重载

下面,开战 拷贝复制 !

----->拷贝构造函数:只有单个形参,该形参是对本类 类型对象的引用(常用 const 修饰

意即,用 已经存在的类 -->类型对象创建对象时,由编译器自动调用 !

其实,前几次讲解 默认构造函数,最重要的还是其特性 !下面。来看看拷贝构造函数的特性 !

---->特性 :>

1. 拷贝构造函数是构造函数的一个重要的重载形式;

2. 拷贝构造函数的参数 有且只有一个 且必须是类 -->类型对象的引用,使用传值方式 编译器直接报错,因为会引发无穷递归调用 ;

3. 如果未显示定义,编译器会自动生成默认拷贝构造函数。默认拷贝构造函数对象 按照内存存储 以字节序完成拷贝

又称 -->浅拷贝,或者 值拷贝。

----->实现环节 --->初步探究:>

#include <iostream>
using std::cout;
using std::endl;


class Date
{
public:
			Date(int year = 2018, int month = 06, int day = 07)
      {
      	_year = year;
        _month = month;
        _day = day;
      }
      void Print()
      {
      	cout << _year << " - " << _month << " - " << _day << " - " << endl;
      }
      
      //拷贝构造函数
      Date(const Date& d)
      {
      	_year = d._year;
        _month = d._month;
        _day = d._day;
      }
private:
			int _year;
      int _month;
      int _day;
};

int main()
{
  Date d1;
  d1.Print();	// 显然此处, Date 类 并没有显示定义,则编译器会生成默认构造函数 --->特性 3
  
  Date d2(d1);
  d2.Print();	// 此处是 拷贝构造函数的运用 与打印
  
  Date d3(2023, 05, 07);
  d3.Print();	// 该处 已经显示定义, 则编译器不会再生成默认构造函数
  
  Date d5(d3);
  d5,Print();
	return 0;
}

为了方便好友们,有更好的观感体验,与更好的理解 !现附上有彩色的代码图样 :>

C++ ---->大类 ~~ 大对象 (中)  __03_拷贝复制函数 三大特性

现 对上述部分 较为难以理解的点,进行讲解 !

----->以下是 正确用法:>

C++ ---->大类 ~~ 大对象 (中)  __03_拷贝复制函数 三大特性_02

----->以下是 错误用法 :>


C++ ---->大类 ~~ 大对象 (中)  __03_拷贝复制函数 三大特性_03

为了便于好友们,更加理解 与 掌握 上述代码 !以下采用递归展开图 -->进行讲解 :>

各位好友,上述话语中,已经有答案了 !😊不进行引用,而进行传值操作的话,会出现 无限递归的现象 !

----->如下:>

C++ ---->大类 ~~ 大对象 (中)  __03_即是 典型 亦然 精华_04

以上 形成的 无限递归展开图,就是传值造成的结果 !显然,避免上述情况,需要运用强大的引用 !

毕竟,引用的传入,不需要生成临时变量空间 !如果,部分好友 对引用,或传值,存在些许不理解 !

可自行查看前几期的博文,其实,这都是前几期重点梳理的 ! 那里,有你要找寻的答案 !😊

各位好友,一定要注意上述代码 对特性 3 指出的位置 !好方便理解 !有关特性 3 描述 --->无彩色的代码环节

对于 上述程序,还需要指明一点,请注意:>

在编译器生成的默认拷贝构造函数中, 内置类型是 按照字节方式直接拷贝, 而自定义类型是 调用其拷贝构造函数完成拷贝 !

各位好友,以下还有两点需要提及:>

a.  编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了 !经由上述 --->日期类的显示实现,即使不书写定义的时候,编译器也会自动调用拷贝构造函数 !

对于 栈区 --->能否实现浅拷贝构造呢?是否 栈区的显示实现 也能经由编译器自动生成呢?

----->以下是探究过程:>

#include <iostream>
using std::cout;
using std::endl;

typedef int DateType;

class Stack
{
public:
  
  Stack(int capacity = 6)
  {
  	_a = (DateType*)malloc(sizeof(DateType) * capacity);
    if(_a == nullptr)
    {
    	perror("malloc::fail");
      return ;
    }
    
    _capacity = capacity;
    top = 0;
  }
  
  	void Push(DateType x)
    {
    	// 检查容量
      // CheckCapacity();
      _a[top++] = x;
    }
  
  ~Stack()
  {
  	free(_a);
    _a = nullptr;
    _capacity = 0;
    top = 0;
  }
  
private:
  DateType* _a;
  int _capacity;
  int top;
};


int main()
{
  Stack s;
  
  s.Push(12);
  s.Push(16);
  s.Push(17);
  s.Push(19);
  s.Push(21);
  
	return 0;
}

以上便是 栈区能否实现 --->编译器自己生成 显示实现 !

----->答案:> 程序会崩溃 !! 出于 对 VS 2019 编译器的保护,在这里就不演示了 !敬请谅解 !!🌹🌹

以下是 方便好友们,有更好的观感,与理解 !现 附上有彩色的代码图样 :>

C++ ---->大类 ~~ 大对象 (中)  __03_即是 典型 亦然 精华_05

出于 希望好友们 能从本篇博客中,学到更多新知识点的考量 !虽然 不进行运行结果的显示了,但是 核心本质 还是要解析一下的 !希望好友们,能加深对此处的理解,光靠文字说明,无法达到 --->理想的效果

----->解析:>

C++ ---->大类 ~~ 大对象 (中)  __03_隐藏版 this 指针_06

---->解析:>

1. s 对象会调用构造函数进行自身创建,在构造函数中申请了 6 个元素的空间;然后 又在里面存储5 个元素 

21 19 17 16 12

2.  对象_s -->对象 s 进行拷贝构造,而 Stack 类没有显示定义的拷贝构造函数,则编译器会给 Stack 类自动生成一个默认拷贝构造函数; 又 默认拷贝构造函数是按值进行拷贝的, 即 将对象 s 中的内容原封不动的拷贝到 _s 中 。因此,对象 s 与 对象 _s 指向了同一块内存空间。

3. 当程序退出的时候, 对象_s 与 对象s 都要进行销毁 !但是,会有一个先后顺序,即 对象_s  先销毁,销毁的时候,自然会调用析构函数,此时将 0x88889858 地址所在的空间释放掉了 !但是 对象 s 并不知道,二者又是指向的同一块空间, 到了销毁对象 s 时,会将 0x88889858 地址所在的空间再一次释放掉 !同一块内存空间连续多次释放,自然,,系统会抗不住的 😊从而造成 --->程序崩溃

----->注意:>

类中 如果没有涉及到资源申请,拷贝构造函数是否写出都可以; 一旦涉及到资源申请,拷贝构造函数是一定要书写的,否则就是浅拷贝 !

b. 拷贝构造函数典型应用场景 :>

(1)使用已经存在的对象创建新的对象;

(2)函数参数类型为 类 -->类型对象;

(3)函数的返回值类型为 类 --->类型对象。

以下展示代码,进行实现 :>

#include <iostream>
using std::cout;
using std::endl;

class Date
{
public:
  // 初始化函数, 又名 构造函数 ----->此处,不清楚的好友,可以自行查看前几期的博文
  Date(int year, int month, int day)
  {
    cout << "Date(int year, int month, int day):>" << this << endl << endl;
  }
  
  // 本期重点:> 一直在讲解的拷贝构造函数
  Date(const Date& d)
  {
  	cout << "Date(const Date& d):>" << this << endl << endl;
  }
private:
  int _year;
  int _month;
  int _day;
};

// 精彩点 -->用存在的类对象 创建 新的对象
Date Test(Date d)
{
	Date tamp(d);
  return tamp;
}

int main()
{
  Date _d(2018, 6, 7);
  Test(_d);
  return 0;
}

为了方便好友们,有更好的观感体验,与更好的理解 !现附上有彩色的代码图样 :>

----->测试环节:>

C++ ---->大类 ~~ 大对象 (中)  __03_隐藏版 this 指针_07

----->运行结果 :>

C++ ---->大类 ~~ 大对象 (中)  __03_隐藏版 this 指针_08

现在,对上述部分进行解析,其中,有好多是难以理解的知识点 !还有那至关重要的 逻辑过程 !

--->难点 -->精华 :>

C++ ---->大类 ~~ 大对象 (中)  __03_即是 典型 亦然 精华_09

其实,上述也有两大比较:传值 与 传引用 !--->效率最高 --->传引用 !

--->盲点 :>

C++ ---->大类 ~~ 大对象 (中)  __03_拷贝复制 典型应用场景_10

各位好友,请注意上述红色框框 ! “this” 指针 --->内置版的隐藏指针 ,是指向不同类型对象所在的地址 !

至此,本模块下,拷贝构造函数 已讲解完成 !希望,各位好友能够 -->得到些 新的体验 与收获 !

下一期,开战 -->赋值运算重载函数 那可是一块 “骨头汤” 啊 ! 是有一定难度的 !但是 更有营养 !尤其是 重载运算符(operator)引入 !

接下来将会进行 --->日期类的运算 !估计会有两篇博客写就 !又一次到了 说再会的时刻了 !

未来两期的博文内容,将有一定的挑战性 !估计,将会有 两到三天时间 用来打磨 !只希望 内容更加通俗易懂,便于学习 与理解 !终于,最后一个  -->重要的默认构造函数 就要来了 !😊😊

接下来, 这座小高山, 攀登顶部 -->风景肯定会非常美丽!而 C++ 魅力 也将得到再一次的体现 !

期待,各位好友,下一期,再相会 !😊😊


举报

相关推荐

0 条评论