. What is a copy constructor?
First, for common objects, copying between them is very simple, for example:
[C-sharp]
Int a = 100;
Int B =;
Different from common objects, class objects have complicated internal structures and various member variables.
The following is a simple example of copying a class object.
[C-sharp]
# Include <iostream>
Using namespace std;
Class CExample {
Private:
Int;
Public:
// Constructor
CExample (int B)
{A = B ;}
// General functions
Void Show ()
{
Cout <a <endl;
}
};
Int main ()
{
CExample A (100 );
CExample B = A; // note that during object initialization, you must call the copy constructor instead of assigning values.
B. Show ();
Return 0;
}
Run the program and output 100 on the screen. From the running results of the above code, we can see that the system allocates memory for object B and completes the replication process with object. For class objects, class objects of the same type are copied to the constructor to complete the entire replication process.
The following example describes how to copy constructors.
[C-sharp]
# Include <iostream>
Using namespace std;
Class CExample {
Private:
Int;
Public:
// Constructor
CExample (int B)
{A = B ;}
// Copy the constructor
CExample (const CExample & C)
{
A = C.;
}
// General functions
Void Show ()
{
Cout <a <endl;
}
};
Int main ()
{
CExample A (100 );
CExample B = A; // CExample B ();
B. Show ();
Return 0;
}
CExample (const CExample & C) is our custom copy constructor. It can be seen that a copy constructor is a special constructor. The name of a function must be the same as the class name. A required parameter is a reference variable of the current type.
Ii. Time for copying Constructors
In C ++, the following three objects need to call the copy constructor!
1. The object passes in function parameters as a value.
[C-sharp]
Class CExample
{
Private:
Int;
Public:
// Constructor
CExample (int B)
{
A = B;
Cout <"creat:" <a <endl;
}
// Copy Structure
CExample (const CExample & C)
{
A = C.;
Cout <"copy" <endl;
}
// Destructor
~ CExample ()
{
Cout <"delete:" <a <endl;
}
Void Show ()
{
Cout <a <endl;
}
};
// Global function. The input is an object.
Void g_Fun (CExample C)
{
Cout <"test" <endl;
}
Int main ()
{
CExample test (1 );
// Input object
G_Fun (test );
Return 0;
}
When g_Fun () is called, the following important steps are taken:
(1) When the test object passes in the form parameter, a temporary variable will be generated first, which is called C.
(2). Then call the copy constructor to give the value of test to C. The two steps are a bit like: CExample C (test );
(3). After g_Fun () is executed, the C object is parsed.
2. The object is returned from the function by passing the value.
[C-sharp]
Class CExample
{
Private:
Int;
Public:
// Constructor
CExample (int B)
{
A = B;
}
// Copy Structure
CExample (const CExample & C)
{
A = C.;
Cout <"copy" <endl;
}
Void Show ()
{
Cout <a <endl;
}
};
// Global functions
CExample g_Fun ()
{
CExample temp (0 );
Return temp;
}
Int main ()
{
G_Fun ();
Return 0;
}
When the g_Fun () function executes return, the following important steps are taken:
(1). A temporary variable will be generated first, which is XXXX.
(2). Then call the copy constructor to send the temp value to XXXX. The two steps are a bit like: CExample XXXX (temp );
(3) analyze the temp local variable at the end of function execution.
(4). parse the XXXX object after g_Fun () is executed.
3. The object needs to be initialized through another object;
[C-sharp]
CExample A (100 );
CExample B =;
// CExample B ();
The next two statements call the copy constructor.
Iii. Shallow copy and deep copy
1. Default copy constructor
Most of the time, if we do not know how to copy constructors, it is good to pass objects to function parameters or return objects, this is because the compiler will automatically generate a copy constructor, which is the "Default copy constructor". This constructor is very simple, only use the value of the data member of the "old object" to assign values to the data member of the "new object". It generally takes the following form:
[C-sharp]
Rect: Rect (const Rect & r)
{
Width = r. width;
Height = r. height;
}
Of course, the above Code does not need to be written, and the compiler will automatically generate for us. However, if we think this will solve the object replication problem, it will be wrong. Let's consider the following code:
[C-sharp]
Class Rect
{
Public:
Rect () // constructor, counter plus 1
{
Count ++;
}
~ Rect () // destructor, counter minus 1
{
Count --;
}
Static int getCount () // returns the counter value
{
Return count;
}
Private:
Int width;
Int height;
Static int count; // a static member acts as a counter
};
Int Rect: count = 0; // initialize the counter
Int main ()
{
Rect rect1;
Cout <"The count of Rect:" <Rect: getCount () <endl;
Rect rect2 (rect1); // use rect1 to copy rect2. At this time, there should be two objects
Cout <"The count of Rect:" <Rect: getCount () <endl;
Return 0;
}
This Code adds a static member to the previous class to count. In the main function, first create the object rect1, output the number of objects at this time, then use rect1 to copy the object rect2, and then output the number of objects at this time, according to understanding, at this time, two objects should exist, but when the actual program runs, the output is 1, reflecting that only one object exists. In addition, when an object is destroyed, because two objects are called and destroyed, the class destructor call twice, and the counter changes to a negative number.
To put it bluntly, the copy constructor does not process static data members.
The most fundamental cause of these problems is that the counter does not increase progressively when copying objects. We re-compile the copy constructor, as shown below:
[C-sharp]
Class Rect
{
Public:
Rect () // constructor, counter plus 1
{
Count ++;
}
Rect (const Rect & r) // copy constructor
{
Width = r. width;
Height = r. height;
Count ++; // Add 1 to the counter
}
~ Rect () // destructor, counter minus 1
{
Count --;
}
Static int getCount () // returns the counter value
{
Return count;
}
Private:
Int width;
Int height;
Static int count; // a static member acts as a counter
};
2. Shallow copy
The so-called shallow copy refers to the simple assignment of only data members in the object during object replication. By default, the copy constructor executes the shortest copy function. In most cases, "Shallow copy" can work well, but once the object has dynamic members, there will be problems with the shallow copy. Let's consider the following code:
[C-sharp]
Class Rect
{
Public:
Rect () // constructor. p points to a space allocated in the heap.
{
P = new int (100 );
}
~ Rect () // destructor to release the dynamically allocated space
{
If (p! = NULL)
{
Delete p;
}
}
Private:
Int width;
Int height;
Int * p; // a pointer member
};
Int main ()
{
Rect rect1;
Rect rect2 (rect1); // copy an object
Return 0;
}
A running error occurs before the code is executed. The reason is that during object replication, the dynamically allocated content is not correctly operated. Let's analyze:
After running the definition rect1 object, since there is a dynamically allocated statement in the constructor, the memory after execution is roughly as follows:
When rect1 is used to copy rect2, the value of the member is assigned only because the shortest copy is executed. In this case, rect1.p = rect2.p, that is, the two pointers point to the same space in the heap, as shown in:
Of course, this is not the expected result. When the object is destroyed, the destructor of the two objects will release the same memory twice, which is the cause of the error. What we need is not that two p values have the same value, but that two p points to the space with the same value. The solution is to use "Deep copy ".
3. Deep copy
In the case of "Deep copy", for dynamic members of an object, it is not just a simple assignment, but a dynamic allocation of space should be performed, the above example should be processed as follows:
[C-sharp]
Class Rect
{
Public:
Rect () // constructor. p points to a space allocated in the heap.
{
P = new int (100 );
}
Rect (const Rect & r)
{
Width = r. width;
Height = r. height;
P = new int; // dynamically allocate space for the new object
* P = * (r. p );
}
~ Rect () // destructor to release the dynamically allocated space
{
If (p! = NULL)
{
Delete p;
}
}
Private:
Int width;
Int height;
Int * p; // a pointer member
};
After copying an object, the memory usage is roughly as follows:
In this case, the p of rect1 and the p of rect2 point to a memory space, but they point to the same content, which is called "Deep copy ".
3. prevent default copy
Through the analysis of object replication, we found that most object replication occurs when "value transfer". Here is a small trick to prevent passing by value -- declaring a private copy constructor. You don't even need to define this copy constructor. Because the copy constructor is private, if you try to pass by value or the function returns this class object, a compilation error is returned, this prevents passing or returning objects by value.
[C-sharp]
// Prevent passing by value
Class CExample
{
Private:
Int;
Public:
// Constructor
CExample (int B)
{
A = B;
Cout <"creat:" <a <endl;
}
Private:
// Copy the structure, just declare
CExample (const CExample & C );
Public:
~ CExample ()
{
Cout <"delete:" <a <endl;
}
Void Show ()
{
Cout <a <endl;
}
};
// Global functions
Void g_Fun (CExample C)
{
Cout <"test" <endl;
}
Int main ()
{
CExample test (1 );
// G_Fun (test); passing by value will cause an error
Return 0;
}
4. Copy the constructor details
1. Can I call private member variables in the copy constructor?
A: This question was posted on the Internet. It was a bit dizzy at the time. At that time, we will know from the name that the copy constructor is a special constructor at that time, and the operation is still the member variable of the class, so it is not restricted by private.
2. Which of the following functions is a copy constructor? Why?
[C-sharp]
X: X (const X &);
X: X (X );
X: X (X &, int a = 1 );
X: X (X &, int a = 1, int B = 2 );
A: For a class X, if the first parameter of a constructor is one of the following:
A) X &
B) const X &
C) volatile X &
D) const volatile X &
If no other parameters or other parameters have default values, this function is a copy constructor.
[C-sharp]
X: X (const X &); // copy the constructor.
X: X (X &, int = 1); // copy the constructor.
X: X (X &, int a = 1, int B = 2); // Of course, it is also a copy constructor.
3. Can there be more than one copy constructor in a class?
A: more than one copy constructor can exist in the class.
[C-sharp]
Class X {
Public:
X (const X &); // const copy Structure
X (X &); // non-const copy Structure
};
NOTE: If only one copy constructor with the parameter X & exists in a class, the object of const X or volatile X cannot be used for copy initialization.
[C-sharp]
Class X {
Public:
X ();
X (X &);
};
Const X cx;
X x = cx; // error
If a copy constructor is not defined in a class, the compiler automatically generates a default copy constructor.
This default parameter may be X: X (const X &) or X: X (X &), which is determined by the compiler based on the context.