C++ (bazowy, bez CLI) w przeciwienstwie do Javy czy C# nie przewiduje czegos takiego jak reflection czyli po naszemu introspekcja, czyli odpytywanie obiektow/klas o strukturę ich zawartości. Bez ekstra narzedzi/frameworkow/(..) nie jestes w stanie -wprogramie- dowiedziec się jakie klasa ma metody, jakie metoda ma paametry, po jakich typach klasa dziedziczy, ba, nawet nie sprawdzisz jakiego typu jest zmienna/obiekt. Nie dasz rady napisac nic w stylu (pseudokod)
lista_metod = costam::pobierzmetody<klasa>();
for(...; lista_metod.size; ...) printf metoda.nazwa();
Na potrzeby polimorfizmu i dynamic_cast<> wprowadzono opcjonalny mechanizm o nazwie RTTI (RunTime Type Information), który zajmuje się próbą określenia co-jest-czym w sensie typów obiektów wskazywanych. Jeżeli go wyłączysz w opcjach kompilatora, wszystkie dynamic_cast zaczna nagle zwracac zero albo rzucać wyjątki - poza tym program bedzie działać i będzie mniejszy. Włączenie RTTI powoduje że kompilator wygenerowuje całą serie ukrytych, statycznych opisów klas, zawierających informację o ich drzewach dziedziczenia. Tutaj już masz pierwszy problem: z RTTI nie dowiedz się niczego o czymś co klasą/strukturą nie jest. RTTI musi miec mozliwosc przyczepienia do kazdego tworzonego obiektu jakiegos 'linka' do tych informacji - wybrano mniej/bardziej sprytną wczepkę do vtable - więc z RTTI nie dowiesz się niczego o czymś co jest 'niepolimorficzną' klasą, nie posiadającą składowych wirtualnych. Dostęp do RTTI w kodzie masz poprzez dwie konstrukcje: dynamic_cast<> oraz typeid(). Jak one dziełają - wiesz. I to koniec. C++ więcej 'wglądu' w faktyczny nieznany obiekt nie przewiduje. Mozesz więc kombinowac z RTTI tworzac hm potworki(?) w stylu:
//pseudokod
void drzewo(void* obiekt)
{
if( dynamic_cast<klasaA1*>(obiekt) == 0 ) cout << "+klasaA1" << endl;
if( dynamic_cast<klasaA2*>(obiekt) == 0 ) cout << "+klasaA2" << endl;
if( dynamic_cast<klasaA3*>(obiekt) == 0 ) cout << "+klasaA3" << endl;
if( dynamic_cast<klasaB1*>(obiekt) == 0 ) cout << "+klasaB1" << endl;
if( dynamic_cast<klasaB2*>(obiekt) == 0 ) cout << "+klasaB2" << endl;
if( dynamic_cast<klasaB3*>(obiekt) == 0 ) cout << "+klasaB3" << endl;
if( dynamic_cast<klasaC1*>(obiekt) == 0 ) cout << "+klasaC1" << endl;
if( dynamic_cast<klasaC2*>(obiekt) == 0 ) cout << "+klasaC2" << endl;
if( dynamic_cast<klasaC3*>(obiekt) == 0 ) cout << "+klasaC3" << endl;
...
}
ale będzie bardzo ciężko Ci się dowiedziec, która klasa skladająca się na daną jest wyżej/niżej w drzewie. tym ciężej, że wszystkie typy musiałbyś wymieniać 'z palca', gdyż nie ma kogo ani jak odpytać o listę wszystkich znanych typów.. możesz kombinować cztając bezposrednio ze struktur RTTI - one w końcu zawierają dokladny opis dziedziczenia - jednak bedzie to dosc karkołomne..
Radziłbym więc Ci odejście od prób 'systemowych' i napisanie krótkiego, własnego rozwiązania:
//klasa bazowa
class Baza
{
...
public: virtual std::string typeofMe() const { return "Baza"; }
...
}
class Inna : cokolwiek // cokolwiek dziedzicyz po Bazie
{
...
public: virtual std::string typeofMe() const { return "Inna < " + cokolwiek::typeofMe(); }
...
}
itp.. tego typu proste kaskada pozwola Ci szybko zbadac cale potrzebne Ci drzewo. Nie sądzę, żebyś potrzebował więcej niż w/w.