复制构造函数

来源:互联网 发布:ubuntu开机启动程序 编辑:程序博客网 时间:2024/05/22 02:00

假设定义了一个ClassDemo的类

class ClassDemo{public:    ClassDemo();    ClassDemo(int num);    ~ClassDemo();private:    int _num;};

在main函数中

CLassDemo demo = 10;demo = 20;

第一句话代表的并不是赋值,此时会调用转换构造函数。
第二句话会调用默认的赋值函数:先通过转换构造函数创建一个临时的对象,再将该对象传递给默认的赋值函数,最后析构该临时对象。
请参考构造函数讲解

如果在main函数中

ClassDemo demo = 10;ClassDemo demo1 = demo;

第二句话并非一个赋值,此时它会调用复制构造函数。

这是复制构造函数的函数原型,它会将类中的所有成员变量复制到对象中

ClassDemo(const ClassDemo &other);

复制构造函数的形参必须是一个引用,否则编译是无法通过的。如果形参不是一个引用的话,此时会产生无限递归,因为将一个对象传递到复制构造函数中时,此时会为该对象产生一个副本,而产生副本的过程就会调用复制构造函数,此时便产生了无限递归。

举个例子:
void f1(ClassDemo demo)
{
}

void f2(ClassDemo &demo)
{
}
在main函数调用这两个函数产生的结果是不一样的

ClassDemo demo;f1(demo);f2(demo);

程序在执行到f1的时候,因为f1的形参为类的对象。此时首先会调用复制构造函数创建这个对象。然后才会进入f1函数执行函数体的部分。在f1执行完之后该对象会被析构。
程序执行到f2的时候,因为传递的是一个对象的引用,此时不会有新的对象产生,复制构造函数不会执行,此时会直接执行f2函数体部分,也不会有析构函数的调用。

学到这里可以知道,在一个空类中有4个函数会被默认生成。
默认构造函数
默认析构函数
默认复制构造函数
默认赋值函

关于复制构造函数的使用:

class MyString{pubilc:    MyString(char *str):_len(strlen(str))    {        new char[_len + sizeof(char)];        strcpy(_str, str);    }    ~MyString()    {        if(_str)            delete[]_str;    }    MyString(MyString &other)    {        _str = other._str;    }    MyString& operator=(MySting &other)    {        _len = other._len;        _str = other._str;        return *this;    }    char *GetString()    {        return _str;    }private:    char *_str;};
int main(){    MyString demo = "I Have Apple";    MyString demo1 = demo;    std::cout << demo1.GetString();    demo1 = "I Have Pen";    std::cout << demo1.GetStrinf();    return 0;}

打印的结果为:
这里写图片描述

这是因为在执行demo1 = “I Have Pen”的时候会调用默认的赋值函数。
默认的赋值函数首先会创建一个临时的对象temp
然后会将该临时对象的值给demo1
即为:

MyString operator=(const MyString& temp){    _str = temp._str;    _len = temp._len;}

在该赋值函数结束后,临时对象temp会被析构掉。所以指向temp._str的空间会被delete。此时的demo1. _str所指向的空间被delete了,demo1. _str也就变成了野指针,所以打印出来的结果自然也是未知的。在vs编译器的dubug下这段空间会被填充成0xdddddddd。

所以当我们类的成员变量中存在指针的时候,使用默认的复制构造函数和默认的赋值函数时就会存在风险

这种直接对指针的赋值称为浅拷贝。使得指针易被delete,在这种情况下应当使用深拷贝来维护该成员变量的生命周期。

MyString(MyString &other){    delete[]_str;    _len = other._len;    _str = new char[_len + sizeof(char)];    strcpy(_str, other._str);}MyString& operator=(MySting &other){    delete[]_str;    _len = other._len;    _str = new char[_len + sizeof(char)];    strcpy(_str, other._str);    return *this;}

深拷贝实质上是维护了对象中所有属性的生命周期。使其生命周期和对象是同步的。

0 0
原创粉丝点击