Pregunta

Quiero contar todas las instancias de derivers de mi clase, yo estoy tratando de hacerlo de esta manera:

archivo .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

archivo .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 ;
    }

}

Tengo dos herederos que se ven así (CPP contiene implementaciones vacías):

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

y esta es la principal función:

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

    Parant::PrintInstances();
....

El resultado que obtengo es:

 typename: .PAVParant@@ ;; count: 3

¿Por qué no funciona?

He cambiado a

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

Por supuesto que sigue sin funcionar, aunque ahora entiendo por qué ... puedo conseguir que funcione?

¿Fue útil?

Solución

typeid(*this) en un constructor simplemente da clase de constructores (que lo tenía typeid(this) pero eso es de todos modos equivocada ya que sólo le dará la type_info de un puntero). Eso se considera el tipo dinámico del objeto durante la construcción.

Otra diferencia no es que las funciones virtuales llamadas durante la construcción no va a terminar en la clase derivada, pero en la clase en la que se realiza la llamada durante la construcción.

Otros consejos

Johannes explica por qué esto no funciona.

Como posible solución, puede pasar un puntero a la instancia de la clase derivada al constructor Parent utilizando la lista de inicialización:

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

Sin embargo, en el constructor Parent, si eliminar la referencia de este puntero, typeid todavía le dirá que su tipo dinámico es Parent. Puede, sin embargo, que el constructor Parent una plantilla:

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

    // ...
};

Esta plantilla constructor se crea una instancia para cada tipo de clase derivada, y T será el tipo correcto de la clase derivada.

Este enfoque se vuelve más difícil con múltiples niveles de herencia y se requiere que se pase el puntero this al constructor de la clase base explícita, pero es una manera de "resolver" el problema.

Es necesario llamar a la AddInstance de los constructores de clase hijo para el puntero "this" a ser de tipo clase hija. Pero eso impone a cada clase hija que tienen que poner en práctica esta "interfaz" de los suyos.

C ++ no soporta la reflexión como Java así que esto no se puede hacer fácilmente de forma genérica.

Se puede hacer que funcione pasando nombre de clase de la clase derivada, como a continuación.

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")
    {
    }
};

Resto del código permanece igual a lo que ya ha proporcionado.

¿Tiene esto suficiente para sus necesidades? Utiliza 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;
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top