Лекции.ИНФО


Разрушение derived2-oбъeктa.



Разрушение derived1-объекта.

Разрушение base-объекта.

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

#include <iostream>

using namespace std;

class base1 {

 public:

  base1() { cout <<"Создание base1-объекта."; }

  ~base1(){ cout <<"Разрушение base1-объекта."; }

};

class base2 {

 public:

  base2() { cout <<"Создание bаsе2-объекта."; }

  ~base2(){ cout <<"Разрушение basе2-объекта."; }

};

class derived: public base1, public base2 {

 public:

  derived() { cout <<"Создание derived-объекта."; }

  ~derived(){ cout <<"Разрушение derived-объекта."; }

};

Int main()

{

 derived ob;

 // Создание и разрушение объекта ob.

 return 0;

}

генерируются такие результаты:

Создание base1-объекта.

Создание basе2-объекта.

Создание derived-объекта.

Разрушение derived-объекта.

Разрушение basе2-объекта.

Разрушение base1-объекта.

Как видите, конструкторы вызываются в порядке происхождения их классов, слева направо, в порядке их задания в списке наследования для класса derived. Деструкторы вызываются в обратном порядке, справа налево. Это означает, что если бы класс base2 стоял перед классом base1 в списке класса derived, т.е. в соответствии со следующей инструкцией:

class derived: public base2, public base1 {};

то результаты выполнения предыдущей программы были бы такими:

Создание basе2-объекта.

Создание base1-объекта.

Создание derived-объекта.

Разрушение derived-объекта.

Разрушение base1-объекта.

Разрушение base2-объекта.

Передача параметров конструкторам базового класса

До сих пор ни один из предыдущих примеров не включал конструкторы, для которых требовалось бы передавать аргументы. В случаях, когда конструктор лишь производного класса требует передачи одного или нескольких аргументов, достаточно использовать стандартный синтаксис параметризованного конструктора. Но как передать аргументы конструктору базового класса? В этом случае необходимо использовать расширенную форму объявления конструктора производного класса, в которой предусмотрена возможность передачи аргументов одному или нескольким конструкторам базового класса. Вот как выглядит общий формат такого расширенного объявления.

конструктор_производного_класса (список_аргументов) :

 base1 (список_аргументов),

 base2 (список_аргументов),

 .

 .

 .

 baseN {список_аргументов);

{

 тело конструктора производного класса

}

Здесь элементы base1-baseN означают имена базовых классов, наследуемых производным классом. Обратите внимание на то, что объявление конструктора производного класса отделяется от списка базовых классов двоеточием, а имена базовых классов разделяются запятыми (в случае наследования нескольких базовых классов).

Рассмотрим следующую простую программу.

#include <iostream>

using namespace std;

class base {

 protected:

  int i;

 public:

  base (int x) {

   i = x;

   cout << "Создание bаsе-объекта.";

  }

  ~base() {cout << "Разрушение base1-объекта.";}

};

class derived: public base {

  int j;

 public:

  // Класс derived использует параметр x, а параметр у передается конструктору класса base.

  derived(int x, int y): base(y){

   j = x;

   cout << "Создание derived-объекта.";

  }

  ~derived() { cout << "Разрушение derived-объекта."; }

  void show() { cout << i << " " << j << ""; }

};

Int main()

{

 derived ob(3, 4);

 ob.show(); // отображает числа 4 3

 return 0;

}

Здесь конструктор класса derived объявляется с двумя параметрами, х и у. Однако конструктор derived() использует только параметр х, а параметр у передается конструктору base(). В общем случае конструктор производного класса должен объявлять параметры, которые принимает его класс, а также те, которые требуются базовому классу. Как показано в предыдущем примере, любые параметры, требуемые базовым классом, передаются ему в списке аргументов базового класса, указываемого после двоеточия.

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

#include <iostream>

using namespace std;

class base1 {

 protected:

  int i;

 public:

  base1(int x) {

   i = x;

   cout << "Создание base1-объекта.";

  }

  ~base1() { cout << "Разрушение base1-объекта."; }

};

class base2 {

 protected:

  int k;

 public:

  base2(int x) {

   k = x;

   cout << "Создание basе2-объекта.";

  }

  ~base2() { cout << "Разрушение basе2-объекта."; }

};

class derived: public base1, public base2 {

  int j;

 public:

  derived(int x, int y, int z): base1(y), base2(z){

   j = x;

   cout << "Создание derived-объекта.";

  }

  ~derived() { cout << "Разрушение derived-объекта."; }

  void show() { cout << i << " "<< j << " "<< k << " n"; }

};

Int main()

{

 derived ob(3, 4, 5);

 ob.show(); // отображает числа 4 3 5

 return 0;

}

Важно понимать, что аргументы для конструктора базового класса передаются через аргументы, принимаемые конструктором производного класса. Поэтому, даже если конструктор производного класса не использует никаких аргументов, он, тем не менее, должен объявить один или несколько аргументов, если базовый класс принимает один или несколько аргументов. В этой ситуации аргументы, передаваемые производному классу, "транзитом" передаются базовому. Например, в следующей программе конструкторы base1() и base2(), в отличие от конструктора класса derived, принимают аргументы.

#include <iostream>

using namespace std;

class base1 {

 protected:

  int i;

 public:

  base1(int x) {

   i=x;

   cout << "Создание base1-объекта.";

  }

  ~base1() { cout << "Разрушение base1-объекта."; }

};

class base2 {

 protected:

  int k;

 public:

  base2(int x) {

   k = x;

   cout << "Создание basе2-объекта.";

  }

  ~base2() { cout << "Разрушение basе2-объекта."; }

};

class derived: public base1, public base2 {

 public:

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

  */

  derived(int х, int у): base1(х), base2(у){

   cout << "Создание derived-объекта.";

  }

  ~derived() { cout << "Разрушение derived-объекта."; }

  void show() { cout << i << " " << k << ""; }

};

Int main()

{

 derived ob(3, 4);

 ob.show(); // отображает числа 3 4

 return 0;

}

Конструктор производного класса может использовать любые (или все) параметры, которые им объявлены для приема, независимо от того, передаются ли они (один или несколько) базовому классу. Другими словами, тот факт, что некоторый аргумент передается базовому классу, не мешает его использованию и самим производным классом. Например, этот фрагмент кода совершенно допустим.

class derived: public base {

  int j;

 public:

  // Класс derived использует оба параметра x и у а также передает их классу base.

  derived(int х, int у): base(х, у){

   j = х*у;

   cout << "Создание derived-объекта.";

  }

// . . .

};

При передаче аргументов конструкторам базового класса следует иметь в виду, что передаваемый аргумент может содержать любое (действительное на момент передачи) выражение, включающее вызовы функций и переменные. Это возможно благодаря тому, что C++ позволяет выполнять динамическую инициализацию данных.

Предоставление доступа

Когда базовый класс наследуется закрытым способом (как private-класс), все его члены (открытые, защищенные и закрытые) становятся private-членами производного класса. Но при определенных обстоятельствах один или несколько унаследованных членов необходимо вернуть к их исходной спецификации доступа. Например, несмотря на то, что базовый класс наследуется как private-класс, определенным его public-членам нужно предоставить public-статус в производном классе. Это можно сделать двумя способами. Во-первых, в производном классе можно использовать объявление using (этот способ рекомендован стандартом C++ для использования в новом коде). Но мы отложили рассмотрение директивы using до темы пространств имен. (Основное назначение директивы using— обеспечить поддержку пространств имен.) Во-вторых, можно настроить доступ к унаследованному члену с помощью объявлений доступа. Объявления доступа все еще поддерживаются стандартом C++, но в последнее время активизировались возражения против их применения, а это значит, что их не следует использовать в новом коде. Поскольку они все еще используются в С++-коде, мы уделим внимание этой теме.

Объявление доступа имеет такой формат:

имя_базового_класса::член;

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









Читайте также:

Последнее изменение этой страницы: 2016-03-17; Просмотров: 84;


lektsia.info 2017 год. Все права принадлежат их авторам! Главная