С++. Конструктор копирования. Примеры использования. Передача объекта класса в функцию. Возврат класса из функции

С++. Конструктор копирования. Примеры использования. Передача объекта класса в функцию. Возврат класса из функции

В данной теме рассмотрена работа конструктора копирования на примере unmanaged (native) классов. При рассмотрении данной темы рекомендуется прочитать тему:


Содержание



1. Какое назначение конструктора копирования (copy constructor)? Пример

Это специальный конструктор, который позволяет получить идентичный к заданному объект. То есть, с помощью конструктора копирования можно получить копию уже существующего объекта. Конструктор копирования еще называется инициализатором копии (copy initializer). Конструктор копирования должен получать входным параметром ссылку (&) на объект такого же класса.

Конструктор копирования вызывается при инициализации объекта класса в момент его объявления.

Пример. Пусть задан класс CMyPoint, описывающий точку на координатной плоскости. В классе объявляется несколько конструкторов, в том числе и конструктор копирования.

// класс CMyPoint
class CMyPoint
{
    int x, y;

    public:
    CMyPoint(void); // конструктор класса по умолчанию
    CMyPoint(int nx, int ny); // конструктор класса с двумя параметрами
    CMyPoint(CMyPoint & ref_Point); // конструктор копирования

    // методы доступа - реализованы в классе
    int GetX(void) { return x; }
    int GetY(void) { return y; }
};

// реализация конструкторов (методов) класса
// конструктор класса CMyPoint
CMyPoint::CMyPoint(void)
{
    x = y = 0;
}

// конструктор класса CMyPoint с двумя параметрами
CMyPoint::CMyPoint(int nx, int ny)
{
    x = nx;
    y = ny;
}

// конструктор копирования класса CMyPoint
// передается ссылка на CMyPoint
CMyPoint::CMyPoint(CMyPoint & ref_Point)
{
    // копирование данных из одного объекта в другой
    x = ref_Point.x;
    y = ref_Point.y;
}

Демонстрация использования конструктора копирования в некотором программном коде (методе)

// демонстрация использования конструктора копирования
CMyPoint p1(5, 8); // создание объекта p1
CMyPoint p2; // создание объекта p2 - вызывается конструктор по умолчанию

// проверка
int d;
d = p1.GetX(); // d = 5
d = p2.GetX(); // d = 0

p2 = p1; // побитовое копирование, конструктор копирования не вызывается
d = p2.GetX(); // d = 5 - данные были скопированы, но без использования конструктора копирования

// код, который вызывает конструктор копирования
CMyPoint p3 = p1; // инициализация объекта => вызывается конструктор копирования
d = p3.GetX(); // d = 5

2. В каких случаях целесообразно использовать конструктор копирования?

Конструкторы копирования очень важны. В классе обязательно должен быть объявлен конструктор копирования в случаях, если нужно:

  • создать копию объекта класса (смотрите предшествующий пункт) в момент его объявления;
  • передать объект класса в некоторую функцию как параметр-значение (см. пример ниже);
  • если нужно возвратить объект класса по значению (см. пример ниже).

3. Пример передачи объекта класса в функцию как параметр-значение

В примере передается объект класса CMyPoint (см. п.1) в функцию GetLength(), которая вычисляет расстояние от точки CMyPoint к началу координат. Текст функции следующий:

// функция, которая вычисляет расстояние от точки до начала координат
// точка есть входящим параметром
double GetLength(CMyPoint mp)
{
    double length;
    int tx, ty;

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

    return length;
}

Использование функции в другом программном коде

CMyPoint p1(5,5); // объявить экземпляр класса CMyPoint
double len;

// передача точки p1 в функцию, вызывается конструктор копирования, len = 7,07...
len = GetLength(p1);

4. Пример возврата объекта класса из функции по значению с помощью конструктора копирования

Реализовать функцию GetCenterPoint(), которая возвращает точку, которая есть серединой отрезка, проведенного между точкой CMyPoint и началом координат.

Объявление класса точно такое же как в п. 1.

Реализация двух вариантов функций GetCenterPoint() и GetCenterPoint2().

// функция, которая возвращает середину отрезка
CMyPoint GetCenterPoint(CMyPoint mp)
{
    int tx, ty;
    tx = mp.GetX() / 2;
    ty = mp.GetY() / 2;

    // возврат из функции, конструктор копирования не вызывается, 
    // вместо него вызывается конструктор с двумя параметрами
    return CMyPoint(tx, ty);
}

// функция, которая возвращает середину отрезка, заданного точками
CMyPoint GetCenterPoint2(int x, int y)
{
    CMyPoint mp(x/2, y/2);

    // создается временный объект, который инициализируется значением mp,
    // в результате вызывается конструктор копирования
    return mp;

    // в этом случае конструктор копирования не вызывается
    // return CMyPoint(x/2,y/2);
}

Демонстрация использования функций

CMyPoint mp(18,-8);

CMyPoint mpC;

// вызывается конструктор копирования при передаче параметра в функцию как параметра-значения
mpC = GetCenterPoint(mp); 

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

mpC = GetCenterPoint2(-9, 13); // вызывается конструктор копирования при возврате из функции
cx = mpC.GetX(); // cx = -4
cy = mpC.GetY(); // cy = 6

В первом варианте GetCenterPoint() конструктор копирования вызывается только при передаче параметра mp по значению. При возврате из функции GetCenterPoint() с помощью оператора return, конструктор копирования не вызывается. Вместо него вызывается конструктор с двумя параметрами, объявленными в классе.

Во втором варианте GetCenterPoint2() конструктор копирования вызывается при возвращении из функции оператором return. В операторе return создается временный объект класса CMyPoint, который сразу инициализируется значением mp, в результате этого вызывается конструктор копирования.


Связанные темы