C++复制构造函数

1.体验构造函数

C ++里的类有默认构造函数,自己定义的构造函数,允许通过类构造函数实现类的类型的隐式转换或者显示转换(构造函数前带explicit关键字),比如如下代码Jungle定义了一个类A,定义了两个构造函数:

using namespace std;

class A
{
public:
    A()
    {
        index++;
        age = -1;
        Num = -1;
        cout<<"A()默认构造函数0"<<endl;
    }
    A(int iAge,int iNum = 0)
    {
        index++;
        age = iAge;
        Num = iNum;
        cout<<"A()默认构造函数1"<<endl;
    }
    ~A()
    {
    }
    void print()
    {
        cout<<"Index="<<index<<"  Value:\t age = "<<age<<", Num = "<<Num<<endl;
    }
    ///用于A创建的对象计数
    static int index;
private:
    int age;
    int Num;
};

int A::index = 0;

int _tmain(int argc, _TCHAR* argv[])
{
    ///默认无参构造函数
    A x1;
    x1.print();
    ///默认带参构造函数
    A x2(100);
    x2.print();
    ///默认带参构造函数
    A x3 = A(29,3);
    x3.print();
    ///默认带参构造函数
    A x4(10);
    x4.print();
    ///隐式类型转换:将int型转换为A类型,因为定义了带默认参数的构造函数1
    A x5 = 123;
    x5.print();

    A x6 = x5;

    getchar(); 
    return 0;
}

main函数里通过不同的初始化方式来调用A的构造函数,并且打印各个对象的值,运行结果如下:
这里写图片描述
可以看到,不同的初始化方式会调用不同的构造函数,类的静态成员变量index计数对象的个数。
但是奇怪的是x6并没有调用构造函数?
接下来我们把x6的值打印出来看看:

int _tmain(int argc, _TCHAR* argv[])
{
    ///默认无参构造函数
    A x1;
    x1.print();
    ///默认带参构造函数
    A x2(100);
    x2.print();
    ///默认带参构造函数
    A x3 = A(29,3);
    x3.print();
    ///默认带参构造函数
    A x4(10);
    x4.print();
    ///隐式类型转换:将int型转换为A类型,因为定义了带默认参数的构造函数1
    A x5 = 123;
    x5.print();

    A x6 = x5;
    x6.print();

    getchar(); 
    return 0;
}

这里写图片描述
不仅成员变量的值与x5相同,连计数index都相同!!!
但明显x5和x6是两个对象。那么为什么x5没有调用上述两个构造函数(甚至是默认构造函数呢?)这就是调用了复制构造函数!其原型为:
A(const A& iA)

2.复制构造函数

  • 什么时候会调用复制构造函数?
  • 当新建一个对象,并将其初始化为同类已有对象时,将会调用复制构造函数。下列情况都会调用复制构造函数:
    A x5 = 123;
    x5.print();
    //x5是已有的对象
    A x6 = x5;
    A x7(x5);
    A x8 = A(x5);
    A *x9 = new A(x5);
  • 复制构造函数的“复制”机制是?
  • 打印x5与x6的成员变量的值来看,复制构造函数是将已有对象(x5)里的非静态成员变量的值逐个复制,成为浅复制
  • 浅复制会不会有问题?
  • 对于有指针的情况,会出现很大的问题。比如我们修改类A如下—增加一个成员变量char指针,并在构造函数里用new分配内存,在析构函数里用delete释放:
class A
{
public:
    A()
    {
        index++;
        age = -1;
        Num = -1;
        len = 0;
        pt = new char[1];
        pt = "\0";
        cout<<"A()默认构造函数0"<<endl;
    }
    A(int iAge,int iNum, char* s)
    {
        index++;
        age = iAge;
        Num = iNum;
        len = strlen(s);
        pt = new char[len +1];
        strcpy(pt, s);
        cout<<"A()默认构造函数1"<<endl;
    }
    ~A()
    {
        --index;
        delete []pt;
        cout<<"析构函数"<<endl;
    }
    void print()
    {
        cout<<"Index="<<index<<"  Value:\t age = "<<age<<", Num = "<<Num<<" 字符串值:"<<pt<<endl;
    }
    ///用于A创建的对象计数
    static int index;
private:
    int age;
    int Num;
    char *pt;
    int len;
};

int A::index = 4;

int _tmain(int argc, _TCHAR* argv[])
{
    A x5 = A(123,10,"Jungle");
    x5.print();

    {
        A x6 = x5;
        x5.print();
    }///代码块结束,x6将被析构
    A x7(x5);
    x5.print();
    A x8 = A(x5);
    x5.print();
    A *x9 = new A(x5);
    x5.print();

    getchar(); 
    return 0;
}

运行结果如下:
这里写图片描述
可以看到,打印结果完全不像想象中那样了,甚至出现了乱码!!
分析如下:
A x6=x5; 这一行代码将调用复制构造函数,采用浅复制,包括复制指针。但是指针只是x5中字符串”Jungle”的地址,而不是内容!!,因此x6对象的成员变量x6.pt和x5.pt指向同一个地址。在x6 代码块结束(大括号结束)时,x6对象将被释放,pt指向的地址被delete了,因此x5里的字符串”Jungle”也不在内存中了!至于后面的代码,更是不能运行了,所以出现了乱码。
- 如何解决上述情况呢?
- 用户自己定义复制构造函数

A(const A& iA)
    {
        index++;
        age = iA.age;
        Num = iA.Num;
        len = strlen(iA.pt);
        pt = new char[len+1];
        std::strcpy(pt,iA.pt);
        cout<<"A()复制构造函数2"<<endl;
    }

接下来运行,就不会出错了:
这里写图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冯Jungle

您的支持是对我最大的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值