2012-03-15 9 views
13

У меня есть некоторые события, как этоForce вызова базового класса виртуальной функции

class Granpa // this would not be changed, as its in a dll and not written by me 
{ 
public: 

    virtual void onLoad(){} 

} 

class Father :public Granpa // my modification on Granpa 
{ 
public: 

    virtual void onLoad() 
    { 
     // do important stuff 
    } 

} 

class Child :public Father// client will derive Father 
{ 

    virtual void onLoad() 
    { 
     // Father::onLoad(); // i'm trying do this without client explicitly writing the call 

     // clients code 
    } 
} 

Есть ли способ заставить призывающую OnLoad без фактического написания Отец :: OnLoad()?

хак решения приветствуются :)

+4

Я не понимаю, почему это проблема. Вы хотите явно что-то сделать, поэтому вам нужно явно сказать это в коде ... –

+2

Немного ли не нужно добавлять строку кода, чтобы делать что-то, что вы хотите явно? –

+0

Поскольку такая же проблема не решена в i.e обработчиках MFC (вам всегда нужно явно вызвать CDialog :: OnInitDialog() из CMyDialog :: OnInitDialog()), я думаю, вы можете просто потребовать от пользователя этого. – Mikhail

ответ

24

Если я правильно понимаю, вы хотите, так что всякий раз, когда переопределенная функция вызывается, реализация базового класса всегда должен вызываться первым. В этом случае вы можете исследовать template pattern. Что-то вроде:

class Base 
{ 
public: 
    void foo() { 
     baseStuff(); 
     derivedStuff(); 
    } 

protected: 
    virtual void derivedStuff() = 0; 
private: 
    void baseStuff() { ... } 
}; 

class Derived : public Base { 
protected: 
    virtual void derivedStuff() { 
     // This will always get called after baseStuff() 
     ... 
    } 
}; 
+2

Также известен как не виртуальный интерфейс (хотя я всегда знал его как шаблон шаблона). –

+0

nativeStuff может быть закрытым в обоих классах тоже. – Dan

+2

Хорошее объяснение можно найти здесь http://www.gotw.ca/publications/mill18.htm – pmr

4

Как предложено выше, но применяется к вашему делу.

class Father :public Granpa // my modification on Granpa 
{ 

public: 

    virtual void onLoad() 
    { 
     // do important stuff 
     onLoadHandler(); 
    } 
    virtual void onLoadHandler()=0; 
} 

class Child :public Father// client will derive Father 
{ 

    virtual void onLoadHandler() 
    { 

     // clients code 
    } 
} 

Однако ничто не может помешать ребенку не переопределить OnLoad, поскольку C++ не имеет окончательного ключевого слова и Granpa OnLoad сама виртуальная.

+4

К счастью, C++ 11 имеет последнее ключевое слово. – juanchopanza

2

Ну, широко известный, признанный способ сделать это не существует. Если бы это было, библиотеки GUI, использующие события и сигналы, вероятно, внедрили бы это. Однако есть и другие решения вашей проблемы.

Вы можете реализовать соединение сигнала - событие, используя boost.Signals, sigslot или что-то вроде собственного. Как делает GTK +:

g_signal_connect(my_wdg, "expose-event", G_CALLBACK(my_func), NULL); 

gboolean my_func(...) 
{ 
    // do stuff 
    return FALSE; /* this tells the event handler to also call the base class's slot */ 
} 

В менее C-ориентированный путь, это можно было бы реализовать по этим направлениям:

/* In Granpa */ 
/* typedef a functor as 'DerivedEventHandler' or use a boost::function */ 
std::vector<DerivedEventHandler> handlers; 

void connect(DerivedEventHandler event) { handlers.push_back(event); } 

/* in loop */ 
while (! iter = handlers.end()) /* call event */ 

/* In constructor of Father */ 
this->connect(this->OnLoad); 

/* In constructor of Child */ 
this->connect(this->OnLoad); 

/* and so on... in all derived classes */ 
-1

Если рассматриваемый объект мал и дешево копировать, просто вызовите базу class 'copy constructor, то есть BaseClass (* производный_class_object) .method()

+0

Наверное, не то, что хотел ОП, так как он спросил, как это сделать, явно не вызывая вызов функции baseClass, который вам также придется делать с этим подходом. – Haatschii