Мегаобучалка Главная | О нас | Обратная связь


Проблемы при множественном наследовании



2016-09-17 422 Обсуждений (0)
Проблемы при множественном наследовании 0.00 из 5.00 0 оценок




1. Перекрытие имен функций
эта проблема есть как и в обычном наследовании, так и в множественном.
Пусть в классах Cow и Sniper были методы sleep(). Тогда код:

2. CowSniper cs;cs.sleep(); // 2

В строке 2 произойдет ошибка компиляции, т. к. компилятор не может выбрать какой метод sleep() ему вызывать (от Cow или от Sniper). Поэтому необходимо сообщимть ему правильный выбор: cs.Cow::sleep();

3. Перекрытие виртуальных функций
Теперь рассмотрим тот случай, если метод sleep() виртуальный в классах-предках.

4. class Cow {5. public:6. virtual void sleep() = 0;7. };8. class Sniper {9. public:10. virtual void sleep() = 0;11.};12.class CowSniper: public Cow, public Sniper {13.public:14. virtual void sleep() {}};

В таком случае будут перегружены сразу оба метода (ведь у них одинаковая сигнатура). Подробнее о том почему это происходит написано в следующем пункте. Тогда в следующих строках кода:

Cow & c = cs;Sniper & s = cs;c.sleep(); //3s.sleep(); //4

В строках 3 и 4 вызовется один и тот же метод CowSniper::sleep();
С одной стороны это удобно, т. к. если методы называются одинаково, то скорее всего они делают что-то похожее. Тогда перегрузив один метод мы перегрузим сразу оба.
С другой стороны может возникнуть проблема, если класс-потомок должен реализовывать один и тот же виртуальный метод от нескольких базовых классов по-разному. Тогда такая перегрузка будет вредна, но стандартно по другому не поступить. В таких случаях используется следующий способ обойти это ограничение.
Если есть иерархия классов A,B,C. И в классах A и B есть некоторый виртуальный метод f().

Добавим в эту иерархию еще два класса A1 и B1. В классах A1 и B1 создадим методы fA() и fB() соотвественно. Теперь в C будут методы fA() и fB(), которые необходимо перегрузить, причем код в них разный ;)

class A{public: virtual void f();};class B{public: virtual void f();};class A1: public A{public: virtual void f() {fA();} virtual void fA() = 0;};class B1: public B{public: virtual void f() {fB();} virtual void fB() = 0;};class C: public A1, public B1 {public: virtual void fA(); virtual void fB();};

Теперь использовать эти классы можно так:

C c;A & a = c;B & b = c;a.f(); //5b.f(); //6

В строке 5 вызовется C::fA(), а в строке 6 - C::fB(). Обратите внимание на то, как перегружен метод f() в классах A1 и B1, которые ко всему прочему теперь являются абстрактными и невозможно создать их экземпляры. Цель достигнута.

Виртуальные функции

Для примеров будем использовать классы из предыдущей лекции. Следует напомнить, что у нас был класс Person, от которого был унаследован класс Student. Рассмотрим следующий пример:

Student s;
Person &p = s;
s.name(); //Student::name()
p.name(); //Person::name()

В 3-й строке вызовется метод класса Student, т.к. s является объектом этого класса. Однако, в строке 4 вызовется метод nameбазового класса Person, хотя по логике следовало бы тоже ожидать вызов name() класса Student — ведь p — это ссылка на объект производного класса.

Возможность вызова методов производного класса через ссылку или указатель на базовый класс осуществляется с помощью механизма виртуальных функций. Чтобы при вызове p.name() вызвался метод класса Student, реализуем классы следующим образом:

struct Person
{
virtual string name() const;
};

struct Student: Person
{
string name() const;
};

Перед методом name класса Person мы указали ключевое слово virtual, которое указывает, что метод является виртуальным. Теперь при вызове p.name() произойдет вызов метода класса Student, несмотря на то, что мы его вызываем через ссылку на базовый класс Person. Аналогичная ситуация и с указателями:

Student s;
Person *p = &s ;
p->name(); //вызовется Student::name();
Person n;
p = &n;
p->name(); //вызовется Person::name()

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

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

В качестве следующего примера можно рассмотреть класс TextFile, от которого наследуются два класса: GZippedTextFile и BZippedTextFile. Базовый класс имеет два метода: name(), возвращающий имя файла, и read(), считывающий данные из файла. В этом случае виртуальным имеет смысл сделать только метод read, т.к. у каждого типа сжатого файла будет свой способ считывания данных:

struct TextFile
{
string name() const;
virtual string read(size_t count);
//...
};

struct GZippedTextFile : TextFile
{
string read(size_t count);
//...
}

struct BZippedTextFile : TextFile
{
string read(size_t count);
//...
}

Перекрытие методов

Рассмотрим класс A, у которого имеется метод f(int), и класс B, унаследованный от A, у которого есть метод f(long):

struct A
{
void f(int);
};
struct B : A
{
void f(long);
};

В следующем коде:

B b;
b.f(1);

произойдет вызов метода f(long) класса B, несмотря на то, что у родительского класса A есть более подходящий метод f(int). Оказывается, что метод f(int) родительского класса A перекрылся. Для того, чтобы в примере вызвался метод f(int), следует добавить строку using A::f; в определении класса B:

struct B : A
{
using A::f;
void f(long);
};


2016-09-17 422 Обсуждений (0)
Проблемы при множественном наследовании 0.00 из 5.00 0 оценок









Обсуждение в статье: Проблемы при множественном наследовании

Обсуждений еще не было, будьте первым... ↓↓↓

Отправить сообщение

Популярное:
Как вы ведете себя при стрессе?: Вы можете самостоятельно управлять стрессом! Каждый из нас имеет право и возможность уменьшить его воздействие на нас...
Организация как механизм и форма жизни коллектива: Организация не сможет достичь поставленных целей без соответствующей внутренней...



©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (422)

Почему 1285321 студент выбрали МегаОбучалку...

Система поиска информации

Мобильная версия сайта

Удобная навигация

Нет шокирующей рекламы



(0.005 сек.)