12.1.2 隐式成员函数

12.1.2 隐式成员函数

StringBad 类中的问题是由自动定义的脑式成员通数引起的,这种函数的行为与类设计不符。兵体来说,
C++自动提供了下面这些成员函数:
● 默认构造函数。如果没有定义构造函数。
● 复制构造函数。如果没有定义。

● 赋值操作符,如果没有定文。
默认析构函数,如果没有定文。
地址操作符,如果没有定义。
更准确地说,编译器将生成上述最后4个函数的定义 -- 如果程序使用对象的方式要求这样做。例如,
如果您将个对象赋给另一个对象,编译器将提供賦值操作符的定义。
结果表明,StringBad类中的问题是由隐式复制构造函数和隐式赋值操作符引起的。
隐式地址操作符返回调用对象的地址(即this指针的值)。这与我们的初衷是一致的,在此将不详细讨
论该成员函数。默认析构函数不执行任何操作,因此这里也不讨论它,不过需要指出的是,这个类已经提
供默认构造函数。至于其也成员函数还需要进一步计论。

1. 默认构造函社
如果没有提供任何构造函数,C++将创建默认构造函数。例如,假如定义了一个Klank类,但没有提
供任何构量函数,则编译器将提供下述默认构造函数;
Klunk :: Klunk() | // implicit default constructor
也就是说,编译器将提供-个不接受任何参数,也不执行任何操作的构造函数,这是因为创建对象时
总是会调用构进函数:
Klunk lonki // invokes default conatruetor
默认构迹涵数使Lunk类似于一个常规的自动变量,也就是说,它的值在初始化时是未知的。
如果定义了构造函数,C++将不会定义默认构造函数。如果希望在创建对象时显式地对它进行初始化,
或需要创建对象数组时,則必须显式地定义默认构造函数。这种构造函数没有任何参数,但可以使用它来
设置特定的值:
Klunk :: Klunk() // expliest defawlt constructor

klunk ct m D:

// constructor $1

// cleatly matches Klunt(int n)
// could match either comstructor

带参数的构造函数也可以是默认构造函数,只要所有参数都有默认值。例如,Klunk类可以包含下述
内联构造函数;
Klunk (int n = 0) [ klunk_ct = n: )
但只能有一个默认构造函数。也就是说,不能这样做;
Klunk()| klunk ct = D ]
Klunk (int m - 0) | klunk ct = n: | // ambiguous constrootor #2
这为何有二义性呢?请看下面两个声明;
Klunk kar [1D);
Klunk bos;
第二:个声明既与构造函数1(没有参数)匹配,也与构造函数2(使用默认参数0)匹配。这将导致编
详器发出一条错误消息。

2. 复制构造函教
复制构造函数用于将一个对象复制到新创建的对象中。也就是说,它用于初始化过程中,而不是常规
的赋值过程中。类的复制构造函数原型通常如下:
Class nane (conat Class_name 6) :
它接受·个指向类对象的常量引用作为参数。例如,String类的复制构造函数的原型如下:
StrimgBad (oonst Steinghad 5) :
对于复制构造函数,需要知道两点:何时调用和有何功能。
{1]何时调网复制构造函数
新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用。这在很多情况下都可能发
生,最常见的情况是将新对象显式地初始化为现有的对象,例如,假设motto是一个StringBad对象,则下
面4种声明都将调用复制构造函数:

StringBad ditto (motto); // calls StringBad (const Stringhad 6)
StringBad metoo = motto: // calls StringBad (Cenat StringBad &)
StringBad also - StringBad (motto)
// calls StringBad (const StringBad &)
StringBad * pStringBad = new Stringhad (motto)
// calls StringBad (const StringBad 5)
其中中间的2种声明可能会使用复制构造函数直接创建metoo和also,也可能使用复制构造函数生成
一个临时对象,然后将临时对象的内容赋给metoo和also,这取决于具体的实现。最后一种声明使用 motto
初始化一个匿名对象,并将新对象的地址赋给 pstring 指针。
每当程序生成了对象副本时,编译器都将使用复制构造函数,具体地说,当函数按值传递对象(如程
序清单 12.3 中的callme2()或函数返回对象时,都将使用复制构造函数。记住,按值传递意味着创建原
始变量的一个副本。编译器生成临时对象时,也将使用复制构造函数。例如,将3个Vector对象相加时,
编译器可能生成临时的Vector对象来保存中间结果。何时生成临时对象随编译器而异,但无论是哪种编译
器,当技值传递和返回对象时,都将调用复制构造函数。具体地说,程序清单12.3中的函数调用将调用下
面的复制构造函数;
callme2 (headline2) .
程序使用复制构造函数初始化sb -- callme2(函数的StringBad型形参。
由于按值传递对象将调用复制构造函数,因此应该按引用传递对象。这样可以节省调用构造面数的时
间以及存储新对象的空间。
〔2|复制构造函数的功能
默认的复制构造函数逐个复制非静态成员(成员复制也称为浅复制),复制的是成员的值。在程序清单
12.3中,下述语句:
Streinghad sailor = sports:
与下面的代码等效(只是由于私有成员是无法访问的,因此这些代码不能通过编译);
Stringbad sailor:
sailor.atr = aports.stri
sailor.len = sports.lem
如果成员本身就是类对象,则将使用这个类的复制构造函数来复制成员对象。静态函数(如
mum_strings)不受影响,因为它们属于整个类,而不是各个对象。图12.2说明了隐式复制构造函数执行的
操作。

3. 复制构造晶数的哪里出了问题
现在介绍程序清单 12.3 的两个异常之处(假设输出为该程序清单后面列出的)。首先,程序的输出表
明,析构函数的调用次数比构造函数的调用次数多2,原因可能是程序确实使用默认的复制构造函数另外
创建了两个对象。当callme2(被调用时,复制构造函数被用来初始化callme2(的形参,还被用来将对象
sailor初始化为对象sports。默认的复制构造函数不说明其行为,因此它不指出创建过程,也不增加计数器
nam_strings的值。但析构函数更新了计数,并且在任何对象过期时都将被调用,而不管对象是如何被创建
的。这是一个问题,因为这意味着程序无法准确地记录对象计数。解决办法是提供一个对计数进行更新的
显式复制构造函数:
String :: String (const String & s)

num_strings++:
... // important stuff to go here

提示:如果类中包含这样的静态数据成页,即其值将在新对象被创建时发生变化,则应该提供一个足
式复制构造函教来处理计数问题。

第二个异常之处更微妙,也更危险,其表现之一是字符串内容出现乱码;
headline2: D04

另一个表现是,使用许多编译器对其进行编译后,运行时将异常终止。例如 Microsoft Visual C++7.1
(调试模式)显示一个错误消息窗口,指出调试断言失败,而gpp发出通用保护错误。其他系统可能提供不
同的消息,甚至不提供任何消息,但程序中的错误是相同的。
原因在于隐式地复制构造函数是按值进行复制的。例如,对于程序清单12.3,隐式地复制构造函教的
功能相当于:
sailor.stt = sport.str.
这里复制的并不是字符串,而是一个指向字符串的指针。也就是说。将sailce 初始化为spodts后,得
到的是两个指向同一个字符率的指针。当operator << ()函数使用指针来显示字符串时,这并不会出现问题。
但当析构函数被调用时,这将引发问题,析构函数StringBad释放str指针指向的内存,因此释故sailor.的
效果如下:
delete || sallor.stri
sailor.str 指针指向“Spinach Leaves Bowl for Dollars”,因为它被赋值为sports.str,而 sports.str指向的
正是上述字符串。所以delete 语句将释放字符串“Spinach Leaves Bowl for Dollars”占用的内存。
然后,释放sports的效果如下:
delete [] sports.str: // etfect is undefined
sports.str 指向的内存已经被 sailor的析构函数释放,这将导致不确定的、可能有害的后果。程序清单
12.3中的程序生成受损的字符串,这通常是内存管理不善的表现。

4. 使用显式复制构造函教未解决问题
解决类设计中这种问题的方法是进行深度复制(deep copy)。也就是说,复制构造函数应当复制字符
非并将副本的地址赋给str成员,而不仅仅是复制字符串地址。这样每个对象都有自己的字符串,而不是引
用另一个对象的字符串。调用析构函数时都将释放不同的字符串,而不会试图去释放已经被释放的字符串。
可以这样编写String的复制构造函数:

// delete the string that ditto.str points to

StringBad :: StrimgBad (const StringBad & at)

// handle static member ypdate
// sare length
J/ allot space
// copy string to new Location
cout << nom_stringa << ", \"* << atr
<< "\" object crestedin": // For Your Information

必须定义复制构造函数的原因在于,一些类成员是使用new初始化的、指向数据的指针,而不是数据
本身。图12.3说明了深度复制。

num_strings++:
len = at.lem:
atr = new char (1en + 1]:
atd :: strepy (str. st.str);

警告:如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,
而不是指针,这被称为深度复制。复制的另一种形式(成员复制或浅复制)只是复制指针值。浅复制仪浅
浅地复制指针信息,而不会深入“挖掘”来复制指针引用的结构。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/234419.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言:指向数组的指针和指向数组元素的指针

相关阅读 C语言https://blog.csdn.net/weixin_45791458/category_12423166.html?spm1001.2014.3001.5482 指向数组的指针和指向数组元素的指针常常被混淆&#xff0c;或者笼统地被称为数组指针&#xff0c;但它们之间是有差别的&#xff0c;本文就将对此进行讨论。 下面的代码…

Java设计模式:工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

第五讲观测值中与卫星、接收机有关的误差 第六讲观测值中与信号传播路径有关的误差以及电离层、对流层相关模型 | GNSS(RTK)课程学习笔记day3

说明&#xff1a;以下笔记来自计算机视觉life吴桐老师课程&#xff1a;从零掌握GNSS、RTK定位[链接]&#xff0c;从零掌握RTKLIB[链接]。非原创&#xff01;且笔记仅供自身与大家学习使用&#xff0c;无利益目的。 第五讲 观测值中与卫星、接收机有关的误差 卫星轨道误差 由卫…

Kafka-Kafka核心参数详解

Kafka的HighLevel API使用是非常简单的&#xff0c;所以梳理模型时也要尽量简单化&#xff0c;主线清晰&#xff0c;细节慢慢扩展。 Kafka提供了两套客户端API&#xff0c;HighLevel API和LowLevel API。 HighLevel API封装了kafka的运行细节&#xff0c;使用起来比较简单&…

jQuery实现轮播图代码

简述 一个简单的jQuery轮播图代码,首先,定义了一个slideshow-container的div容器,其中包含了所有轮播图幻灯片。每个幻灯片都包含一个mySlides的类名,并且使用CSS将其隐藏。然后,使用JavaScript代码来控制幻灯片的显示和隐藏。在showSlides()函数中,遍历所有幻灯片并将它…

【项目管理】redmine

Redmine是用Ruby开发的基于web的项目管理软件&#xff0c;是用ROR框架开发的一套跨平台项目管理系统&#xff0c;据说是源于Basecamp的ror版而来&#xff0c;支持多种数据库&#xff0c;有不少自己独特的功能&#xff0c;例如提供wiki、新闻台等&#xff0c;还可以集成其他版本…

Flutter实现丝滑的滑动删除、移动排序等-Dismissible控件详解

文章目录 Dismissible 简介使用场景常用属性基本用法举例注意事项 Dismissible 简介 Dismissible 是 Flutter 中用于实现可滑动删除或拖拽操作的一个有用的小部件。主要用于在用户对列表项或任何其他可滑动的元素执行删除或拖动操作时&#xff0c;提供一种简便的实现方式。 使…

大数据处理与分析-Spark

导论 (基于Hadoop的MapReduce的优缺点&#xff09; MapReduce是一个分布式运算程序的编程框架&#xff0c;是用户开发“基于Hadoop的数据分析应用”的核心框架 MapReduce是一种用于处理大规模数据集的编程模型和计算框架。它将数据处理过程分为两个主要阶段&#xff1a;Map阶…

(2021|EMNLP,CLIP,CLIPScore,RefCLIPScore)CLIPScore:图像标题的无参考评估指标

CLIPScore: A Reference-free Evaluation Metric for Image Captioning 公z号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 相关工作 3. CLIPScore 4. 标题评估基准 …

item_get-1688商品详情在跨境电商中的品牌形象塑造与传播

随着全球化的深入发展&#xff0c;跨境电商逐渐成为商品贸易的新趋势。在跨境电商中&#xff0c;商品详情作为消费者了解商品的重要途径&#xff0c;对于品牌形象塑造与传播具有重要意义。本文将探讨item_get-1688商品详情在跨境电商中的品牌形象塑造与传播&#xff0c;以期为相…

vue实现文本上下循环滚动

前言 页面上有两块公告,需要循环滚动,最初使用animation实现了,但如果两块公告的条数不一致的话,就会导致两块公告滚动的快慢不同,由此需要换种方式实现,使两块公告始终以同样的快慢节奏滚动。 第一种方式:animation实现(存在两块公告滚动的快慢不同的问题) <!-…

yolov5障碍物识别-雪糕筒识别(代码+教程)

简介 这是一个检测交通锥并识别颜色的项目。我使用 yolov5 来训练和检测视锥细胞。此外&#xff0c;我使用 k 均值来确定主色&#xff0c;以对锥体颜色进行分类。目前&#xff0c;支持的颜色为红色、黄色、绿色和蓝色。其他颜色被归类为未知。 数据集和注释 我使用了一个自收…

CMMI认证中的ATM是什么?

CMMI&#xff08;Capability Maturity Model Integration&#xff09;认证是国际上广泛认可的一种软件能力成熟度模型&#xff0c;旨在帮助组织提高软件开发的效率和质量。在CMMI认证中&#xff0c;ATM&#xff08;Appraisal Team Member&#xff09;起着关键作用。本文将详细介…

Open5GSUeRANSim3:VirtualBOX VM使用static IP并和host互通

本文档参考 https://blog.csdn.net/shuaihj/article/details/127589833 https://www.cnblogs.com/manongqingcong/articles/16659150.html https://blog.csdn.net/justlpf/article/details/132977047 VM默认使用的是自动分配的IP&#xff0c;每个VM的ip都是10.0.2.15。后续为了…

12.19_黑马数据结构与算法笔记Java

目录 203 排序算法 选择排序 204 排序算法 堆排序 205 排序算法 插入排序 206 排序算法 希尔排序 207 排序算法 归并排序 自顶至下 208 排序算法 归并排序 自下至上 209 排序算法 归并加插入 210 排序算法 单边快排 211 排序算法 双边快排 212 排序算法 快排 随机基准…

ITIL® 4 Foundation​,12月23日即将开课~想了解点击查看

ITIL 4 Foundation即将开课~ 想报名的必须提前预约啦 &#x1f447;&#x1f447;&#x1f447; 培训地点&#xff1a; 远程直播&#xff1a;线上平台学习 开课时间&#xff1a; 周末班&#xff1a;12月23日、24日&#xff1b; 什么是ITIL&#xff1f; 信息技术基础架构…

将Abp默认事件总线改造为分布式事件总线

文章目录 原理创建分布式事件总线实现自动订阅和事件转发 使用启动Redis服务配置传递Abp默认事件传递自定义事件 项目地址 原理 本地事件总线是通过Ioc容器来实现的。 IEventBus接口定义了事件总线的基本功能&#xff0c;如注册事件、取消注册事件、触发事件等。 Abp.Events…

LTD256次升级 |一分钟创建小程序官网 • 官网内容可在小程序分享

1、 商品关联表单支持上传图片&#xff1b; 2、 「我的咨询」新增快捷添加入口&#xff1b; 3、 极速官微新增官网内容分享页面&#xff1b;优化创建流程&#xff1b; 4、 极速官微支持编辑方式添加文章与产品&#xff1b; 5、 极速官微新增数据枢纽入口与网站设置页面&#xf…

(9)Linux Git的介绍以及缓冲区

&#x1f4ad; 前言 本章我们先对缓冲区的概念进行一个详细的探究&#xff0c;之后会带着大家一步步去编写一个简陋的 "进度条" 小程序。最后我们来介绍一下 Git&#xff0c;着重讲解一下 Git 三板斧&#xff0c;一般只要掌握三板斧就基本够用了。 缓冲区&#xff…

Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

当使用ssh登录服务器时&#xff0c;由于文件权限没有设置报以下错误 WARNING: UNPROTECTED PRIVATE KEY FILE! Permissions for test_1.pem are too open. It is required that your private key files are NOT accessible by others. This private key will be ignored. Loa…