4.Copy Constructor的构造操作

news/2024/9/19 4:47:43/ 标签: c++

目录

1、对象赋值问题引入

2、Bitwise Copy Semantics(位逐次拷贝)

3、处理class virtual function

4、处理virtual base class subobject


1、对象赋值问题引入

在C++中,有三种情况会以一个object的内容作为另一个class object的初值。这三种情况分别如下:

第一种,显式地以一个object的内容作为另一个class object的初值 X xx = x;

第二种,当object被当作参数交给某个函数时,例如:

extern void foo(X x);
void bar()
{X xx;//以xx作为foo()的第一个参数初值(隐式的初始化操作)foo(xx);//...
}

第三种,当一个函数传回一个class object时,例如

X
foo_bar()
{X xx;//...return xx;
}

那么问题来了,以一个object的内容作为另一个class object的初值,C++语言是怎么进行操作的

假设class设计者显示定义了一个copy constructor,像这个样子。

//user-defined copy constructor 的实例
//可以是多参数的形式,其第二参数以及后继参数以一个默认值供应之
X::X(const X &x);
Y::Y(const Y & y,int = 0);

在大部分的情况下,以上的问题将会调用copy constructor。少数情况会执行Bitwise Copy。

如果class没有提供一个explicit copy constructor,当class object以相同的class的另外一个object作为初值,其内部以default memberwise initialization的方法完成。也就是每一个内建的或者派生的data member的值,从一个object拷贝到另外的一个object上。不过它不会拷贝其中的member class object,而是以递归的方式施加memberwise initialization。例如,有一个下面的class声明:

class String
{
public://...没有explicit copy constructor
private:char *str;int len;
};

对于String verb = noun;语句,他的完成方式像是设定每一个members一样:

//语意相等
verb.str = noun.str;
verb.len = noun.len;

以上是一种memberwise initialization。如果String object是另外一个class的member,像这样子:

class Word
{
public://...没有explicit copy constructor
private:int _occurs;String _world;
};

对于Word verb = noun;语句,他的完成方式像是设定每一个members一样:

//语意相等
verb.occurs = noun.occurs;//bitwise copy
verb._world = String::String(noun._world);//编译器生成copy constructor,并执行拷贝构造函数

Default constructors和copy constructors在必要的时候才由编译器产生出来。这里“必要的时候”指的是当class不展示bitwise copy semantics时候。

2、Bitwise Copy Semantics(位逐次拷贝)

一个class什么时候不展示“bitwise copy semantics”?有下面的4种情况:

1)当一个class内含一个member object而后者的class声明一个copy constructor时(不论是class设计者显示的声明,还是编译器隐式的合成),例如下面的代码,String显示的声明了,而Word隐式的合成。

class String
{
public:String(const char *);String(const String &);~String();//...
};
class Word
{
public:Word(const String &);~Word();//...
private:int cnt;String str;
};

2)当class继承一个base class而后者存在一个copy constructor时(不论是显示声明还是隐式的被合成)。例如class Dog没有拷贝构造函数,当发生一个Dog object的内容作为另一个Dog object的初值,Dog会被编译器合成一个copy constructor。

class Animal
{
public:Animal(const char *);Animal(const Animal &);~Animal();//...
};
class Dog:public Animal
{
public:Dog(char * name);~Dog();
};

3)当class声明一个或者多个virtual function时。

class Student
{
public:Student();~Student();String virtual get_name();
};

4)当class派生自一个继承串链,其中一个或多个virtual base classes时。

class Postgraduate : virtual public Student
{
public:Postgraduate();~Postgraduate();String get_Thesis_topic();
};

3、处理class virtual function

在前一节的bitwise copy semantics,提到当class声明一个或者多个virtual function时会被编译器合成一个copy constructor。此外class会进行两种扩张操作:

  • 增加一个virtual function table(vtbl),内含每一个有作用的virtual function的地址。
  • 一个指向virtual function table的指针(vtpr),安插在每一个class object内部。

首先,我定义两个class,ZooAnimal和Bear:

class ZooAnimal
{
public:ZooAnimal();virtual ~ZooAnimal();virtual void animate();virtual void draw();//...
private://ZooAnimal 的animate() 和 draw()//所需的数据
};
class Bear : public ZooAnimal
{
public:Bear();void animate();//译注:虽未写明是virtual,但它其实是virtualvoid draw();//译注:虽未写明是virtual,但它其实是virtualvirtual void dance();//...
private://Bear 的animate() 、 draw() 和 dance()//所需的数据	
};

然后,Bear class object以另一个Bear class object作为初值,我可以看到yogi的vptr值拷贝给了winnie的vptr了,这样的操作是安全的,它是通过编译器合成的拷贝构造函数完成的。

最后,当一个base class object以其derived class的object内容做初始化操作时,其vptr复制操作也必须保证安全,例如:

ZooAnimal franny = yogi; //译注:派生类给基类赋值

4、处理virtual base class subobject

Virtual base class 的存在需要特别的处理。一个class object如果以另一个object作为初值,而后者有一个virtual base class subobject,那么也会使“bitwise copy semantics”失效。看看如下继承关系的代码。

class ZooAnimal
{
public:ZooAnimal();virtual ~ZooAnimal();virtual void animate();virtual void draw();//...
private://ZooAnimal 的animate() 和 draw()//所需的数据
};class Raccon : public virtual ZooAnimal
{
public:Raccon(){/*设定private data的初值*/}Raccon(int val){/*设定private data的初值*/}//...
private://所有必要的数据
};class RedPanda : public virtual Raccon
{
public:RedPanda(){/*设定private data的初值*/}RedPanda(int val){/*设定private data的初值*/}//...
private://所有必要的数据
};

对于如下的代码,little_red和little_critter的关系如下图所示。

RedPanda little_red;
Raccon little_critter = little_red;

在这种情况下,为了完成正确的设定little_critter初值设定,编译器必须合成一个copy constructor,安插一些代码以设定virtual base class pointer/offset的初值。


http://www.ppmy.cn/news/1520870.html

相关文章

ubuntu任何版本 卡死 解决办法

首先,我们一定要记得ubuntu一定不要强制关机,一定,一定 因为90% 的可能你的电脑从此就会黑屏开不了机了,然后你就可以按照我的方法去卸载,重装ubuntu系统了。/(ㄒoㄒ)/~~ (如果能解决您的问题&#xff0c…

go语言的闭包

闭包其实是匿名函数,不过与一般匿名函数不同,它要引用外部变量。 package main import "fmt"func getSum() func(int)(int){var sum int 0return func(x int) int{sum xreturn sum} } func main(){f : getSum()fmt.Println(f(1))fmt.Printl…

谷粒商城实战笔记-285~290-分布式事务

文章目录 一,285、商城业务-分布式事务-分布式CAP&Raft原理1,CAP简介2,三种常见的组合2.1 CA 模型 - 一致性 可用性2.2 CP 模型 - 一致性 分区容忍性2.3 AP 模型 - 可用性 分区容忍性 3,CAP最小必要知识4,Raft算…

Qt中的各种“q+基本数据类型“

前言 虽说Qt支持C的数据类型,但是还是用Qt自己又封装的数据类型比较好。你在支持能有我原生的支持? 正文 先看qint系列 有qint8,quint8,qint16,quint16,qint32,quint32,qint64,quint64 源码如下 解读 1. typedef signed char qint8; 说明: 定义…

【GPT】Coze使用开放平台接口-【6】Dify 也来一遍

前面讲了 coze 的相关用法,这边想着用 Dify 也来一遍,刚开始的时候接触的是 Dify,后面才是 coze。Dify 和 coze 的侧重点不同,我个人是更倾向用 Dify 构建工作流就可以了,coze 还是相对全能。 本节用 Dify 也会创建插…

MATLAB 计算凹凸多边形的面积(85)

MATLAB 计算凹凸多边形的面积(84) 一、算法介绍二、算法实现1.代码一、算法介绍 计算凹凸多边形的面积,并输出计算结果,可视化 二、算法实现 1.代码 % 设置多边形的顶点坐标 % 这里以一个五边形为例 x = [1, 3, 4

java宠物商城网站系统的设计与实现

springboot508基于Springboot宠物商城网站系统 题目:宠物商城网站系统的设计与实现 摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往…

【无标题】一起学习LeetCode热题100道(67/100)

67.寻找旋转排序数组中的最小值(学习) 已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums [0,1,2,4,5,6,7] 在变化后可能得到: 若旋转 4 次,则可以得到 …

【Linux修行路】进程通信——消息队列、信号量

目录 ⛳️推荐 一、消息队列 1.1 实现原理 1.2 消息队列接口 1.2.1 msgget——创建、获取一个消息队列 1.2.2 msgctl——释放消息队列、获取消息队列属性 1.2.3 msgsnd——发送数据 1.2.4 msgrcv——从消息队列中检索数据块 1.3 消息队列的指令操作 二、信号量 2.1 …

我写了个ffmpeg-spring-boot-starter 使得Java能剪辑视频!!

最近工作中在使用FFmpeg,加上之前写过较多的SpringBoot的Starter,所以干脆再写一个FFmpeg的Starter出来给大家使用。 首先我们来了解一下FFmpeg能干什么,FFmpeg 是一个强大的命令行工具和库集合,用于处理多媒体数据。它可以用来做…

【拉取Git项目到本地,知识小记,后续再改】

前提:Git已经安装好 https://blog.csdn.net/mukes/article/details/115693833 安装至步骤2.2.4即可 第一步创建本地项目目录 第二步获取他人提供的项目git地址或者自己在网上找的他人项目的git地址 Git 全局设置: git init git config --global user.name “ASxx”…

公寓项目(尚庭公寓笔记)

公寓项目 课程介绍项目概述移动端业务功能后台管理系统业务功能-公寓管理后台管理系统业务功能-租赁功能后台管理系统业务功能-系统管理&用户管理核心业务功能技术概述 项目开发流程项目原型数据库设计理论ER模型数据库设计流程 数据库设计实操概念模型逻辑模型公寓信息房间…

因 Mysql root 密码过于简单导致 Mysql 连接失败的解决方法

问题: Access denied for user ‘root’‘192.168.xx.xx’ (using password: YES) 用户“root”“192.168.xx.xx”的访问被拒绝(使用密码:YES) 解决方法: 1、使用root用户登录mysql,通过下面的命令给ro…

【云原生之kubernetes实战】k8s环境中部署Nginx服务

【云原生之kubernetes实战】k8s环境中部署Nginx服务 一、Nginx介绍1.1 Nginx简介1.2 Nginx特点1.3 Nginx使用场景二、本次实践介绍2.1 本次实践简介2.2 本次环境规划三、检查k8s环境3.1 检查工作节点状态3.2 检查系统pod状态四、部署storageclass(可选)4.1 配置NFS服务器4.2 …

XSS LABS - Level 16 过关思路

关注这个靶场的其他相关笔记:XSS - LABS —— 靶场笔记合集-CSDN博客 0x01:过关流程 进入靶场,右击页面,查看网页源码,搜索关键词 test 查看页面回显点: 页面只有一个回显点,跟前面关卡不同&am…

Spring Boot报错:没有配置数据源(url属性未设置)

文章目录 小结问题解决参考 小结 Spring Boot报错:没有配置数据源(url属性未设置),进行解决。 问题 Spring Boot报错: ERROR 2024-08-28 17:24:43.734 [main] - *************************** APPLICATION FAILED T…

提升多跳问答中的语言模型知识编辑能力

人工智能咨询培训老师叶梓 转载标明出处 大模型在静态知识库的更新上存在局限,特别是在面对需要多步骤推理的多跳问题时,难以提供准确和最新的回答。为了解决这一问题,来自美国佐治亚大学、纽约大学、莱斯大学、北卡罗来纳州立大学等机构的研…

flutter 提示框2 Dialog

flutter 提示框 写在点击的方法体中 child里放自己喜欢的 showDialog( context: context, builder: (BuildContext context) { final Dialog alertDialog Dialog( backgroundColor: Colors.transparent,shadowColor:Colors.transparent,child: Container(height: mediawi…

突破视觉理解极限,Qwen2-VL重磅登场

前沿科技速递🚀 经过近一年的持续努力,Qwen团队宣布推出最新一代的视觉语言模型:Qwen2-VL。基于Qwen2的基础,Qwen2-VL在多个方面实现了显著提升,相较于前代模型Qwen-VL,它具备以下核心优势: 1. …

风塔市场研究:未来几年年复合增长率CAGR为6.4%

塔架是风力涡轮机结构中的一个重要部件。它将载荷从机舱传递到地基,是决定盈利能力的重要因素:塔架越高,能量输出越高。 据QYResearch调研团队最新报告“全球风塔市场报告2024-2030”显示,预计2030年全球风塔市场规模将达到152.9亿…