复制构造函数如何执行?

时间:2019-04-24 08:21:41

标签: c++ constructor default-copy-constructor

我试图详细了解复制构造函数。这样做时,我做了下面的例子,

#include<iostream>

class Test
{
private:
        int a;
public:
        /*
        Test(const Test &t)                          // User defined copy constructor
        {
            a = t.a;
        } */
        Test()
        {
                a = 120;
        }
        int display()
        {
                return a ;
        }
        void set(int var)
        {
                a = var;
        }
};

int main()
{
        Test t1;
        std::cout << "t1.a " << t1.display() << std::endl;
        Test t2 = t1;                                           //Default copy constructor is called
        std::cout << "T2.a " << t2.display() << std::endl;
        t2.set(99);                                             //Changing the value
        std::cout << "t1.a " << t1.display() << std::endl;
        std::cout << "T2.a " << t2.display() << std::endl;
        return 0;
}

我在线阅读默认副本构造函数会进行“浅表复制”,所以这意味着,如果obj1 = obj2,即使分配后我在obj1或obj2中所做的更改 当它们指向同一位置时,需要在两个对象上均得到反映。 但是在这个例子中,当我更改一个对象的值时,它并没有反映在另一个对象中。使用用户定义的副本构造函数可获得相同的结果。

有人可以澄清这个话题吗,无论是否正在进行浅表复制!

谢谢!

4 个答案:

答案 0 :(得分:3)

浅表副本不是您通常需要记住的特殊内容。相反,这仅仅是由于使用引用或指针而发生的事情。考虑以下示例:

struct foo { 
     int* x;
};

int a = 4;
foo f{&a};

此处x指向a,如果您复制f,则新实例x将指向相同的a。多数民众赞成在浅表副本。一个深入的复制是要尊重不仅x而且x指向的内容是foo的组成部分,并且也需要复制。通常,编译器无法决定您想要什么。 x只是参考,还是x所指的foo的一部分?因此,您得到的是显而易见的:仅复制成员,而不复制它们可能引用的成员。

现在,如果您复制foo,然后修改指向x的值,那么它将修改相同的a。进行了浅拷贝。以我的经验,“深层复制”和“浅层复制”这两个术语增加了混乱而不是清晰度。您免费获得的是所有成员都被复制(无论是浅副本还是深副本)。仅当您需要更多内容(还复制pointee)时,才需要担心浅层副本与深层副本。

TL; DR:您的示例中没有深层/浅层副本。对于值,这种区别是没有意义的。使用int*来查看效果。

答案 1 :(得分:2)

  

我在线阅读默认副本构造函数会进行“浅拷贝”

这不是复制构造函数的正确思维方式。默认的复制构造函数只是复制类型中的任何成员,就像将复制构造函数依次应用于成员一样。

引用自

  

如果未删除隐式声明的副本构造函数,则为   定义(即生成和编译函数主体)   编译器(如果已使用)。对于联合类型,隐式定义的副本   构造函数复制对象表示形式(如std :: memmove所示)。对于   非联合类类型(类和结构),构造函数执行   该对象的基础成员和非静态成员的完整成员级副本,位于   他们的初始化顺序,使用直接初始化。

因此,它实际上更像是深拷贝而不是浅拷贝。

答案 2 :(得分:1)

考虑将浅表副本复制为单纯的任务。所以,

Test t2 = t1; 

表示

t2.a = t1.a

由于aint,因此如果您从a修改t1,它将不会反映在t2中。 因此,对于int来说,浅表副本确实是深表副本。

考虑案例a的类型为int*。现在t2.at1.a都指向相同的存储位置。因此,如果您修改存储位置t1.a上的值,由于t2.a实际上指向相同的位置,因此也会通过UUU反映出来。

答案 3 :(得分:0)

类的隐式定义的复制构造函数仅复制每个成员[class.copy.ctor]/14。复制成员基本上意味着,新对象的每个成员(被复制到其中的成员)都是从复制对象的相应成员中初始化的,就像编写相同的方式

T member(original.member);

其中T是成员的类型,original是要复制的对象。如果member是类类型的,这实际上可以归结为调用T的副本构造函数。但是,您的成员是普通的int,不是类类型。没有要调用的副本构造函数(int没有副本构造函数);简单地从原始对象的int初始化新对象中的int,归结为将原始int的值复制到新的int中... < / p>

您的编译器无法区分深拷贝与浅拷贝,甚至不知道“深拷贝”或“浅拷贝”的含义。在语言级别,C ++中没有深层副本或浅层副本。这些只是程序员常用的简单术语,用于讨论复制逻辑(但不是物理)包含其他对象的对象的不同方法……