关于拷贝构造函数的猜想【很久之前写的】

2024-03-19 15:58

本文主要是介绍关于拷贝构造函数的猜想【很久之前写的】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

书上对拷贝构造函数的解释我看过,是在不怎么让人信服(完全是为了考试的教育,据说是外文翻译过来的,那么这个外国作者水平也不咋滴)。

  “拷贝”这个词21世纪的人都知道,就是“复制品”的意思,那么什么是对象的拷贝呢?这个比较好理解,那就是给定一个已经赋值的对象,然后如果存在一个没有赋值的同类对象的时候就可以将已知的对象的相应内容复制过来,而不会改变已知的对象。

    以上这些大家自己想想也都能想通,但对于三个会引发拷贝构造函数调用的情况却有点莫名奇妙。其实三种情况不是偶然的,是由C++语言的本质所决定的。为什么这么说呢?我先来讨论第一种情况:

 1.  当用类的一个对象去初始化该类的另一个对象时。

   比如:

class point
{
public:
 point(int xx=0,int yy=0):X(xx),Y(yy)
 {
 }
 point(point &p);
 int getX(){return X;}
 int getY(){return Y;}
 int X;//为了验证一些问题本质,设为公有类型
 int Y;
 };

point::point(point &p)//此函数的作用是把p的作用
{
 cout<<"COPY!!!"<<endl;
}//该函数的功能就是将p的内容复制,即得到p的复制品。

 

int main()

{

  point a(1,2);

  point b(a);

}

 

 第一个其实很容易理解,就是把a(源对象)的值赋给b(目的对象)就相当于把a复制给了b。再进一步就是我的理解:b想要a的内容,a为了使自己的内容不受b的影响,于是便用一个函数(拷贝构造函数)来过渡。在我上面写的point(point&p)中b是得到了a的复制品(复制过程是用户自定义的),但是如上的情况b在得到a的引用后却没有做任何的操作。所以其实在这个赋值过后,b的内容还是没有改变(大家可以自行调试)。所以一旦添加了拷贝构造函数,那么就相当于要经过这个函数才能得到源对象的内容,那么就只有在函数体内添加点对点,值对值的赋值。才能完成整体的赋值。所以大家如果用point b=a,得到的结果也是一样的,当然不可以是这样

point b;

b=a;

为什么呢?我们要牢记一个东西:那就是以上所有的赋值都是指“赋初值”的意思,也就是说在目的对象刚建立(申明)的时候源对象才能被其拷贝。(至于为什么,这是因为构造函数的本质:是在一个对象刚建立的时候才能被调用的)而这里的b已经不是真空的了,他已经被赋了一次值。所以b=a不能称的上是赋初值了,所以无效。这时b的值就被赋为a的值了。

到这里,我想大家都应该懂了基本的原因:正是因为类中申明了拷贝构造函数,所以该类的对象有从同类对象获取其副本(或者成一定关系的伪副本:不是一对一的一般赋值)的能力(拷贝构造函数的通融)。而得到与源对象一致或者成一定关系的目的对象。所以“拷贝”的真正含义体现在获得副本上,而并非很多同学与老师所认为的“b获得了与a一样的值,这就叫‘拷贝’”。
   我在这个例子中用的拷贝构造函数是“空”的(除了一个输出外)。这就告诉程序,就采用我定义的这个“空”拷贝构造函数,而不需要它自己创建一个值对值的拷贝构造函数。
(在用户没有定义拷贝构造函数时:用户会定义这样一个拷贝构造函数:如下
    point::point(point &p)
   {
    X=p.X;
    Y=p.Y;
   }
也可以写成:
point::point(point &p):X(p.X),Y(p.Y)
{
}

  )
   知道了这些,我想对2,3种情况的分析就相当简单了。

2.如果函数的形参是类的对象,调用函数时,进行形参和实参结合时。如:

void f(point p)
{
  cout<<p.getX()<<endl;
}

这是因为,形参p正是一个临时建立的point类型。当实参向形参进行值传递的时候,便发生了跟1一样的情况。所以这也会调用拷贝函数。读者可以自己证明,当我们把函数改为

void f(point &p)
{
 p.X++;
  cout<<p.getX()<<endl;

}

这就相当与告诉了源对象“我不要你的拷贝,我要你本身!”这就是引用的强大。如此,读者会发现,如果是引用,那么如果对其进行改动的话,那么在main函数里的源对象也会发生改变。而如果不用引用,那么就算源对象的“拷贝”被改的面目全非,他自己也不会有任何改变。大家初学的时候都学过swap函数,就是这个原理。对于一般的数据类型(int,float等)之所以也这样,我想大家都会怀疑:他们不会也是这样的类吧?答案是:Yes! 他们的本质也是一种类,也定义了拷贝函数。

 int a(12);
 int b(a);
 cout<<b<<endl;

以上的写法想必很多人都没尝试过,其实也完全正确的。

3.如果函数的返回值是类的对象,函数执行完成返回调用者时。如:

point f2()
{
 point h(2,3);
 return h;
}
同理。读者自己试着推导一遍。(提示:函数的返回值其实也是相应的变量,在内存中跟同类型的变量的处理方式完全一样。return h就是相当于对返回目的变量赋初值!)
    而除去以上这点重要因素之后,就是拷贝与目的函数之间的简单赋值了。

这篇关于关于拷贝构造函数的猜想【很久之前写的】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/826511

相关文章

Java中ArrayList的8种浅拷贝方式示例代码

《Java中ArrayList的8种浅拷贝方式示例代码》:本文主要介绍Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅... 目录引言什么是浅拷贝?ArrayList 浅拷贝的重要性方法一:使用构造函数方法二:使用 addAll(

C++中第一次听到构造函数

在C++中第一次听到构造函数这个名词,在C#中又遇到了。   在创建某个类时,由于对该对象的状态(数据)不是很明确,因此需要对其进行初始化。比如说我们要在长方形这个类中创建一个对象,或者说新建一个长方形,那么我们首先要确定他的长和宽,假如我们无法确定它的长和宽,那么我们是无法造出一个长方形来的。所以就要使用这个长方形类中一个用来构造该类所有对象的函数--构造函数。由于该函数要在创建一个新对象

day45-测试平台搭建之前端vue学习-基础4

目录 一、生命周期         1.1.概念         1.2.常用的生命周期钩子         1.3.关于销毁Vue实例         1.4.原理​编辑         1.5.代码 二、非单文件组件         2.1.组件         2.2.使用组件的三大步骤         2.3.注意点         2.4.关于VueComponen

《C++中的移动构造函数与移动赋值运算符:解锁高效编程的最佳实践》

在 C++的编程世界中,移动构造函数和移动赋值运算符是提升程序性能和效率的重要工具。理解并正确运用它们,可以让我们的代码更加高效、简洁和优雅。 一、引言 随着现代软件系统的日益复杂和对性能要求的不断提高,C++程序员需要不断探索新的技术和方法来优化代码。移动构造函数和移动赋值运算符的出现,为解决资源管理和性能优化问题提供了有力的手段。它们允许我们在不进行不必要的复制操作的情况下,高效地转移资源

Linux 使用rsync拷贝文件

显示进度条 rsync 可以显示进度条,您可以使用 --progress 或 -P 选项来显示每个文件的传输进度和已完成文件的统计信息。 显示进度条的常用选项: --progress 选项 使用 --progress 显示每个文件的传输进度信息:rsync -av --progress /src/ /dest/ -a:归档模式,表示递归拷贝并保持文件权限、时间戳等。-v:详细模式,显示更

为什么构造函数不能为虚函数

1,从存储空间角度     虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数。 2,从使用角度         虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调

python基础语法十一-赋值、浅拷贝、深拷贝

书接上回: python基础语法一-基本数据类型 python基础语法二-多维数据类型 python基础语法三-类 python基础语法四-数据可视化 python基础语法五-函数 python基础语法六-正则匹配 python基础语法七-openpyxl操作Excel python基础语法八-异常 python基础语法九-多进程和多线程 python基础语法十-文件和目录操作

插件maven-search:Maven导入依赖时,使用插件maven-search拷贝需要的依赖的GAV

然后粘贴: <dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>8.0.26</version> </dependency>

JS手写实现深拷贝

手写深拷贝 一、通过JSON.stringify二、函数库lodash三、递归实现深拷贝基础递归升级版递归---解决环引用爆栈问题最终版递归---解决其余类型拷贝结果 一、通过JSON.stringify JSON.parse(JSON.stringify(obj))是比较常用的深拷贝方法之一 原理:利用JSON.stringify 将JavaScript对象序列化成为JSO

HDD 顺序和随机文件拷贝和存储优化策略

对于机械硬盘(HDD),顺序拷贝和随机拷贝涉及到磁头的移动方式和数据的读取/写入模式。理解这些概念对于优化硬盘性能和管理文件操作非常重要。 1. 顺序拷贝 定义: 顺序拷贝指的是数据从硬盘的一个位置到另一个位置按顺序连续读取和写入。这意味着数据在硬盘上的位置是线性的,没有跳跃或回溯。 特点: 磁头移动最小化:由于数据是连续的,磁头在读取或写入数据时只需要在磁盘的一个方向上移动,减少了寻道时