Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ответы по экзамену ЯП.doc
Скачиваний:
3
Добавлен:
25.08.2019
Размер:
534.02 Кб
Скачать

Конструктор копирования

Основная статья: Конструктор копирования

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

Конструктор копирования в основном необходим, когда объект имеет указатели на объекты выделенные в куче. Если программист не создаёт конструктор копирования, то компилятор создаст неявный конструктор копирования, который копирует указатели как есть, то есть фактическое копирование данных не происходит и два объекта ссылаются на одни и те же данные в куче. Соответственно попытка изменения «копии» повредит оригинал, а вызов деструктора для одного из этих объектов при последующем использовании другого приведёт к обращению в область памяти, уже не принадлежащую программе.

Аргумент должен передаваться именно по ссылке, а не по значению. Это вытекает из коллизии: при передаче объекта по значению (в частности, для вызова конструктора) требуется скопировать объект. Но для того, чтобы скопировать объект, необходимо вызвать конструктор копирования.

Конструктор преобразования

Конструктор, принимающий один аргумент. Задаёт преобразование типа своего аргумента в тип конструктора. Такое преобразование типа неявно применяется только если оно уникально.

Виртуальный конструктор

Конструктор не бывает виртуальным в смысле виртуального метода — для того, чтобы механизм виртуальных методов работал, нужно запустить конструктор, который автоматически настроит таблицу виртуальных методов данного объекта.

«Виртуальными конструкторами» называют похожий, но другой механизм, присутствующий в некоторых языках — например, он есть в Delphi, но нет в C++ и Java. Этот механизм позволяет создать объект любого заранее неизвестного класса при двух условиях:

  • этот класс является потомком некоего наперёд заданного класса (в данном примере это класс TVehicle);

  • на всём пути наследования от базового класса к создаваемому цепочка переопределения не обрывалась. При переопределении виртуального метода синтаксис Delphi требует ключевое слово overload, чтобы старая и новая функции с разными сигнатурами могли сосуществовать, override для переопределения функции либо reintroduce для задания новой функции с тем же именем — последнее недопустимо.

47. Порядок вызова конструкторов и деструкторов в языке C++

В большинстве случаев при работе с объектами сразу после создания осуществляется их инициализация – заполнение полей объекта начальными значениями.

                Для того чтобы  инициализация объектов осуществлялась более просто и надежно, используются специальные методы – конструкторы.

                Конструкторы определяют, каким образом будет создан новый объект, как будет проводиться распределение памяти и инициализация объекта.

                Общий вид объявления конструкторов:

class ИмяКласса {

  public:

    ИмяКласса(параметры);

  ...

};

Отличия конструкторов от обычных методов:

  1. Имя конструктора всегда должно совпадать с именем класса

  2. При объявлении конструктора запрещается указывать тип возвращаемого значения (даже void).

  3. Конструкторы обычно объявляются в разделе public.

В том случае, когда за время работы программы поля созданных объектов не изменяются, в класс, содержащий конструктор, не включают методы для изменения значения полей (setter'ы).

В зависимости от наличия параметров, конструкторы делят на

конструкторы по умолчанию параметры отсутствуют параметризованные конструкторы имеется один или несколько параметров. Конструкторы по умолчанию представляют собой простейший вид конструкторов, которые не имеют никаких параметров.

                Общий вид конструктора по умолчанию:

class ИмяКласса {

  public:

    ИмяКласса();

  ...

};

Задача конструктора по умолчанию – присвоить полям объекта такие начальные значения, при которых его существование имеет хоть какой-то смысл.

Очень часто в конструкторе по умолчанию полям объекта присваиваются нулевые значения.

Пример. Конструктор по умолчанию для класса "Точка"

class Point {

  private:

    double x, y;

  public:

    Point();

  ...

};

Point::Point() {

  x = 0;

  y = 0;

}

Конструктор по умолчанию автоматически вызывается при объявлении переменной-объекта:

Point A; // Вызов конструктора по умолчанию

Если в классе отсутствует конструктор по умолчанию, то при подобном объявлении переменной-объекта, его поля получают непредсказуемые значения.

В некоторых случаях наличие конструктора по умолчанию является обязательным:

–        при объявлении массива объектов (Point m[10]);

–        при наследовании;

–        при работе с некоторыми шаблонами  и т.п.

Параметризованные конструкторы

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

В простейшем случае этими параметрами могут быть начальные значения для полей объекта.

Пример. Параметризованный конструктор для класса "Точка"

class Point {

  private:

    double x, y;

  public:

    Point(double X, double Y);

  ...

};

Point::Point(double X, double Y) {

  x = X;

  y = Y;

}

При создании объектов с помощью параметризованных конструкторов используются две формы записи:

1. Явный вызов конструктора

ИмяТипа ИмяОбъекта = ИмяКонструктора(параметры);

Пример. Явный вызов конструктора класса "Точка"

Point A = Point(x,y);

2. Неявный вызов конструктора

ИмяТипа ИмяОбъекта(параметры);

Пример. Неявный вызов конструктора класса "Точка"

Point A(x,y);

По правилам языка C++ в одном классе может быть объявлено несколько параметризованных конструкторов, отличающихся наборами параметров.

 Подобная возможность носит название перегрузка конструкторов.

 Благодаря наличию нескольких конструкторов, программист всегда может выбрать для создания объекта наиболее подходящий конструктор.

Пример. Параметризованные конструкторы для класса "Вектор"

class Vector {

  private:

    double x, y;

  public:

    // создание вектора по координатам

    Vector(double X, double Y);

    // создание вектора по точкам

    Vector(Point A, Point B);

  ...

};

  // создание вектора по координатам

  Vector::Vector(double X, double Y) {

    x = X;

    y = Y;

  }

  // создание вектора по точкам

  Vector::Vector(Point A, Point B) {

    x = B.GetX() - A.GetX();

    y = B.GetY() - A.GetY();

  }

 Если класс не содержит собственных конструкторов, он инициализируется так, словно компилятор создал конструктор без аргументов за вас. Этот конструктор вызывает конструкторы без аргументов базовых классов и переменных класса. Четко определенный порядок вызова конструкторов не зависит от того, используются конструкторы стандартные или перегруженные, с аргументами или без:

1. Сначала вызываются конструкторы базовых классов в порядке их перечисления в списке наследования (еще один список, в котором после символа : перечисляются базовые классы, разделенные запятыми).

2. Затем вызываются конструкторы переменных класса в порядке их объявления в объявлении класса.

3. После того как будут сконструированы все базовые классы и переменные, выполняется тело вашего конструктора.

Описанный порядок применяется рекурсивно, то есть первым конструируется первый базовый класс первого базового класса... и т. д. Он не зависит от порядка, указанного в списке инициализации членов.

Если бы дело обстояло иначе, для разных перегруженных конструкторов мог бы использоваться разный порядок конструирования. Тогда компилятору было бы трудно гарантировать, что деструкторы будут вызываться в порядке, обратном порядку вызова конструкторов.

48. Списки инициализации членов и анонимные экземпляры в языке C++

49. Понятия базового и производного классов

50. Спецификатор доступа при наследовании классов в языке C++