复制构造函数

时间:2015-01-08 00:54:39

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

class Gun{
private:
    int bullet;
public:
    Gun(int bnum) : bullet(bnum) { }
};

class Police{
private:
    Gun * pistol;
public:
    Police(int bNum) : {
        if(bNum>0)
            pistol = new Gun(bNum);
        else
            pistol=NULL;
    }
    Police(const Police& ref){
        pistol=new Gun(*(ref.pistol)); //Confused about this part.

    }
};

我现在正在学习C ++,而且我对于警察的复制构造函数中发生的事情感到很遗憾。我相信Gun的构造函数只占用整数,但是如何将*(ref.pistol)作为参数赋值给它?我认为*(ref.pistol)是一个Gun对象,而不是整数。

3 个答案:

答案 0 :(得分:4)

如果您没有自己明确声明一个复制构造函数,编译器总是隐式声明一个复制构造函数(尽管在某些情况下可以删除它)。您对此混淆的行调用了这个隐式声明的复制构造函数。

这个隐式声明的复制构造函数是公共的,并且(如果使用的话)它只是一个成员副本,,就像你写的一样

public:
    Gun(const Gun& other): bullet(other.bullet) {}

答案 1 :(得分:1)

  

我相信Gun的构造函数只占用整数,但是如何将*(ref.pistol)指定为参数呢?我认为*(ref.pistol)是一个Gun对象,而不是整数。

你没错,*(ref.pistol)是枪,不是整数。 在C ++中,您可以使用某些特殊方法而不声明它们,编译器将为您生成一些(希望)适当的方法。复制构造函数就是其中之一。

在警察的复制构造函数中,使用默认的枪支复制构造函数创建一个新的Gun,然后将其分配给this->pistol

如果你想明确说你想要默认的复制构造函数,你可以在Gun中写这个:

Gun(const Gun& other) = default;

构造函数,析构函数,复制/移动构造函数和赋值运算符的作用相同。

答案 2 :(得分:0)

*(ref.pistol)正在访问Gun个实例,因此代码正在尝试调用Gun复制构造函数,但您尚未明确定义。您仅定义了非默认的非复制构造函数,因此编译器可能省略创建默认复制构造函数。但是,您可以显式定义自己的复制构造函数:

class Gun{
private:
    int bullet;
public:
    Gun(int bnum) : bullet(bnum) { }
    Gun(const Gun& ref) : bullet(ref.bullet) { }
};

或者,在C ++ 11及更高版本中:

class Gun{
private:
    int bullet;
public:
    Gun(int bnum) : bullet(bnum) { }
    Gun(const Gun& ref) = default;
};

无论哪种方式,您都可以像这样使用它(不要忘记pistol可以为NULL,因此您必须在Police复制构造函数中检查它:

class Police{
private:
    Gun * pistol;
public:
    Police(int bNum) {
        if(bNum>0)
            pistol = new Gun(bNum);
        else
            pistol=NULL;
    }

    Police(const Police& ref) {
        if (ref.pistol)
            pistol=new Gun(*(ref.pistol));
        else
            pistol=NULL;
    }

    ~Police() {
        delete pistol;
    }
};

并且不要忘记将相似的逻辑应用于复制赋值运算符(处理手动深层复制实现时,不要忘记rule of 3 C ++ 11及更高版本中的规则5

class Gun{
private:
    ...
public:
    ...

    // the implicit operator is sufficient in this particular example,
    // this is being shown just for demonstation purposes...
    Gun& operator=(const Gun& ref) {
        bullet = ref.bullet;
        return *this;
    }

    // or, in C++11 and later
    //Gun& operator=(const Gun& ref) = default;
};

class Police{
private:
    ...
public:
    ...

    Police& operator=(const Police& ref) {
        if (ref != *this) {
            delete pistol;
            pistol = NULL;
            if (ref.pistol)
                pistol=new Gun(*(ref.pistol));
        }
        return *this;
    }

    // alternatively:
    /*
    Police& operator=(const Police& ref) {
        if (ref != *this) {
            if (pistol) {
                if (ref.pistol) {
                    *pistol = *(ref.pistol);
                    return *this;
                }
                delete pistol;
                pistol = NULL;
            }
            if (ref.pistol)
                pistol=new Gun(*(ref.pistol));
        }
        return *this;
    }
    */
};