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?

War es hilfreich?

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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top