Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Базовый и производный классы. Конструкторы производного класса. Перегрузка методов при наследовании. Алгоритм выбора перегруженного метода.

Область видимости и класс памяти. | Объявление и инициализация одномерного и двумерного массивов. Работа с элементами массива через указатель. | Принципы ООП. Инкапсуляция. Наследование. Полиморфизм. | Конструкторы и деструкторы. Конструкторы копирования по умолчанию. | Объекты как аргументы методов и доступ к их числам. | Размещение в памяти членов объектов одного класса и способ создания общих полей (св-в). | Константные методы, их аргументы и константные объекты. | Строки на основе массива типа char и класса string | Перегрузка бинарных операций | Преобразование типов от основного к пользовательскому. |


Читайте также:
  1. I. Изменение Конституции, участие в выборах и референдуме
  2. IX. Данные лабораторных и инструментальных методов обследования.
  3. Quot;О выборах депутатов Государственной Думы Федерального Собрания Российской Федерации" 0
  4. Автономные импульсные процессы. Алгоритм вычисления вектора импульсов и вершин.
  5. Алгоритм
  6. Алгоритм
  7. Алгоритм ведения больных язвенной болезнью

Базовый и производный классы

class Counter //базовый класс

{

protected:

unsigned int count; //счетчик

public:

Counter (): count (0) //конструктор без аргументов

{ }

Counter (int c): count (c)

{ }

unsigned int get_count () const

{ return count; } // возвращает значение счетчика

Counter operator++ () //увеличивает значение

//счетчика (префикс)

{ return Counter (++count); }

};

//////////////////////////////////////////////////////////

class CountDn: public Counter//производный класс

{

public:

Counter operator-- () //уменьшает значение счетчика

{ return Counter (--count); }

};

//////////////////////////////////////////////////////////

int main ()

{

CountDn c1; // объект с1

cout << "\n c1=" << c1.get_count (); //вывод на печать

++c1; ++c1; ++c1; //увеличиваем c1 три раза

cout << "\n c1=" << c1.get_count (); //вывод на печать

--c1; --c1; //уменьшаем c1 два раза

cout << "\n c1=" << c1.get_count (); //вывод на печать

cout << endl;

return 0;

}

Класс CountDn наследует все признаки Counter. Создается объект класса CountDn в ф-ии main(). Он будет инициализирован нулем.

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

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

class Counter

{

protected: // заметьте, что тут не следует использовать private

unsigned int count; // счетчик

public:

Counter (): count () // конструктор без параметров

{ }

Counter (int c): count (c) // конструктор с одним параметром

{ }

unsigned int get_count () const // получение значения

{ return count; }

Counter operator++ () // оператор увеличения

{ return Counter (++count); }

};

///////////////////////////////////////////////////////////

class CountDn: public Counter

{

public:

CountDn (): Counter () // конструктор без параметров

{ }

CountDn (int c): Counter (c)// конструктор с одним параметром

{ }

CountDn operator-- () // оператор уменьшения

{ return CountDn (--count); }

};

Здесь использованы два новых конструктора. Когда мы запишем в ф-ию main() CountDn c1 компилятор создаст объект класса CountDn и вызовет конструктор класса CountDn. А конструктор вызовет конструктор Counter. Там где конструктор с одним аргументом происходит тоже самое.

Перегрузка функций

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

Алгоритм выбора перегруженного метода

1. Использовать строгое соответствие (если это возможно).

2. Попробовать стандартное повышение типа.

3. Попробовать стандартное преобразование типа.

Стандартное повышение типа лучше, чем остальные стандартные преобразования. Повышение – это преобразование float в double. Кроме того, к стандартным преобразованиям относятся преобразования массивов похожих целых типов. Похожими типами являются: bool, char; и т.д.(счет идет по байтам)

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

 

28) Общее и частное наследование. Уровни наследования. Множественное наследование. Неопределённость при множественном наследовании. Алгоритм выбора перегруженного метода

Наследование позволяет использовать код программ повторно: в производном классе можно расширить возможности базового класса без его модификации, даже не имея доступа к его коду. Классы могут быть общими и частными производными базового класса. Объекты общего производного класса имеют доступ к членам базового класса, объявленным как public, а объекты частного производного класса доступа к ним не имеют.

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

class A

{ };

class В: public A

{ };

class C: public В

{ };

Здесь класс В является производным класса A, а класс C является производным класса B. Процесс может продолжаться бесконечно. Класс может быть производным более чем одного базового класса. Этот случай называется множественным наследованием.

class A {};

class В {};

class C: public A, public В

{ };

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

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

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

class A

{ public:

void show ()

{ cout << "Класс A"; } };

class B

{ public:

void show ()

{ cout << "Класс B"; } };

class C: public A, public B { };

int main ()

{

C objC; // объект класса C

// objC.show (); // так делать нельзя – неопределённость

objC.A::show (); // так можно

objC.B::show (); // так можно

return 0;

}

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

class A

{ public:

virtual void func();

};

class B: public A

{ };

class C: public A

{ };

class D: public B, public C

{ };

int main()

{

D objD;

objD.func(); //неоднозначность: программа не скомпилируется.

...

return 0;

}

/* классы В и C содержат в себе копии метода func(), унаследованные от класса A. Компилятор не может решить, какой из методов использовать, и сообщает об ошибке. */

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

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


Дата добавления: 2015-08-17; просмотров: 184 | Нарушение авторских прав


<== предыдущая страница | следующая страница ==>
Предотвращение преобразования типов от основного к пользовательскому с помощью конструктора| Указатели. Инициализация. Арифметические операции.

mybiblioteka.su - 2015-2024 год. (0.013 сек.)