Each type also defines what happens when an object of that type is created-the constructor defines the initialization of the object of that class type. Types can also control what happens when an object of that type is copied, assigned, or revoked-the class controls these behaviors through special member functions: Copy constructors, assignment operators, and destructors.
A copy constructor is a special constructor that has a single formal parameter, which is a reference to the class type, which is a common const adornment. When you define a new object and initialize it with an object of the same type, the copy constructor is used explicitly. When you pass an object of that type to a function or function that returns an object of that type, the copy constructor is implicitly used.
Destructors are complementary to constructors: destructors are automatically applied when objects that are out of scope or dynamically allocated are deleted. Destructors can be used to dispose of resources when objects are constructed or acquired during the life of an object.
The copy constructor , assignment operator , and destructor are always referred to as replication controls.
There is a particularly common case where a class is required to define its own copy control members: The class has a pointer member.
13.1. Copy Constructors
Only a single parameter, which is a reference to objects of this class type (commonly used const adornments), is called a copy constructor.
• Explicitly or implicitly initialize an object based on another object of the same type.
• Copy an object and pass it as an argument to a function.
• Copy an object when the function returns.
• Initialize the elements in the sequential container.
• Initializes an array element based on the element initializer list.
The defined form of the object
Recall that C + + supports two types of initialization (section 2nd. 3.3): Direct initialization and replication initialization. Copy initialization uses the = symbol, and direct initialization places the initialization in parentheses.
When used with class-type objects, the replication form and the direct form of initialization are different: direct initialization calls directly to the constructor that matches the argument, and replication initialization always calls the copy constructor. Copy initialization first creates a temporary object (section 7th 3.2) with the specified constructor, and then copies the temporary object to the object being created with the copy constructor:
string null_book = " 9-999-99999-9 ; // Copy-initialization string dots (10 , "); // Direct-initialization string empty_copy = string (); // Copy-initialization string empty_direct; // Direct-initialization
The
Usually direct initialization and replication initialization differ only at the low level. However, for types that do not support replication, or for further education using non-explicit constructors (section 12th 4.4), they have an intrinsic area of
:
Ifstream file1 ("filename"// ok:direct initialization" FileName"// Error:copy constructor is private// This initialization Is okay only if// the sales_item (const string&) constructor are not explicitstring
("9-999-99999-9");
Shape participation return value
The value of the argument is copied when the parameter is a non-reference type (section 7th. 2.1). Similarly, a copy of the value in the return statement is returned when the return value is a non-reference type
Initializing container elements
The copy constructor can be used to initialize the elements in the sequential container. For example, you can initialize a container with a single parameter representing the capacity (Section 3rd. 3.1). This method of constructing a container uses the default constructor and the copy constructor:
// default string constructor and five string copy constructors invokedvector<string> Svec (5
);
The compiler first uses the string default constructor to create a temporary value to initialize the Svec, and then uses the copy constructor to copy the temporary values to each element of the Svec.
Constructors and array elements
If no element initialization is provided for the class-type array, each element is initialized with the default constructor. However, if you use the regular curly braces to enclose the array initialization list (section 4th. 1.1) to provide an explicit element initializer, use copy initialization to initialize each element. Creates an element of the appropriate type based on the specified value, and then copies the value to the appropriate element with the copy constructor:
string ("0-201-16487-6"), string ("0-201-54848-8"), string ("0-201-82470-1"), Sales_item ()};
13.1.1. Synthetic copy Constructors
The behavior of the composite copy constructor is to perform a member-by-instance initialization to initialize the new object to a copy of the original object.
The simplest conceptual model for member-by-group initialization is to think of a composite copy constructor as a constructor where each data member is initialized in the constructor initialization list.
class Sales_item {// other members and constructors as beforeprivate: std:: string ISBN; int units_sold; Double revenue;};
The composition copy constructor is as follows:
Sales_item::sales_item (const Sales_item &orig): // uses string copy Constructor // copies orig.units_sold // copy orig.revenue{ // empty body
13.1.2. Defining your own copy constructors
A copy constructor is a constructor that accepts a single class type reference parameter, which is usually decorated with a const:
class Foo {public: // default constructor Foo (const// copy Constructor // ...};
For many classes, the synthetic copy constructor accomplishes only the necessary work. A class that contains only members of a class type or a built-in type (but not a pointer type), you do not have to explicitly define a copy constructor, or you can copy it.
However, some classes must control what happens when objects are copied. Such a class often has a data member that is a pointer, or has members that represent other resources that are allocated in the constructor. Other classes must do some specific work when creating new objects. In both cases, the copy constructor must be defined.
In general, the most difficult part of defining a copy constructor is recognizing the need to copy the constructor. As long as you realize that you need to copy a constructor, it is generally very simple to define a constructor function. The definition of a copy constructor is the same as the other constructors: it has the same name as the class, there is no return value, you can (and should) initialize the members of the newly created object using the constructor initialization list, and you can do any other necessary work in the body of the function.
13.1.3. Prohibit replication
Some classes require a complete ban on replication. For example, the Iostream class would not allow replication (section 8.1). If you want to suppress replication, it seems that you can omit the copy constructor, however, if you do not define a copy constructor, the compiler will synthesize one.
To prevent replication, the class must explicitly declare its copy constructor as private.
If the copy constructor is private, user code will not be allowed to replicate objects of that class type, and the compiler will reject any attempts to replicate.
However, friends and members of the class can still replicate. If you want to disallow replication in friends and members, you can declare a (private) copy constructor but not define it.
Declaring a member function without defining it is legal, but any attempt to use an undefined member will cause the link to fail. By declaring (but not defining) the private copy constructor, you can suppress any attempt to replicate a class type object: The copy attempt in user code is marked as error at compile time, and the copy attempt in the member function and friend causes an error at link time.
13.2. Assignment operators
As with classes to control how objects are initialized, the class also defines what happens when an object of that type is assigned a value:
= Accum;
As with the copy constructor, if the class does not define its own assignment operator, the compiler will synthesize one.
Introducing overloaded Assignments
Before you introduce the synthetic assignment operator, you need to know a little bit about overloaded operators
The overloaded operator is a function whose name is operator followed by the symbol of the operator that is defined. Therefore, by defining a function named Operator=, we can define the assignment. Like any other function, the operator function has a return value and a formal parameter list. The formal parameter list must have the same parameters as the number of operators (if the operator is a class member, the implicit this parameter is included). The assignment is a two-tuple operation, so the operator function has two parameters: the first parameter corresponds to the left operand, and the second parameter corresponds to the right operand.
When the operator is a member function, its first operand is implicitly bound to the this pointer. Some operators, including assignment operators, must be members of the class that defines them. Because the assignment must be a member of the class, this is bound to a pointer to the left operand. Therefore, the assignment operator accepts a single parameter, and the parameter is an object of the same class type. The right operand is generally passed as a const reference.
The return type of the assignment operator should be the same type returned by the built-in type assignment operation (5th. 4.1). The assignment operation of the built-in type returns a reference to the right operand, so the assignment operator also returns a reference to the same class type.
Synthetic assignment operators
The synthetic assignment operator is similar to the operation of the synthetic copy constructor. It performs a member-by-value assignment: Each member of the right operand object is assigned to the corresponding member of the left operand object. In addition to the divisor group, each member is assigned in the usual manner of the owning type. For arrays, assign values to each array element.
// equivalent to the synthesized assignment operator sales_item& Sales_item::operator= (const Sales_item &rhs) { // Calls string::operator= // uses built-in int assignment // uses Built-in double assignment return *this;}
Replication and assignment are often used together
In general, if a class requires a copy constructor, it will also require an assignment operator.
In fact, these two operators are treated as a unit. If one is needed, we almost certainly need another.
13.3. Destructors
One use of constructors is to obtain resources automatically. For example, a constructor can allocate a buffer or open a file, and after a resource is allocated in the constructor, a corresponding action is required to automatically reclaim or dispose of the resource.
When to call destructors
The destructor is called automatically when the class object is revoked:
// p points to default constructed object New Sales_item; { // New Scope // copy constructor copies *p into item // destructor called on object pointed to by P // exit local scope; destructor called on item
When to write an explicit destructor
Many classes do not require explicit destructors, especially classes that have constructors that do not necessarily need to define their own destructors. Destructors are only required when some work requires a destructor to complete. Destructors are typically used to release resources that are acquired in a constructor or during the lifetime of an object.
If a class requires a destructor, it also requires an assignment operator and a copy constructor, which is a useful rule of thumb. This rule is often called a three-rule, meaning that if a destructor is required, all three copy control members are required.
Composition destructor
The composition destructor revokes each non-static member in reverse order when the object is created, so that it revokes the member in the reverse sequence of declaring the member in the class. For each member of a class type, the composition destructor calls the member's destructor to undo the object.
How to write Destructors
A destructor is a member function whose name is preceded by the class name with a tilde (~), which has no return value and no formal parameters. Destructors cannot be overloaded because no formal parameters can be specified. Although you can define more than one constructor for a class, only one destructor is available that applies to all objects of the class.
An important difference between a destructor and a copy constructor or assignment operator is that, even if we write our own destructor, the composition destructor is still running.
class Sales_item {public:// empty, no work to do other than destroying the MEMBERS,// which happens automatically ~Sales_item () {}// other members as Before};
When you undo an object of type Sales_item, you run a destructor that does nothing, and when it finishes executing, the composition destructor is run to revoke the members of the class. The composition destructor calls the string destructor to undo the string member, and the string destructor frees the memory that holds the ISBN.
C++primer 13th Chapter Copy Control