2013-06-17 4 views
2

У меня возникла ситуация, когда я хотел бы получить каждый производный экземпляр System, чтобы подписаться на событие через мою собственную систему событий. В основном это означает передачу std :: function в событие, которое является полем члена другого экземпляра. Так что это в основном так:Вызов метода производного класса из конструктора базового класса

// System.h 
class System 
{ 
    public: 
     System(std::shared_ptr<EntityManager> entityManagerPtr); 
     virtual ~System(); 
     virtual void componentAddedEventHandler(void* source, const ComponentAddedEventArgs& args); 
    protected: 
     std::shared_ptr<EntityManager> m_entityManagerPtr; 
}; 

И реализации, с помощью делегата:

// System.cpp 
System::System(std::shared_ptr<EntityManager> entityManagerPtr) : m_entityManagerPtr(entityManagerPtr) 
{ 
    // Subscribe to the componentAddedEvent 
    m_entityManagerPtr->componentAddedEvent += [&](void* source, ComponentAddedEventArgs args) { 
     this->componentAddedEventHandler(source, args); 
    }; 
} 

Но очевидно, что это не будет компилироваться без определения System::componentAddedEventHandler().

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

+0

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

+0

Можете ли вы предоставить более подробную информацию о том, что вы на самом деле пытаетесь сделать? Прямо сейчас моя кишка говорит, что вы передумали это. –

+0

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

ответ

2

ОП сказал в комментарии (empahsis мой):

Я думал, я хотел бы иметь все классы, полученные из System подписаться на событие, и вынуждены реализовать свой собственный обработчик для указанного события.

«Все классы, полученные из X» и «быть вынужденными» в одном и том же предложении, кричит для чистой виртуальной функции-члена.

struct System 
{ 
    virtual void foo() = 0; 
}; 

struct Subsystem : public System 
{ 
    virtual void foo() override { /* forced to implement this */ } 
}; 

Если вы храните свои системы с помощью смарт-указатель (в контейнере может быть), вы можете позвонить foo() для каждого из них, и быть уверены, чтобы получить поведение dervied класса.

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

template <typename T> 
unique_ptr<T> make_system() 
{ 
    auto obj = make_unique<T>(); 
    obj->foo(); 
    return obj; 
} 

auto s1 = make_system<Subsystem1>(); 
auto s2 = make_system<Subsystem2>(); 

Оба этих объектов вынуждены осуществлять foo() и оба объекта назвали foo() перед использованием. Это все еще двухфазная инициализация, но она скрыта для вас за вызовом функции.

+0

Да, но это половина проблемы решена: я могу заставить производные классы реализовать обработчик событий, но не подписаться на это событие. – vijoc

+0

@vijoc 'm_entityManagerPtr-> componentAddedEvent + = foo;'? Примечание: Извините за то, что не кричал, когда я упоминал абстрактные виртуальные машины ... Вы можете сделать это в конструкторе. (Или вы были обеспокоены тем, что они пропустили конструктор базового класса?) Завод может быть более сильным. –

+0

Действительно ли это так просто? Если я передам лямбда, вызывающий абстрактный виртуальный метод (в конструкторе базового класса), он будет компилироваться и делать то, что я надеюсь, что он будет, т. Е. Вызвать метод производного класса? – vijoc

Смежные вопросы