![]() |
|||||||||
4.9 Copy Constructors |
|||||||||
|
A copy constructor is a constructor that has a certain, fixed signature. Like other constructors, the copy constructor cannot be called explicitly, but only implicitly when the C++ language dictates that a copy of an object is required. If a class does not define a copy constructor, a default copy constructor is used that performs a byte-by-byte copy from the existing object to the new object. In many simple cases the default copy constructor is adequate. However, as the examples below will show, the default copy constructor is often inadequate. In addition, many consider it good style to always define a copy constructor even if it has the same effect as the default copy constructor. The first of two circumstances under which a copy constructor is implicity used is when a new object is declared and initialized using an existing object. This circumstance is illustrated in the following code:
Frame window1("First", Location(100, 100), Shape (200,300));
Frame window2("Second", Location(100, 100), Shape (200,300));
Message originalMsg("Hello World");
Message copiedMsg( originalMsg ); // copy constructor used
// to initialize new object
In this example, the declaration of the Message object copiedMsg
uses the copy constructor defined for the Message class. The initial
values for the data members of the object copiedMsg are initialized
based on the data members in the object originalMsg. The second
circumstance where a copy constructor is implicitly used is when
an object is passed as a parameter by-copy. This circumstance
is illustrated in the case of the StatusLine class defined below.
When either the StatusLine constructor or its SetStatus method
is used, a copy of the Message parameter is made because both
of these parameters are passed by-copy.
class Message {
private:
char* message;
...
public:
...
~Message(); // delete message
};
Message::~Message(){ delete message; }
When a copy of a Message object is made using the default copy constructor, the pointer (message), but not the string to which it points, is copied. This default copying results in the following situation:
Both objects point to the same place in memory. As long as both objects exist, there is no problem. However, if either of the objects is deleted, the character string will be deallocated by that object's destructor, leaving the other object pointing to a place in memory that has an undefined content. The errors that can result from this situation are as follows. In the case above, the first call on the Display method will create a copy of the originalMsg object. This copy will be destructed at the end of the Display method. Thus, both the originalMsg object and the copiedMsg object are pointing to memory with undefined content. When the second call on Display is made one of three things can happen:
The copy constructor for the Message class illustrates how a copy constructor is defined:
class Message {
private:
...
public:
Message(const Message& other); // copy constructor
};
The copy constructor has a single argument - a reference to an object of the same class (i.e., the Message class in this case) that is not changed (i.e., it is declared const). The input argument (other) is declared const because the copy constructor does not need to change the argument to initialize the new object. The code for the Message class's copy constructor is:
Message::Message(const Message& other) {
message = copystring(other.message); }
This constructor copies the character string that is defined by the other object. In this case, when each object is destructed only its own copy of the character string will be deleted. No memory leaks are created and no dangling pointers occur.
Tasks
|
|||||||||
|
|||||||||