0
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.

    }
};

I'm currently learning C++ now, and I am kind of lost as to what is happening in the copy constructor of Police. I believe Gun's constructor only takes integers, but how do you assign *(ref.pistol) to it as a parameter? I think *(ref.pistol) is a Gun object, not an integer.

Ji Lam
  • 23
  • 3

3 Answers3

4

The compiler always implicitly declares a copy constructor if you don't explicitly declare one yourself (although in some circumstances it can be deleted). The line you're confused about calls this implicitly declared copy constructor.

This implicitly declared copy constructor is public and (if it is used) it just does a memberwise copy, i.e., it is as though you had written

public:
    Gun(const Gun& other): bullet(other.bullet) {}
Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Thank you for the clarification. Just another quick question, I realized that pistol is a private variable, but how come ' ref.pistol' compiles without any errors? – Ji Lam Jan 08 '15 at 01:30
  • 1
    @JiLam http://stackoverflow.com/questions/4117002/why-can-i-access-private-variables-in-the-copy-constructor – Brian Bi Jan 08 '15 at 01:30
1

I believe Gun's constructor only takes integers, but how do you assign *(ref.pistol) to it as a parameter? I think *(ref.pistol) is a Gun object, not an integer.

You're right, *(ref.pistol) is a Gun, not an integer. In C++ you're allowed to use certain special methods without declaring them, the compiler will generate some (hopefully) appropriate ones for you. The copy constructor is one of them.

Here in Police's copy constructor a new Gun is created with the default Gun copy constructor, and then it's assigned to this->pistol.

If you want to explicitely say that you want the default copy constructor, you can write this in Gun :

Gun(const Gun& other) = default;

The same works for the constructors, destructors, copy/move constructors and assignement operators.

tux3
  • 7,171
  • 6
  • 39
  • 51
0

*(ref.pistol) is accessing a Gun instance, so the code is trying to call Gun's copy constructor, but you have not defined one explicitly. You defined a non-default non-copy constructor only, so the compiler may omit creating a default copy constructor. You can explicitly define your own copy constructor, though:

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

Or, in C++11 and later:

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

Either way, you can use it like this (don't forget that pistol can be NULL, so you have to check for that in your Police copy constructor):

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;
    }
};

And don't forget to apply similar logic to the copy assignment operator as well (when dealing with manual deep copy implementations, don't forget the rule of 3, and the rule of 5 in C++11 and later):

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;
    }
    */
};
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Nothing is preventing the automatic generation of the Gun class' copy constructor. Note that the OP is not asking about a compile error. He's wondering why this code is working, despite the fact that there appears to be no copy constructor. – Benjamin Lindley Jan 08 '15 at 01:21