现在的位置: 首页 > 综合 > 正文

Copy Constructor

2018年02月16日 ⁄ 综合 ⁄ 共 1623字 ⁄ 字号 评论关闭
1,对象本体 与 实体
    例如:
        int a = 1;
        a 本体
        1 实体
        本体与实体一致。
        int* a, b = 1;
        a = &b;
        a 本体
        a所指向的空间 实体
        本体与实体不一致。
2,当对象本体与实体一致时,如:
    class Person
    {
        int age;
    public:
        Person(int arg = 18):age(arg){ cout << "Constructing." <<  endl; }
        ~Person(){ cout << "Deconstructing." << endl; }
    };

    int main()
    {
        Person p1(20);
        Person p2(p1); // 或Person p2 = p1;

        return 0;
    }
    输出:
    Constructing
    Deconstructing
    Deconstructing
    会只调用构造函数一次,但调用析构函数两次。实际上,当定义p1时,会调用构造函数,此时输出一次"Constructing.",而当以p1创建p2时,不会调用构造函数,会直接把p1的本体拷贝给p2。对于Person类而言,本体与实体一致,故Person p1(20); Person p2(p1);相当于:int a = 1; int b = a;。
3,当对象本体与实体不一致时,如:
    运行结果:
    在上述代码中,我们在类的构造函数中为成员变量pName创建了内存,在析构函数中进行释放。运行结果表明程序出错。这是因为当我们直接使用对象p1来创建对象p2时,并不会再次调用构造函数,也就不会为p2的成员变量pName分配内存,而是直接将本体进行了复制,即只复制了p1的成员变量pName的值而已。故而,当析构了p2再析构p1时,之前的内存已经被释放了,p1对象再释放内存时内存是不存在的,最终导致程序运行出错。这说明,的确只是将本体进行了复制而已。当本体与实体一致时,程序运行还正常,当不一致时,就会出错。
4,注意:当使用赋值(=)或p2(p1)这种形式创建对象时,也会创建相应的对象,只是对于成员变量中本体与实体不一致的情况,会仅仅进行本体的复制。见如下代码:
    运行结果如下:
    我们看到,两个对象的地址不一样。我们知道this其实是一个隐含的指针,指向调用对象,比如:myclass my;,则this实际上就是指向my的指针,所存储的就是my的地址。所以,此处输出的this里的值不一样,说明的确是创建了新的对象,而且把本体与实体一致的参数Age的值进行了正确的复制。
但是,但类的成员变量中有本体与实体不一样的情况时,就会出错,看如下代码:
    毫无疑问,程序出错。结果如下:
    从结果中看到,当p2修改了姓名后,实际上修改的是p1的姓名,也就是说,实际上并没有为p2存储姓名分配空间,仅仅是将p1的pName值进行了简单复制。这就是本体与实体不一致的情况,如下图所示:
    那么,对于本体与实体一致的情况,真的为p2中的变量分配内存了么?我们修改一下程序,输出相关内容进行验证。
    程序修改如下:
    运行结果:
    运行结果说明,的确创建了对象,而且当本体与实体一致时,对象的复制操作也没有问题。当不一致时,就会导致仅仅把本体进行了复制,将通过复制创建的对象中的本体也指向了被复制的对象,造成错误。
5,不一致的情况还想拷贝创建对象,怎么办?
    此时可以通过重写拷贝构造函数来完成目的。
    程序如下:
    拷贝构造函数本身是构造函数的重载,需要注意的是,拷贝构造函数的参数必须是该类对象的常量引用,并且,和默认构造函数一样,提供了拷贝构造函数后,默认的拷贝构造函数就不存在了。钱老爷子说,自定义的对象作为参数传递时,能用引用就用引用,能用常量引用的尽量使用常量引用
    当对象的本体与实体不一致时,自定义拷贝构造函数才具有意义,否则,默认拷贝构造函数就够用了。
6,注意:

抱歉!评论已关闭.