Reputation: 344
I am looking at an example of the PIMPL idiom, and I found a line of code I really don't understand. Since I'm new to c++, and OOP, I was hoping somebody could explain what this function does.
Can somebody clarify this function?
PublicClass::PublicClass(const PublicClass& other)
: d_ptr(new CheshireCat(*other.d_ptr)) { // <------- This line
// do nothing
}
/
Here is the example.
//header file:
class PublicClass {
public:
PublicClass(); // Constructor
PublicClass(const PublicClass&); // Copy constructor
PublicClass(PublicClass&&); // Move constructor
PublicClass& operator=(const PublicClass&); // Copy assignment operator
~PublicClass(); // Destructor
// Other operations...
private:
struct CheshireCat; // Not defined here
unique_ptr<CheshireCat> d_ptr; // opaque pointer
};
/
//CPP file:
#include "PublicClass.h"
struct PublicClass::CheshireCat {
int a;
int b;
};
PublicClass::PublicClass()
: d_ptr(new CheshireCat()) {
// do nothing
}
PublicClass::PublicClass(const PublicClass& other)
: d_ptr(new CheshireCat(*other.d_ptr)) {
// do nothing
}
PublicClass::PublicClass(PublicClass&& other)
{
d_ptr = std::move(other.d_ptr);
}
PublicClass& PublicClass::operator=(const PublicClass &other) {
*d_ptr = *other.d_ptr;
return *this;
}
PublicClass::~PublicClass() {}
Upvotes: 0
Views: 642
Reputation: 1849
C++ by default provides a copy constructor when the user does not define one: http://en.cppreference.com/w/cpp/language/copy_constructor
The line:
d_ptr(new CheshireCat(*other.d_ptr))
is simply dereferencing a pointer to an existing CheshireCat
object and copying it to instantiate a new CheshireCat
object that the d_ptr
to the instantiated object points to.
Upvotes: 1
Reputation: 169143
The expression *other.d_ptr
is parsed as equivalent to *(other.d_ptr)
. Let's take the syntax d_ptr(new CheshireCat(*other.d_ptr))
and work from the inside out to determine what it's doing:
other
-- a PublicClass const &
as declared.other.d_ptr
-- a unique_ptr<CheshireCat> const &
, a reference to the d_ptr
instance member of other
.*other.d_ptr
-- the invocation of operator*
on the unique_ptr
object, which will yield a result of type CheshireCat const &
(a reference to the object that the unique_ptr
object owns).new CheshireCat(*other.d_ptr)
-- takes this CheshireCat const &
and heap-allocates a new CheshireCat
object by invoking the copy constructor of the CheshireCat
type. This expression is of type CheshireCat *
.d_ptr(new CheshireCat(*other.d_ptr))
-- constructs the d_ptr
member of the PublicClass
object being constructed, using the CheshireCat *
value. (This is the initializer list of this particular PublicClass
constructor.)In other words, all this line is doing is copying the CheshireCat
object owned by the other
instance, and giving ownership of that copy to the PublicClass
object that is being constructed.
Upvotes: 1
Reputation: 27538
Structs do not "take values". Functions takes values. Constructors are functions. In new CheshireCat(*other.d_ptr)
, you invoke the compiler-generated copy constructor of CheshireCat
.
You also do not pass a pointer but a reference, because you dereference other.d_ptr
via the overloaded operator*
of std::unique_ptr
. In fact, if you wrote new CheshireCat(other.d_ptr)
or new CheshireCat(other.d_ptr.get())
, then you would get a compilation error.
Upvotes: 2