Lesson 5 | Defining a copy constructor |
Objective | Add a constructor to the ch_stack class based on a supplied function prototype. |
C++ Designing Copy Constructor (Supplied Function Prototype)
In C++, if the copy constructor is not present, then these operations default to member-by-member initialization of value.
It is appropriate for the class to explicitly define its own copy constructor, even though the compiler provides a
default copy constructor.
Default copy constructors
The signature for the compiler's default copy constructor is:
ch_stack::ch_stack(const ch_stack&);
The compiler copies by memberwise initialization. This may not work in all circumstances for complicated aggregates with members that are themselves pointers. In many cases, the pointer is the address of an object that is deleted when going out of scope.
However, the act of duplicating the pointer value, but not the object pointed at, can lead to buggy code. This deletion affects other instances that still expect the object to exist.
If we use constructors and allow the copy constructor to be default, then we'll get shallow copy semantics. In shallow copy semantics, a new value is not created. Instead, a pointer variable is assigned the address of the existing value.
As a rule of thumb, the class provider should explicitly write out the copy constructor unless it is self-evident that memberwise copy is safe.
Always be cautious if the aggregate has any members that are pointer-based.
A class constructor is a special kind of function in a class that differs in significant respects from an ordinary function member.
A constructor is called whenever a new instance of the class is defined. It provides the opportunity to initialize the new object as it is created and
to ensure that data members contain valid values.
A class constructor always has the same name as the class. Box(), for example, is a constructor for the Box class.
A constructor does not return a value and therefore has no return type. It is an error to specify a return type for a constructor.
There is no such thing as a class with no constructors. If you do not define a constructor for a class, the compiler will supply a default constructor.
The Box class really looks like this:
class Box{
private:
double length {1};
double width {1};
double height {1};
public:
// The default constructor that is supplied by the compiler...
Box(){
// Empty body so it does nothing...
}
// Function to calculate the volume of a box
double volume(){
return length*width*height;
}
};
The default constructor has no parameters and its sole purpose is to allow an object to be created. It does nothing
else so the data members will have their default values. If there are no initial values specified for data members, they
will contain junk values. Note that when you do define a constructor, the default constructor is not supplied. There are
circumstances in which you need a constructor with no parameters in addition to a constructor that you define that
has parameters. In this case you must ensure that there is a definition for the no-arg constructor in the class.
Here is the copy constructor for ch_stack
:
//Copy constructor for ch_stack of characters
ch_stack::ch_stack(const ch_stack& str):
max_len(str.max_len),top(str.top)
{
s = new char[str.max_len];
assert(s);
memcpy(s, str.s, max_len);
}
Add a constructor to the ch_stack class based on a supplied function prototype.
Copy Constructors in C++
A constructor that takes as argument a reference to an object of the same class is termed a
copy constructor. A copy constructor is used to create a copy, or clone, of a value:
String first("Fred");
String second(first);
// second is initialized from first using copy constructor
String third = first; // Also uses copy constructor
The body of the copy constructor must do whatever is necessary to copy the value from the argument. In our example every String value manages its own dynamically allocated buffer. Therefore the copy constructor creates and initializes a new area:
String::String(const String& right)
{
len = right.length();
buffer = new char[len + 1];
for (int i = 0; i < len; i++)
buffer[i] = right[i];
buffer[len] = '\0';
}
Copy constructors are invoked whenever a new object needs to be created as an exact copy of an existing object.
This happens, for example, when an object is passed as an argument to a function that has declared a value parameter.
void print_line(String a)
{
cout << a;
a = "\n"; // Function modifies parameter variable
cout << a;
}
String name("Fred");
print_line(name); // Argument is initialized by copy constructor
cout << name;
Adding Constructor to Stack - Exercise