C ++: включение наследования, полиморфизма и фабрик

0

В настоящее время я пытаюсь создать пару классов, которые зависят друг от друга. По сути, объекты класса B создают объекты класса A Тем не менее, я также использую иерархию наследования, поэтому все производные класса B также должны иметь возможность создавать производные класса A (каждая производная от B соответствует производной от A, поэтому DerB1 создает объекты DerA1, а DerB2 создает объекты DerA2),

У меня проблемы с моей реализацией, и это может быть глупо, но я хотел бы узнать, знает ли кто, что делать. Мой код ниже (я НИЧЕГО читаю код других людей, поэтому я попытался сделать его максимально простым для чтения... только несколько важных бит, которые я прокомментировал, чтобы объяснить)

class BaseB {} // Declare BaseB early to use in BaseA constructor

class BaseA
{
public:
BaseA(BaseB* b) {}; // Declare the BaseA constructor (callable by all B classes, which pass a pointer to themselves to the constructor so the A objects can keep track of their parent)
}

class DerA:public BaseA
{
    DerA(BaseB* b):BaseA(b) {}; // Inherit the BaseA constructor, and use initialization list
}

class BaseB
{
public:
    virtual BaseA createA() = 0; // Virtual function, representing method to create A objects
}

class DerB:public BaseB
{
    BaseA createA() {
        DerA* a = new DerA(this); // Definition of createA to make a new A object, specifically one of type DerA (Error1: No instance of constructor "DerA::DerA" matches the argument list)
        return a; // Error2: Cannot return DerA for BaseA function
    }
}

Итак, у меня есть две основные проблемы: одна из них практична (Error1, поскольку я просто просто неправильно вызываю функцию, даже если я пытаюсь this), один из них философский (ошибка 2, поскольку я не знаю, как реализовать функции, которые я хочу. Если кто-нибудь может указать, почему возникает Error1, это было бы замечательно! Ошибка2, однако, требует некоторого объяснения.

Я хотел бы, чтобы мой пользователь (программист) взаимодействовал со всеми объектами A одинаковым образом. Они будут иметь одинаковые точные публичные функции, но каждая из них будет ОЧЕНЬ различной реализации этих функций. Некоторые из них будут использовать разные типы данных (и поэтому потребуются контракты функций), но многие из них будут иметь одинаковые типы данных только с различными алгоритмами, которые они используют на них. Я хотел бы, чтобы часть кода работала точно так же, если используется один производный класса A или другой. Однако в моей текущей реализации кажется, что мне нужно вернуть объект DerA вместо объекта BaseA (на сайте Error2). Это означает, что мне нужно будет написать сегмент основного кода SPECIFICALLY для объекта DerA вместо любого произвольного объекта A Мне хотелось бы что-то вроде:

BaseB b = new DerB(); // Declare which derivative of BaseB I want to use
BaseA a = b->createA(b); // Call the createA function in that derivative, which will automatically make a corresponding A object

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

Будет ли я лучше использовать шаблоны или какой-либо другой метод вместо наследования? (Прошу прощения за то, что вы намеренно расплывчаты, но я надеюсь, что мой пример класса A/B должен в основном объяснить, что мне нужно).

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

  • 2
    class BaseB {} должен быть class BaseB;
  • 1
    virtual BaseA createA() Вы должны возвращать не по значению, а по (умному) указателю. См. En.wikipedia.org/wiki/Object_slicing
Показать ещё 1 комментарий
Теги:
polymorphism
inheritance
factory

1 ответ

2
Лучший ответ

У вас есть несколько синтаксических проблем для устранения ошибок:

  • Добавить ; после каждого определения класса.
  • Первая строка должна быть объявлением вперед: class BaseB/*{} NO!!*/;
  • Добавить public: сделать конструктор DerA доступным для DerB
  • BaseA createA() должен возвращать значение, а не указатель (согласно сигнатуре): return *a;

Существует еще одна потенциальная проблема скрытого среза, поскольку createA() возвращает значение, а не указатель. Это означает, что ваш возвращенный объект (здесь *a) будет скопирован, но как реальный объект BaseA. Таким образом, будет скопирована только часть BaseA объекта, а не производная часть. Это может привести к неожиданным неожиданностям.

Чтобы избежать нарезки, подумайте о возврате указателя, соответственно изменив подпись createA(). Указанный объект затем сохранит правильный тип, не потеряв ничего.

Если позже вам нужно будет скопировать объект, вы можете использовать статический приведение, если вы абсолютно уверены в действительном типе объекта, на который указывают:

   BaseA *pba = pdb->createA();         // get pointer returned 
   DerA da = *static_cast<DerA*>(pba);  // static cast with pointer

Если вам нужно будет скопировать выделенные объекты BaseA, не обязательно обязательно указывая их реальный тип, вы можете реализовать функцию виртуального клонирования в DerA (например, образец шаблона прототипа)

  • 0
    Весь синтаксис исправлен, и компилятор доволен. Прошу прощения за трату вашего времени на простые синтаксические проблемы. Знаете ли вы, как бороться с проблемой нарезки объектов (на которую я пытался сослаться в Error2)? Мне нужно получить объект DerA , но я бы хотел иметь возможность ссылаться на него, не разрезая членов подкласса. Можно ли использовать «умные указатели» или динамическое приведение?
  • 1
    Если вы определяете функцию как BaseA *createA() и возвращаете указатель, вы избегаете нарезки (т. BaseA *createA() Объект, на который указывает указатель, имеет правильный тип). Если вам нужен объект DerA и вы уверены, что указатель указывает на такой объект, вы можете написать что-то вроде DerA da = *static_cast<DerA*>(pba);
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню