IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++第四章 -> 正文阅读

[C++知识库]c++第四章

目录

一、拷贝构造函数

二、深拷贝与浅拷贝

三、this指针

四、异常机制


一、拷贝构造函数

????????当我们用一个对象去初始化另外一个对象的时候,参数很明显是我的一个类,里面做的初始化很有可能是多种多样的,因此它的实现应该是和我简单的构造函数不一样的。如果我们的成员里面有指针,这个指针有可能是自己的一个独立空间

? ??class people
?? ?{
?? ??? ?
?? ??? ?int * a;
?? ??? ?public:
?? ??? ??? ?people():a(new int(1024)){}?? ?
?? ??? ??? ?~people(){delete a;}
?? ?}

????????通过这个类定义的对象去初始化另外一个对象的时候,另外的那个对象需求这个a的地址,如果是简单的值得赋值,那么就会遇到一个问题 -> 两个指针指向了同样的一个空间,那么由people是存在这个析构函数的 , 我在上方的这个对象里面,会析构这个地址,而现在用这个对象创建出来的这个对象也需要析构这个地址,因此这个初始化很明显会存在两种不同的操作:
?? ??? ?????????1 简单的成员赋值
?? ??????????? ?2 我们需要新开空间

?? ??? ?因此里面的操作就跟原先的构造函数不一样,所以这种初始化我们就应该要另寻机制 -> 拷贝构造函数

????????声明:
?? ??? ?????????拷贝构造函数编译器在你没有写拷贝构造函数的时候,会默认给你生成一个拷贝构造函数,里面做的事情是逐成员赋值。当我们自己写了自己的拷贝构造函数,那么编译器就不会给你生成了
?? ??????????? ?
拷贝构造函数也是一个构造函数,实际上也是对我们的对象进行初始化的,只是这个初始化的值来源于另外一个对象 ,因此它的参数只有一个,就是本类的一个引用

????????语法:
?? ??? ??? ?类名(类名 &){}

?? ??? ??? ?????????我们在使用的时候注意,由于是一个对象初始化另外一个对象,仅此而已,因此我们是不能将我传进来的这个对象的值改变的,因此我们
需要加const
?? ??? ??? ?类名(const 类名 &){}
?? ??? ??? ?????????里面的操作看自己的实现,更多的时候我们是直接赋值,少数的时候我们需要开空间

????????????void func(const char * p)
?? ??? ??? ?{
?? ??? ??? ??? ?printf("%s\n",p);
?? ??? ??? ??? ?*p = 'j';//p指向的这个空间不可更改
?? ??? ??? ??? ?
?? ??? ??? ??? ?char * q = (char *)p;//c语言里面是可以做的
?? ??? ??? ??? ?
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?int main()
?? ??? ??? ?{
?? ??? ??? ??? ?char arr[] = "hehe";
?? ??? ??? ??? ?func(arr);
?? ??? ??? ?}

????????区别于c的const ?c++里面的const就一定是const声明了就不能更改,除非你不声明,因此 const 类名 & 和类名 & ?-> 在c++里面实际上参数不一样
????????建议不要这么做,初始化就是初始化,没有那么多的不一样的地方,建议写拷贝构造的时候建议加上const

? ? ? ? ? ?void func(const char * p)
?? ??? ??? ?{
?? ??? ??? ??? ?printf("%s\n",p);
?? ??? ??? ??? ?*p = 'j';//p指向的这个空间不可更改
?? ??? ??? ??? ?
?? ??? ??? ??? ?char * q = (char *)p;//c语言里面是可以做的
?? ??? ??? ??? ?
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?int main()
?? ??? ??? ?{
?? ??? ??? ??? ?char arr[] = "hehe";
?? ??? ??? ??? ?func(arr);
?? ??? ??? ?}

?? ??? ??? ?区别于c的const ?c++里面的const就一定是const
?? ??? ??? ?声明了就不能更改,除非你不声明
?? ??? ??? ?
?? ??? ??? ?因此 const 类名 & 和类名 & ?-> 在c++里面实际上参数不一样
?? ??? ??? ?建议不要这么做,初始化就是初始化,没有那么多的不一样的地方
?? ??? ??? ?建议写拷贝构造的时候建议加上const

?? ??? ??? ?
?? ??? ??? ?struct people
?? ??? ??? ?{
?? ??? ??? ??? ?people(int a = 0,char b = 0):a(a),b(b){}
?? ??? ??? ??? ?people(const people & p)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?a = p.a;
?? ??? ??? ??? ??? ?b = p.b;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?void show()
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?cout << a << " " <<b << endl;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?private:
?? ??? ??? ??? ??? ?int a;
?? ??? ??? ??? ??? ?char b; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??? ??? ??? ?
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?int main()
?? ??? ??? ?{
?? ??? ??? ??? ?people p(1024,'q');
?? ??? ??? ??? ?p.show();
?? ??? ??? ??? ?
?? ??? ??? ??? ?people p1(p);
?? ??? ??? ??? ?p1.show();
?? ??? ??? ?}

二、深拷贝与浅拷贝

? ? ? ? 1浅拷贝逐成员赋值
?? ????????????但是有的时候会出现问题,有指针 很有可能这个指针指向的是同一个空间,并且一改 两个人都会改, 一释放就多次释放,这个时候我们就应该让这个指针指向自己应该需要的空间
?? ??? ?这个时候我们就应该要重新申请另外的空间 -> 这种情况我们叫深拷贝

????????2深拷贝?
????????????????申请的空间,要将原空间里面的内容拷贝过来
?? ??? ?注意:是完全的复制
?? ??? ??? ?memcpy
?? ??? ?????????不一定所有的指针都是需要用深拷贝的,具体的事情具体对待,有的时候浅拷贝 有的时候是深拷贝

struct people

{

? ? people(int a = 0,char b = 0):a(a),b(b),ptr(new int(a)){cout << "构造函数" << endl;}

? ? people(const people & p)

? ? {

? ? ? ? a = p.a;

? ? ? ? b = p.b;

? ??

? ? ? ? //ptr = p.ptr;

? ? ? ? //根据深拷贝的原则 我们这里就需要申请新的空间

? ? ? ? ptr = new int;

? ? ? ? *ptr = *(p.ptr);

? ? ? ? cout << "拷贝构造函数" << endl;

? ? }

? ? ~people()

? ? {

? ? ? ? if(ptr != nullptr)

? ? ? ? {

? ? ? ? ? ? cout << ptr << endl;

? ? ? ? ? ? delete ptr;

? ? ? ? ? ? ptr = nullptr;

? ? ? ? }

? ? ? ? cout << "析构函数" << endl;

? ? }

? ? void show()

? ? {

? ? ? ? cout << a << " " << b << " ?" << *ptr << endl;

? ? }

? ? private:

? ? ? ? int a;

? ? ? ? char b; ?

? ? ? ? int * ptr;

};


?

people func()

{

? ? people p(111,'s');//构造函数必然会在这里调用

? ? return p;

}


?

int main()

{

? ? /*

? ? people p(1024,'q');

? ?

? ? people p1(p);

? ?

? ? people p2 = p;

? ?

? ? people p3 = func();//按照道理来说是要调用拷贝构造的 ?但是最后

? ? ? ? ? ? ? ? //只调用了一次构造函数 编译器会在这里优化

? ? ? ? ? ? ? ? //有的时候优化不一定好 ?我需要不优化

? ? ? ? ? ? ? ? //编译的时候后面加上 -fno-elide-constructors

? ? */

? ?

??

? ? people q(1024,'r');//q.ptr == 0x01 -> delete q.ptr ->delete 0x01

? ? ? ? ? ? ? ? ? ? //q.ptr = nullptr

? ? q.show();

? ? people q1(q);//q1.ptr == 0x01 -> delete q1.ptr ->delete 0x01

? ? ? ? ? ? ? ? //当q1结束生命的时候 ?会再一次free 这个时候就多次free一个地方了

? ? ? ? ? ? ? ? //不允许

? ? q1.show();

}

三、this指针

????????有的时候我们需要在类里面使用自己本身,实际上就是对象使用对象自己本身,类里面会封装方法,而这些方法是属于这个对象的,我们在使用这个方法的时候必须要将这个类实例化,而在这些方法里面我们就有可能会使用指针->包括这个对象自己的地址
?? ??? ?如果像方法一样带我自己的地址进去,好像是可以,但是有一个时候它绝对不行 -> 初始化的时候,按照道理来说我应该是可以去使用自己的,为了解决这个需求,在每一个类里面都会隐藏一个指针 ?-> this

????????this不是在类的 -> 没有实例化的时候实际上就没有实体,没有实体哪来地址,因此这个this一定是属于对象自己本身的

????????this就是对象自己的地址,对象不一样,那么this就不一样,谁调用我this就是谁
?? ??? ??? ?people p;
?? ??? ??? ?&p -> this,得到这个this我们就可以用这个对象里面的成员了
?? ??? ??? ?使用方式跟在外面使用指针是一样的
?? ??? ??? ?this -> 成员 这个this肯定是在类里面用得

class people
?? ??? ??? ?{
?? ??? ??? ??? ?int a;
?? ??? ??? ??? ?int b;
?? ??? ??? ??? ?public:
?? ??? ??? ??? ??? ?people(int a,int b):a(a)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?this ->a = a;
?? ??? ??? ??? ??? ??? ?this ->b = b;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?void setdata(int a,int b)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?this -> a = a;
?? ??? ??? ??? ??? ?}
?? ??? ??? ?}

四、异常机制

????????c++里面错误分为两种
????????????????1 编译错误(这种问题是最简单的)
????????????????2 运行错误(这种问题就非常让人不好受)

?? ?
????????c++里面为了优化运行错误而有了异常处理机制,所谓的异常,就是在程序的运行过程中,由于系统条件、操作不当等原因引起的程序崩溃,这种情况我们就叫异常

????????常见的异常:除数为0,内存分配失败,你要操作一个没有打开的文件,我们往一个没有读端的管道里面写......
?? ??? ??? ??? ?
????????异常一旦产生,我们的程序就会崩溃,对我们来说是一种毁灭性的打击。为了提高我们程序的健壮性,加强它的容错能力,我们需要对这些异常,进行处理,防止我们的程序意外终止。在c语言里面我们实际上也经常在干这个事情
?? ??? ??? ?if(p == NULL)//这个时候实际上就是在做异常处理
?? ??? ??? ??? ??? ??? ?//发现这个错误我们及时处理就可以了
????????但是用c语言里面的这一套我们需要在各种时间里面都需要去判断,这样就有点不美好,c++为了继续去完成这一套,设置了异常处理,这个机制由三个部分去组成:
?? ??? ??? ??? ?1 抛出异常
?? ??? ??? ??? ?2 捕捉这个异常
?? ??? ??? ??? ?3 处理这个异常

????????c++为了这三个步骤引出了三个关键字:throw try catch
????????????????try:检测这个异常
???????????????
?throw:抛出这个异常
????????????????
catch:关联这个异常

? ? ? ? ? ? try
?? ??? ??? ?{
?? ??? ??? ??? ?//检测异常 实际上还是c语言里面的那一套
?? ??? ??? ??? ?if(a == 0)
?? ??? ??? ??? ?
?? ??? ??? ??? ?
?? ??? ??? ??? ?throw 异常值;//抛出这个异常
?? ??? ??? ?
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ??? ?catch(异常值类型1)
?? ??? ??? ?{
?? ??? ??? ??? ?//这里就可以进行错误处理
?? ??? ??? ?}
?? ??? ??? ?catch(异常值类型2)
?? ??? ??? ?{
?? ??? ??? ??? ?//这里就可以进行错误处理
?? ??? ??? ?}
?? ??? ??? ?catch(...)//其余的类型都往这个地方来
?? ??? ??? ?{
?? ??? ??? ??? ?
?? ??? ??? ?}
?? ??? ??? ?...这三个点必须写在最后面,前面没有匹配到,那么就匹配这里

?eg.

//有一个功能去做除法运算

double function(double a,double b)

{

? ? if(b > -0.0000001 && b < 0.0000001)//项目里面判断一个double是否等于0必须这么来

? ? {

? ? ? ? cout << "异常出现了" << endl;

? ? ? ? throw 123;//抛出异常

? ? ? ?

? ? }

? ? else

? ? {

? ? ? ? return a / b;

? ? }

? ?

? ?

}

int main()

{

? ? double a = 250;

? ? double b = 0;

? ? double c = 0;

? ? try

? ? {

? ? ? ? //调用可能出现异常的功能的代码

? ? ? ? //我们就应该让它处于try里面

? ? ? ? c = function(a,b);

? ? }

? ? //catch(int)//由于上方抛出的是异常值 那么我们实际上是可以接收这个值

? ? ? ? ? ? ? ? //直接定义变量 如果你不定义变量相当于不获取这个值 只关联这个类型

? ? catch(int hehe)//这个hehe就可以去获取你抛出的异常值

? ? {

? ? ? ? cout << "你的除数为0 = " << hehe << ?endl;

? ? }

? ? catch(char)

? ? {

? ? ? ? cout << "兄弟,你是what异常" << endl; ?

? ? }

? ? catch(...)

? ? {

? ? ? ? cout << "姐妹们,其它的都在这里" << endl;

? ? ? ?

? ? }

? ? return 0;

}

????????我们发现上述的代码好像就是脱裤子放屁,把他变得复杂了。实际上工程里面异常都是用的这种机制,这种机制最大的优势 -> 错误和错误处理分开进行,异常处理机制是面向对象的一种设计思维,我们以后的程序错误处理操作应该要遵循,实际在项目里面有非常多问题 ->?异常处理一定要做关注,将main函数里面的东西全部包含在try ?貌似可以,实际也可以,但是效率低下,我们的这种机制是为防止错误,不是为了防止正确的 -> 正确的地方该怎么跑就怎么去跑

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-15 11:36:23  更:2021-10-15 11:38:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:38:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码