前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >复制构造函数

复制构造函数

作者头像
小飞侠xp
发布2022-03-23 14:28:31
8130
发布2022-03-23 14:28:31
举报
文章被收录于专栏:书山有路勤为径

生成一个对象的副本有两种途径——第一种途径是建立一个新的对象,然后将一个已有对象的数据成员值取出来,赋值给新的对象。这样做虽然可行 但是实在是太麻烦了。而接下来,向大家介绍 复制构造函数 ——它的作用就是用一个已有的对象,来执行一个新的对象的构造。

复制构造函数具有一般构造函数的所有特性——它的形参是本类的一个对象的引用,作用是用一个已经存在的对象(即为函数的参数)来初始化一个新的对象。前面我们已经向大家介绍了函数具有 引用传递 的传参方式——我们可以看到,复制构造函数使用的就是引用传参。

为什么这里要使用引用来传参呢?因为我们知道,值传递就是当函数发生调用的时候,给形参分配内存空间,然后用实参的值来初始化形参——如果参数是一个对象的话,那么对于值传递来说,“初始化形参”这个过程就会造成很多额外的时间开销,浪费系统资源。而使用引用,则不会有这样的问题。

代码语言:javascript
复制
class 类名{
public:
    类名(类名& 对象名){
      //实现
    }
};

看一下一个实际的例子:现在我们有一个Point类,表示屏幕上的一个点——它包括两个int类型的私有成员x,y,表示这个点的坐标。现在我们来定义这个类的复制构造函数:

代码语言:javascript
复制
class Point{
public:
    Point(Point &p);
private:
    int x,y;
};

这里我们按照以下代码,实现复制构造函数:

代码语言:javascript
复制
Point::Point(Point &p){
    x = p.x;
    y = p.y;
}

这里我们可以注意到,复制构造函数通过一种看似“不合法”的方式,访问了Point类的实例对象p的两个私有成员变量。我们需要注意的是——private与public的区别是对类来说的,而不是对对象来说的。拷贝构造函数是Point类的成员函数——所以它可以访问类的私有成员变量,这跟具体的对象无关。

普通的构造函数(包括默认构造函数)是在对象创建的时候被调用的——而复制构造函数会在什么时候被调用呢?主要是以下的三种情况:

当用类的一个对象去初始化该类的另一个对象的时候:
代码语言:javascript
复制
Point a(1,2);
Point b(a);//用对象a初始化对象b,复制构造函数被调用
Point c = b;//用对象b给对象c赋值,复制构造函数被调用
当函数的形参是类的对象,调用函数时进行形实结合的时候:
代码语言:javascript
复制
void f(Point p){
    //code here

}
int main(){
    Point a(1,2);
    f(a);
    return 0;
}
当函数的返回值是类的对象,函数执行完成返回调用者的时候:
代码语言:javascript
复制
Point g(){
    Point a(1,2);
    return a;
}

前两种情况,应该很好理解——那么为什么在第三种情况下,返回函数值的时候也要调用复制构造函数呢?在前面的章节中,我们已经向大家介绍过——我们定义在函数中的变量,都是局部变量,当函数返回值的时候这些局部变量都被销毁了。

同样,对于在函数中创建的对象,也是如此——例子中的return a;返回的并不是a这个对象本身,而是通过复制构造函数,在主调函数中用a重新构造的对象。在函数调用返回的时候,原来的临时对象a的使命已经完成,随着整个函数中的其他临时变量一起被销毁了.

Question????

就算是不自己定义复制构造函数,编译器也可以自动帮我们生成一个隐含构造函数——而我们上面的示例中写的复制构造函数,功能跟隐含的复制构造函数其实并没有什么区别。那么问题来了——这种情况下,我们还有必要自己写一个复制构造函数吗?

的确,很多情况下我们确实没必要自己去定义一个复制构造函数——但是我们需要考虑另外一种情况:有些时候,我们并不需要复制一个对象的所有成员——就好像在复印的时候,我们有的时候只需要复印一本书的某一页,甚至某一个段落(现实中我们可以用白纸把不需要的部分盖住)。同样,对于复制构造函数来说,我们也可以自己实现一些有选择、有变化的复制——例如下面的代码,可以把每一个由复制构造得到的Point对象,横坐标增加10:

代码语言:javascript
复制
Point(Point &p){
    x = p.x+10;
    y = p.y;
}

除此之外,有的时候类的数据成员中会有 指针 类型,这个时候默认的复制构造函数能够实现的就只有 浅复制 ——这会带来数据安全上的隐患。要实现正确的复制,也就是所谓的 深复制 ,就必须重新编写复制构造函数才行。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022.03.01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 当用类的一个对象去初始化该类的另一个对象的时候:
  • 当函数的形参是类的对象,调用函数时进行形实结合的时候:
  • 当函数的返回值是类的对象,函数执行完成返回调用者的时候:
  • Question????
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档