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

Это, наверное, простой вопрос, пожалуйста, потерпите меня, так как я привык к Java …

Допустим, у нас есть интерфейс:

class IDoable {
virtual void do() = 0;
};

Другой класс:

class Base : public IDoable {
//...
virtual void do() { ... }
};

И последний класс, расширяющий наш базовый класс:

class ExtendingBase : public Base {
// some extra functionality
};

Я потерялся в той части, если я хочу составить список IDoable объекты, которые могут быть Base объекты или ExtendingBase объекты. Должен ли я добавить некоторые методы объявления методов в Base учебный класс? Как работает этот аспект?

РЕДАКТИРОВАТЬ:

У меня есть несколько списков указателей типа IDoable
и если я тогда попытаюсь добавить Base возражать против этого списка я получаю сообщение об ошибке:

IDoable — это неоднозначная база Base

То же самое, если я попытаюсь добавить ExtendingBase объект

IDoable является неоднозначной основой ExtendingBase

2

Решение

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

Если вы создаете ExtendingBase возразить и вызвать do функция, она будет вызывать Base класс первый ExtendingBase наследует этот метод).

Виртуальный полиморфизм вступает в игру, когда вы вызываете do() функция из указателя или ссылки базового класса: do() Будет вызвана функция, соответствующая динамическому типу объекта, на который указывает или на который ссылаются:

class IDoable{
public:
virtual void dof()=0;
virtual ~IDoable() = default;
};class Base:public IDoable{
public:
virtual void dof(){std::cout << "Base";}
virtual ~Base() = default;
};

class ExtendingBase:public Base{
public:
virtual void dof() { std::cout << "ExtendingBase"; }
};

int main()
{
IDoable *ptr = new Base(); // A smart pointer would be a better choice
// but for clarity's sake I'm using bare
// memory allocations here
ptr->dof(); // Walks the virtual table and calls "Base"delete ptr;

ptr = new ExtendingBase();
ptr->dof(); // Walks the virtual table and calls "ExtendingBase"delete ptr;
}

Также обратите внимание на использование виртуальных деструкторов: они работают как обычные виртуальные функции и, таким образом, при вызове delete для базового указателя, чтобы фактически уничтожить нужный тип объекта (т. Е. Вызвать правильный деструктор в иерархии), вам потребуется сделать это виртуальным.

В качестве обозначения: do является зарезервированным ключевым словом в C ++


В ответ на ваши изменения: если у вас есть вектор или список IDoable указатели, вы не можете просто добавить производный объект к нему, но вы должны добавить указатель к производному объекту. То есть следующее неправильно:

std::vector<IDoable*> vec;
vec.push_back(Base());

плюс базовый класс остается классом (нет интерфейс концепция в C ++ (как в Java), и вы не должны наследовать от базового класса несколько раз:

class Base:public IDoable{
...
class ExtendingBase:public Base, public IDoable <- nope
...

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

1

Другие решения

если я хочу составить список IDoable объекты

Вы не можете сделать IDoable период объекта. Это абстрактный класс, он не может быть создан напрямую, поэтому у вас не может быть его контейнера. То, что вы можете сделать и что вы, вероятно, намереваетесь, это иметь контейнер IDoable*:

std::vector<IDoable*> objects;
objects.push_back(new Base);
objects.push_back(new ExtendedBase);

Или лучше выразить право собственности в C ++ 11:

std::vector<std::unique_ptr<IDoable>> objects;

Учитывая ваш интерфейс, вы уже можете позвонить do() на любом из этих объектов, и это будет делать правильные вещи с помощью виртуальной отправки. Хотя есть одна функция-член, которую вы определенно хотите добавить в свой интерфейс:

class IDoable {
public:
virtual ~IDoable() = default; // this one
virtual void do() = 0;
};

Таким образом, когда ты delete IDoable*, ты сможешь delete полный объект, а не только базовый интерфейс.

1

Вы должны будете реализовать свой do() функция в Base, так как функция в классе IDoable чисто виртуальный.

Если вы решили создать ExtendingBase объект, do() Функция будет вести себя так, как она реализована в Base, если вы не переопределите его, повторно внедрив его в ExtendingBase,

1

Первая и самая главная проблема в том, что вы думаете на Java.
слова «интерфейс» и «расширение» очень ориентированы на Java. С ++ так не думает.

например, когда кто-то говорит об «интерфейсе» в контексте C ++, я могу подумать, что он говорит об объявлении класса внутри файла .h (в отличие от реализации, которая находится в файле .cpp)

IDoable — это КЛАСС. период. единственное отличие состоит в том, что он имеет чисто виртуальные функции, которые запрещают инстанциацию. кроме того, что он ведет себя как класс, он может наследоваться, может содержать переменные-члены и все остальное.

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

так сказал:

//in the stack:
Base base;
ExtendingBase eBase;
base.do();
eBase.do()

//in the heap with IDoable as pointer:
IDoable * base = new Base();
IDoable * ebase = new ExtendingBase ();
base->do();
ebase->do();

Теперь вы можете спросить — как мне активировать функции Base и ExtendingBase? так же, как и в Java, вам нужно привести указатель и только потом вызвать нужную функцию.

 Base* realBase = (Base*)base;
realbase->someBaseFunction();

как и многие вещи в C ++, этот код немного опасен. ты можешь использовать dynamic_cast вместо.

и еще одна вещь — do это ключевое слово в C ++, оно не может объявить имя функции.

1
IDoable *pDo1 = new Base();
IDoable *pDo2 = new ExtendingBase();
pDo1->do();
pDo2->do();
delete pDo1;
delete pDo2;
0
По вопросам рекламы [email protected]