C++对象模型(14)-- 构造函数语义学:拷贝构造函数和赋值运算赋

1、拷贝构造函数

1.1 什么是拷贝构造函数

拷贝构造函数是一种构造函数,它的功能是创建新对象。也就是说对象还没生成,这时利用另一个对象的拷贝来生成新的对象。

class MyDemo {
public:
    // 默认构造函数
    MyDemo(){}

    // 拷贝构造函数
    MyDemo(const MyDemo& _demo) {
        cout << "copy constructor is called" << endl;
    }
};

int main()
{
    MyDemo demoA;
    MyDemo demoB = demoA;

    return 0;
}

例子中的:MyDemo demoB = demoA; 语句调用的就是拷贝构造函数。

1.2、默认拷贝构造函数生成规则

(1)包含一个类类型的成员变量,且成员变量所属的类有拷贝构造函数。

(2)其父类有拷贝构造函数。

(3)类有虚函数。

(4)类继承虚基类。

这几条生成规则,跟默认构造函数的生成规则相似。因为拷贝构造函数也是一种构造函数,这几条规则的出发点是为了保证类对象的完整性。

1.3 用到拷贝构造函数的3种场景

(1)用 = 号直接赋值

int main()
{
    MyDemo demoA;
    MyDemo demoB = demoA;

    return 0;
}

(2)函数参数传递

所以拷贝构造函数必须以引用的方式传递参数。这是因为,在值传递的方式传递给一个函数的时候,会调用拷贝构造函数生成函数的实参。如果拷贝构造函数的参数仍然是以值的方式,就会无限循环的调用下去,直到函数的栈溢出。

void test(MyDemo _demo){ }

int main()
{
    MyDemo demoA;
    MyDemo demoB;
    demoB.test(demoA);

    return 0;
}

(3)函数返回值

MyDemo getDemo() {
    MyDemo demo;
    return demo;
}

int main()
{
    MyDemo demoA;
    demoA.getDemo();

    return 0;
}

(4)用花括号列表初始化一个数组中的元素

int main()
{
    MyDemo demoA;
    MyDemo demoArr = { demoA };

    return 0;
}

(5)标准库容器调用insert或push添加成员时

2、赋值运算符

当对象都已经生成,把另一个对象赋值给这个对象时,会调用赋值运算符。

class MyDemo {
public:
    // 默认构造函数
    MyDemo(){}

    // 拷贝构造函数
    MyDemo(const MyDemo& _demo) {
        cout << "copy constructor is called" << endl;
    }

    // 赋值运算符
    MyDemo& operator = (const MyDemo& _demo) {
        cout << "operator = is called" << endl;

        return *this;
    }
};

int main()
{
    MyDemo demoA;
    MyDemo demoB;
    demoB = demoA;

    return 0;
}

调用的是拷贝构造函数还是赋值运算符,主要是看是否有新的对象产生。如果产生了新的对象,那调用的就是拷贝构造函数;如果没有,那就是对已有的对象赋值,调用的是赋值运算符。

3、浅拷贝和深拷贝

3.1 浅拷贝

当一个类中有指针变量时,如果只拷贝了指针的值,而指针所指向的地址并没有拷贝过来,这种拷贝就叫做浅拷贝。

class MyDemo {
public:
    MyDemo() {
        pm_i = new int(3);
    }

    ~MyDemo() {
        delete pm_i;
    }

    int* pm_i;
};

int main()
{
    MyDemo demoA;
    MyDemo demoB(demoA);

    return 0;
}

运行上面的代码,发现会报错。为什么呢?

因为对象demoB和demoA的指针pm_i都指向了同一个地址,这样的话指针pm_i所指向的地址会被delete两次,所以就会报错。

3.2 深拷贝

当类含有指针变量时,在拷贝构造函数中应该为指针变量重新申请一块内存空间,并把相应的值拷贝到该内存中,这种拷贝就叫深拷贝。

MyDemo(const MyDemo& _demo) {
    pm_i = new int(5);
    memcpy(pm_i, _demo.pm_i, sizeof(int));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值