C++. Classes. Part 2. Copy constructor. Examples of using. Passing a class object to a function. Returning a class from a function




C++. Classes. Part 2. Copy constructor. Examples of using. Passing a class object to a function. Returning a class from a function

When considering this topic, it is recommended to read the topic:


Contents


Search other websites:

1. What is the purpose of a copy constructor?

Copy constructor – this is a special constructor which allows you to get the identical object. That is, using the copy constructor, you can get a copy of an existing object. The copy constructor is also called a copy initializer. The copy constructor should receive the constant reference (&) to the object of same class. This reference is as input parameter.

 

2. In what cases, the copy constructor is called?

The copy constructor is called in cases when you need to get a complete copy of the object. In C++, a complete copy of the object is needed in three cases.

Case 1. At the time of the declaration of a new object and its initialization with the data of another object using the = operator. The following code snippet demonstrates this situation for some class ClassName.

// declaration of an instance (object) of class ClassName
ClassName obj1;

// declaration of obj2 object with simultaneous initialization of obj2 object data
ClassName obj2 = obj1; // copy constructor is called

In this case, you need to copy the data from the obj1 object into the obj2 object. That is, you need to create a copy of the obj1 object so that this object can be used correctly in the program in the future. Therefore need a copy. This is what the copy constructor does.

Case 2. When you need to pass an object to a function as a parameter value. In this case, a complete copy of the object is created.

Case 3. When you need to return an object from a function by value. In this case, a full copy of the object is also created.

 

3. In some cases it is advisable to use the copy constructor?

The copy constructor should be used in those classes where dynamic memory allocation for data is performed. In other words, if a class has a pointer for which memory is dynamically allocated using the new operator (or other functions), then such a class must have a copy constructor. Otherwise, the program will experience problems with the disadvantages of bitwise copying. In addition, such a class must contain the operator function operator=(), which overloads the copy operator (this is another topic).

If there is no dynamic allocation of data for the class, then the copy constructor can be omitted. In this case, bitwise copying (by default) is sufficient for the class to work correctly. The exception is if during initialization of the object by another object you need to set some special copying conditions. 






 

4. Example of declaring a copy constructor in a class where there is no dynamic memory allocation

This example is for demonstration purposes. For a class where there is no dynamic memory allocation, using the copy constructor is optional.

An example. Let the class CMyPoint, describing a point on the coordinate plane, be given. The class declares several constructors, including the copy constructor.

// class CMyPoint
class CMyPoint
{
    int x, y;

    public:
    CMyPoint(void); // default constructor
    CMyPoint(int nx, int ny); // constructor with two parameters
    CMyPoint(const CMyPoint& ref_Point); // copy constructor

    // Access methods - implemented in the class
    int GetX(void) { return x; }
    int GetY(void) { return y; }
};

// implementation of class constructors (methods)
// CMyPoint class default constructor
CMyPoint::CMyPoint(void)
{
    x = y = 0;
}

// a CMyPoint class constructor with two parameters
CMyPoint::CMyPoint(int nx, int ny)
{
    x = nx;
    y = ny;
}

// copy constructor of CMyPoint class
// a reference to CMyPoint is passed
CMyPoint::CMyPoint(const CMyPoint& ref_Point)
{
    // copying data from one object into another
    x = ref_Point.x;
    y = ref_Point.y;
}

Demonstration of the use of the copy constructor in some program code (method)

// demonstrating the use of the copy constructor
CMyPoint p1(5, 8); // creating object p1, the constructor with two parameters is called
CMyPoint p2; // creating object p2 - the default constructor is called

// testing
int d;
d = p1.GetX(); // d = 5
d = p2.GetX(); // d = 0 

p2 = p1; // bitwise copying, the copy constructor is not called
d = p2.GetX(); // d = 5 - Data were copied

// a code, that calls a copy constructor
CMyPoint p3 = p1; // object initializing => the copy constructor is called
d = p3.GetX(); // d = 5

 

5. Example of passing a class object to a function as a parameter-value

In the example, an object of the CMyPoint class (see p. 4) is passed to the GetLength() function, which calculates the distance from the CMyPoint point to the origin. The function text is as follows:

// function that calculates the distance from the point to the origin
// point is an incoming parameter
double GetLength(CMyPoint mp)
{
    double length;
    int tx, ty;

    tx = mp.GetX();
    ty = mp.GetY();
    length = Math::Sqrt(tx*tx + ty*ty);

    return length;
}

Using a function in another program code

CMyPoint p1(5,5); // declare an instance of the CMyPoint class
double len;

// pass the point p1 to the function, the copy constructor is called, len = 7,07...
len = GetLength(p1);

 

6. Example of returning a class object from a function by value using the copy constructor

Implement the GetCenterPoint() function, which returns a point that is the midpoint of the segment drawn between the CMyPoint point and the origin.

The class declaration is exactly the same as in p. 4.

Implementation of two variants of functions GetCenterPoint() and GetCenterPoint2().

// function that returns the middle of a line segment
CMyPoint GetCenterPoint(CMyPoint mp)
{
    int tx, ty;
    tx = mp.GetX() / 2;
    ty = mp.GetY() / 2;

    // returning from the function, the copy constructor is not called,
    // the constructor with two parameters is called instead of it
    return CMyPoint(tx, ty);
}

// function that returns the midpoint of a segment specified by points
CMyPoint GetCenterPoint2(int x, int y)
{
    CMyPoint mp(x/2, y/2);

    // a temporary object, that is initialized with the value of mp, is created,
    // as a result, the copy constructor is called
    return mp;
    // in this case, the copy constructor is not called
    // return CMyPoint(x/2,y/2);
}

Demonstration of the use of functions

CMyPoint mp(18,-8);
CMyPoint mpC;

// the copy constructor is called when passing the parameter to the function as a value parameter
mpC = GetCenterPoint(mp); 

int cx, cy;
cx = mpC.GetX(); // cx = 9
cy = mpC.GetY(); // cy = -4

mpC = GetCenterPoint2(-9, 13); // the copy constructor is called when returning from function
cx = mpC.GetX(); // cx = -4
cy = mpC.GetY(); // cy = 6

In the first version of GetCenterPoint(), the copy constructor is called only when mp is passed by value. When you return from the GetCenterPoint() function using the return statement, the copy constructor is not called. Instead, it calls a constructor with two parameters declared in the class.

In the second version of GetCenterPoint2(), the copy constructor is called when the function returns a value by using return statement. In the return statement, a temporary object of the CMyPoint class is created, which is immediately initialized with the value of mp. As a result, the copy constructor is called.

 

7. How is copying done when there is no copy constructor in the class?

If no copy constructor is declared in the class, the copy constructor is used, which is automatically generated by the compiler. This copy constructor implements a bit-wise copy to obtain a copy of an object.

Bitwise copying is acceptable for classes in which there is no dynamic memory allocation. However, if there is dynamic memory allocation in the class (the class uses pointers), then bitwise copying will cause the pointers of both objects to point to the same memory location. But this is a mistake.

 


Related topics