Domanda

Voglio contare tutte le istanze di DERIVATORI della mia classe, sto cercando di farlo in questo modo:

file h:

#ifndef _Parant
#define _Parant

#include<map>

class Parant
{
public:
    Parant();
    virtual ~Parant();
    static void PrintInstances();

private:
    static void AddInstance(const char* typeName);
    static std::map<const char*, int> InstanceCounter;
};

#endif

file cpp:

#include "Parant.h"
#include <typeinfo>
#include <iostream>

using namespace std;

Parant::Parant()
{
    AddInstance(typeid(this).raw_name());
}


Parant::~Parant()
{
}


std::map<const char*, int> Parant::InstanceCounter;

void Parant::AddInstance(const char* typeName)
{
    InstanceCounter[typeName]++;
}


void Parant::PrintInstances()
{
    for(map<const char*,int>::iterator i = InstanceCounter.begin(); i != InstanceCounter.end(); i++)
    {
        cout << " typename: " << i -> first << " ;;" ;
        cout << " count: " << i -> second << endl ;
    }

}

Ho due eredi che assomigliano a questo (la cpp contiene implementazioni vuote):

#pragma once
#include "parant.h"
class ChildA :
    public Parant
{
public:
    ChildA(void);
    virtual ~ChildA(void);
};

e questa è la funzione principale:

int main()
{
    ChildA a;
    ChildB b;
    ChildA a1;

    Parant::PrintInstances();
....

Il risultato che ottengo è:

 typename: .PAVParant@@ ;; count: 3

Perché non funziona?

L'ho cambiato in

AddInstance(typeid(*this).raw_name());

Naturalmente lo fa ancora non funziona, anche se ora capisco perché ... posso farlo funzionare?

È stato utile?

Soluzione

typeid(*this) in un costruttore solo produce classe del costruttore (avete avuto typeid(this) ma questo è comunque sbagliato dal momento che sarà solo dare il type_info di un puntatore). Che è considerato il tipo dinamico dell'oggetto durante la costruzione.

Un'altra differenza è che le funzioni virtuali chiamati durante la costruzione non finiscono nella classe derivata, ma nella classe in cui viene effettuata la chiamata durante la costruzione.

Altri suggerimenti

Johannes spiega perché questo non funziona.

Come possibile soluzione, è possibile passare un puntatore all'istanza classe derivata al costruttore Parent utilizzando l'elenco di inizializzazione:

struct ChildA : Parent 
{
    ChildA() : Parent(this) { }
};

Tuttavia, nel costruttore Parent, se dereferenziare questo puntatore, typeid sarà ancora vi dirà che il suo tipo dinamico è Parent. È possibile, tuttavia, fare il Parent costruttore di un modello:

struct Parent
{
    template <typename T>
    Parent(T* x)
    {
       AddInstance(typeid(T).raw_name());
    }

    // ...
};

Questo modello costruttore verrà creata un'istanza per ogni tipo di classe derivata, e T sarà il tipo corretto della classe derivata.

Questo approccio diventa più difficile con più livelli di ereditarietà e richiede che si passa il puntatore this al costruttore della classe base in modo esplicito, ma è un modo per "risolvere" il problema.

È necessario chiamare l'AddInstance dai costruttori della classe bambino per il "questo" puntatore a essere di tipo classe figlio. Ma che impone su ogni classe figlia che devono implementare questa "interfaccia" del tuo.

C ++ non supporta riflessione come Java, quindi questo non può essere fatto facilmente in un modo generico.

È possibile farlo funzionare passando nome della classe da classe derivata come qui di seguito.

class Parent
{
public:
   Parent(const char* pClassName) //Gets called for every derived object with
   {                              //corresponding derived class name as parameter.
       AddInstance(pClassName);  //Instance count will be incremented here.
   }
};

class ChildA: public Parent
{
public:
    ChildA()
      : Parent("ChildA") //Pass the child class name to Parent.
    {
    }
};
class ChildB: public Parent
{
public:
    ChildB()
      : Parent("ChildB")
    {
    }
};

Il resto del codice rimane uguale a quello che hai fornito.

Fa questo basti il ??vostro bisogno? Utilizza CRTP

map<string, int> m;

template<class T> struct Base{
    Base(){
        m[typeid(T).name()]++;    // potentially unsafe
    }
};

struct Derived : Base<Derived>{
};

struct AnotherDerived : Base<AnotherDerived>{
};

int main(){
    Derived d1, d2;
    AnotherDerived d11, d21;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top