Der Versuch, Instanzen von Klassen ableiten zu zählen, tut type_id nicht Arbeit
Frage
Ich möchte alle Instanzen von derivers aus meiner Klasse zählen, ich versuche, es zu tun, wie so:
H-Datei:
#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
CPP-Datei:
#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 ;
}
}
Ich habe zwei Nachfolgern, dass wie folgt aussehen (die CPP enthält leere Implementierungen):
#pragma once
#include "parant.h"
class ChildA :
public Parant
{
public:
ChildA(void);
virtual ~ChildA(void);
};
und das ist die Hauptfunktion:
int main()
{
ChildA a;
ChildB b;
ChildA a1;
Parant::PrintInstances();
....
Das Ergebnis ich erhalte, ist:
typename: .PAVParant@@ ;; count: 3
Warum funktioniert es nicht?
Habe ich es zu
AddInstance(typeid(*this).raw_name());
natürlich ist es immer noch nicht funktioniert, obwohl ich jetzt verstehen, warum ... kann ich es an der Arbeit?
Lösung
typeid(*this)
in einem Konstruktor liefert nur Konstruktor der Klasse (Sie hatte es typeid(this)
aber das ist falsch sowieso, da es wird Ihnen nur die type_info geben einen Zeiger). Das ist der dynamische Typ des Objekts während der Bauphase berücksichtigt.
Ein weiterer Unterschied besteht, dass virtuelle während des Bau aufgerufenen Funktionen werden nicht in der abgeleiteten Klasse am Ende, aber in der Klasse, wo der Anruf während der Bauphase durchgeführt wird.
Andere Tipps
Johannes erklärt, warum funktioniert das nicht.
Als mögliche Abhilfe Sie einen Zeiger auf die abgeleitete Klasse Instanz mit dem Parent
Konstruktor mit der Initialisierungsliste passieren können:
struct ChildA : Parent
{
ChildA() : Parent(this) { }
};
Doch im Parent
Konstruktor, wenn Sie diese Zeigerdereferenzierung, typeid
werden Ihnen immer noch sagen, dass seine dynamische Art Parent
ist. Sie können jedoch machen die Parent
Konstruktor eine Vorlage:
struct Parent
{
template <typename T>
Parent(T* x)
{
AddInstance(typeid(T).raw_name());
}
// ...
};
Dieser Konstruktor Vorlage wird für jede abgeleitete Klasse Typ instanziert werden, und T
wird die richtige Art der abgeleiteten Klasse sein.
Dieser Ansatz wird schwieriger mit mehreren Ebenen der Vererbung und es erfordert, dass Sie die this
Zeiger auf die Basisklassenkonstruktor explizit übergeben, aber es ist ein Weg, um „zu lösen“ das Problem.
Sie müssen die addInstance von der untergeordneten Klasse Bauer für den „diesen“ Zeiger rufen zu sein von Kinderklassentyp. Aber das erlegt jedes Kind Klasse, dass sie diese „Schnittstelle“ implementieren, haben von Ihnen.
C ++ nicht Reflexion wie Java unterstützen, damit diese nicht einfach in einer generischen Art und Weise durchgeführt werden können.
Sie können es, indem Klassennamen von abgeleiteten Klasse funktioniert wie unten.
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")
{
}
};
Der Rest des Codes bleibt gleiche wie das, was Sie zur Verfügung gestellt.
Enthält diese genügen Ihren Bedarf? Verwendet 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;
}