2010-12-29 10 views
9
class B { 
virtual int foo(); 
}; 

class D : public B { 
virtual int foo() { cout<<"D\n"; } 
}; 

int B::foo() 
{ 
    /* how do i tell if this->foo() is overridden by a subclass, or if it will */ 
    /* simply recurse into B::foo()? */ 
    this->foo(); 
} 

main() 
{ 
D d; 
d.B::foo(); 
} 
+3

Prawdopodobnie nie ma niezawodnego sposobu. Dlaczego chcesz? –

+0

Zgadzam się z Oli - wystarczy zadzwonić d.foo() jak normalna osoba. – Puppy

+1

Chcę uzupełnić moją odpowiedź o kilka dodatkowych osobistych punktów widzenia. Staram się nigdy nie pytać, dlaczego ktoś chce coś zrobić. Nie wiem, dlaczego chcą coś zrobić, wiem tylko, że zadali pytanie.Myślę, że jest w porządku, aby spróbować rozwiązać ich problem i zapewnić alternatywę, o której mogą nie myśleć, ale stwierdzenia takie jak "rób to jak normalna osoba" nie są ani konstruktywne, ani pomocne. –

Odpowiedz

8

Odpowiedź: nie można.

Zostałabym rozwinięta, gdyby było coś do rozszerzenia.

+0

to też myślałem. – deltamind106

0

Najbezpieczniejszym sposobem jest nie przesłonięcie foo() w ogóle, ale pozwalają na nadpisanie funkcji OnFoo(), która jest wywoływana z baseclass, jeśli nie możesz ufać swoim programistom. MFC robi to dużo, aby zapewnić pewne domyślne zachowanie (zamiast chronić się przed powtarzaniem).

Następnie, również na poziomie statycznym, wszystko, co implementuje OnFoo(), jest łatwo zauważalne dzięki "Znajdź w plikach".

E.g. (Nie testowane na składni/kompilacji i nie THREADSAFE)

class B 
{ 
public: 
    B() 
    { 
     m_bInFoo=false; 
    } 

    int foo() 
    { 
     if(!m_bInFoo) 
     { 
      m_bInFoo=true; 

      int nRet = OnFoo(); 

      m_bInFoo=false; 

      return nRet; 
     } 

     return 0;// probably throw exception 
    } 

protected: 
    // inherited classes override OnFoo(), and never call OnFoo(); 
    virtual int OnFoo(){ return 0 }; 

private: 
    bool m_bInFoo; 
} 
1

Nienawidzę nawet zapewniając tym .. ale tutaj jest

int B::foo() 
{ 
std::cout << "B" << std::endl; 
if (typeid (*this) != typeid(B)) 
    this->foo(); 
return 0; 
} 

Edit

Chcę udowodnić, że to działa w MSVC++ 2010.

#include "stdafx.h" 
#include <iostream> 

class B { 
public: 
virtual int foo(); 
}; 

class D : public B { 
public: 
virtual int foo() { 
    std::cout<<"D\n"; return 0; 
} 
}; 

int B::foo() 
{ 
std::cout << "B" << std::endl; 

/* how do i tell if this->foo() is overridden by a subclass, or if it will */ 
/* simply recurse into B::foo()? */ 
if (typeid (*this) != typeid(B)) 
    this->foo(); 

return 0; 
} 


int main(int argc, _TCHAR* argv[]) 
{ 
D d; 
d.B::foo(); 

B b; 
b.foo(); 
return 0; 
} 

Ou tput

B 
D 
B 

Dowód, że nie zawsze będzie działać

Zmień D do tego i nie będzie już pracować

class D : public B { }; 
+0

To nie działa. Nie jest powiedziane, czy foo() jest przesłonięte, i w rzeczywistości, jeśli nie jest to twój kod będzie nieskończenie rekurencyjny przy każdym wywołaniu foo() na obiekcie D; dokładnie to, co OP chce uniknąć. W rzeczywistości nie pomaga ci dowiedzieć się niczego poza tym, czy B, do którego odwołuje się foo(), jest w rzeczywistości bardziej szczegółową wersją czy nie ... to wszystko. Punkty byłyby bardziej znaczące, gdyby ludzie nie tylko rozdawali je przed sprawdzeniem poprawności odpowiedzi. –

+0

@ Noah Roberts Masz rację, jeśli D nie zastąpi B :: foo, to się powtórzy. Można to również rozwiązać za pomocą rozwijania stosu. Utwórz zmienną na stosie, która ustawia flagę w wątku lokalnego magazynu po wprowadzeniu B :: foo(), jeśli B: foo() zostanie ponownie wpisany przez ten sam stos i spróbuje utworzyć inną zmienną, może sprawdzić, czy flaga flaga została ustawiona, a następnie zakończ. Po rozwinięciu stosu zniszczenie zmiennej może zdezaktywować flagę. Moje rozwiązanie rozwiązuje dokładnie problem, który podał, co jest moją winą, ponieważ nie przeczytałem innych scenariuszy, które mogłyby się wydarzyć. –

2

Jednym ze sposobów jest, aby foo()czystą funkcję wirtualną w B, i również go definiują. W ten sposób upewnisz się, że klasy pochodne muszą zdefiniować B zdefiniować foo(). Oto B,

class B 
{ 
public: 
     virtual int foo() = 0; //pure virtual function 
}; 

//pure virtual function also has a default implementation! 
int B::foo() 
{ 
     std::cout << "B" << std::endl; 
     this->foo(); //this will call the overridden foo() in the derived class! 
     return 0; 
} 

Jeśli klasa pochodzi od B nie realizuje foo(), to nie można nawet utworzyć instancję tej klasy pochodnej!

Zobacz pełny kod pracujący w ideone: http://www.ideone.com/m8O2s

Nawiasem mówiąc, moja osobista opinia byłby taki projekt zajęć jest zły na początek. Co jeśli zadzwonisz pod numer B::foo() z klasy pochodnej foo()? Rekurencyjny?

+0

To sprawia, że ​​nie może on utworzyć instancji B. Nie wiemy, czy nadal chce tworzyć obiekty typu B. –

+0

tak, oczywiście, zdaję sobie sprawę, że istnieje kilka sposobów inżynierii wokół niego, ale mój Pytanie brzmi, czy istnieje sposób wbudowany do rtti w C++, aby zrobić to, co chcę. – deltamind106

0

Jak inni podkreślili, nie ma niezawodnego sposobu, aby to zrobić. Zachęcam do przemyślenia swojego projektu ...

+0

cóż, tak, byłoby miło, gdybym mógł przeprojektować niezręczny kod poprzedniego programisty, ale niestety nie ma go teraz na kartach. – deltamind106

Powiązane problemy