C++ Автоматическое создание экземпляров производных классов

У меня есть абстрактный базовый класс с именем Base, для которого другие программисты должны написать реализацию. В какой-то другой части приложения я хочу перехватить все написанные реализации и создать по одному экземпляру каждой. Если бы это можно было сделать без каких-либо дополнительных инструкций для других, помимо «внедрить базу», это было бы прекрасно. Однако приведенный ниже код требует, чтобы каждая реализация регистрировала себя. Это также не работает.

#include <iostream>
#include <vector>

class Base;

std::vector<Base*>* registrationList = new std::vector<Base*>;

class Base {
public:
   Base(){}
   virtual void execute() = 0;
};

class ImplementationOne: public Base {
public:
   ImplementationOne(){registrationList->push_back(this);}
   void execute(){std::cout << "Implementation One." << std::endl;}
   static int ID;
};

class ImplementationTwo: public Base {
public:
   ImplementationTwo(){registrationList->push_back(this);}
   void execute(){std::cout << "Implementation Two." << std::endl;}
   static int ID;
};

int main(int argc, const char * argv[]){
   std::cout << "Registration List size: " << registrationList->size() << std::endl;
   for(auto it = registrationList->begin() ; it != registrationList->end() ; ++it){
      (dynamic_cast<Base*>(*it))->execute();
   }
   return 0;
}

Я получаю вывод: Registration List size: 0, поэтому ясно, что реализации никогда не создавались. Вероятно, очевидно, что этого не произойдет, но я новичок, и это лучшее, что я мог придумать. Я предполагал, что static int ID; вызовет создание каждой реализации, которая затем зарегистрируется. Я вижу, что static не приводит к созданию экземпляра. Я оставляю это в своем коде здесь, так как это показывает мое намерение.

Что я могу сделать, чтобы получить автоматическое создание каждой реализации? Является ли это возможным?


person Little Endian    schedule 01.07.2013    source источник
comment
Послание из будущего: Ты безнадежный новичок, но не волнуйся, ты поправишься.   -  person Little Endian    schedule 11.03.2019


Ответы (2)


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

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


В вашем коде есть проблемы, не связанные с вашей проблемой:

  • Практически никогда нет причин иметь указатель на контейнер.
  • Вы полиморфно наследуете тип без виртуального деструктора.
  • Вы dynamic_cast<Base*> без видимой причины.
  • Каждый из ваших производных классов объявляет но не определяет член ID.
person Mooing Duck    schedule 01.07.2013
comment
Спасибо за ответ. Похоже, вы определили статическую функцию registrationList() так, как вы это сделали, чтобы обойти проблему определения статической переменной static std::vector<Base*> registrationList; в определении класса. Я попытался отредактировать ваш код, чтобы использовать статическую переменную, но получил ошибки компоновщика. - person Little Endian; 01.07.2013
comment
На самом деле это не приходило мне в голову. Я имел в виду (A) это часть иерархии Base, а не глобального состояния программы, и (B) избежание Статическая инициализация ордера Fiasco - person Mooing Duck; 01.07.2013
comment
Ах. Я понял, как решить проблему из моего комментария. Сделайте: std::vector<Base*> Base::registrationList; вне определения класса. - person Little Endian; 02.07.2013
comment
Не делай этого. Если вы попытаетесь масштабировать этот дизайн, вы столкнетесь с фиаско статического порядка инициализации. Сделайте его функционально-локальной статической переменной. - person Mooing Duck; 02.07.2013

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

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

Вы должны явно создать экземпляры классов для вызова конструктора.

person Some programmer dude    schedule 01.07.2013
comment
Значит, автоматическая реализация (как я описал) невозможна? - person Little Endian; 01.07.2013
comment
@thethuthinnang Да. Экземпляры объектов не создаются, если вы явно не объявите переменную этого класса. - person Some programmer dude; 01.07.2013