Пытаясь считать экземпляры получения классов, type_id не работает

StackOverflow https://stackoverflow.com/questions/3746742

  •  04-10-2019
  •  | 
  •  

Вопрос

Я хочу считать все случаи получения из моего класса, я пытаюсь сделать это так:

.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

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

}

У меня есть два наследования, которые выглядят так (CPP содержит пустые реализации):

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

И это главная функция:

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

    Parant::PrintInstances();
....

В результате я получаю:

 typename: .PAVParant@@ ;; count: 3

Почему это не работает?

Я изменил это на

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

Конечно, он все еще не работает, хотя теперь я понимаю, почему ... Могу ли я получить это на работу?

Это было полезно?

Решение

typeid(*this) в конструкторе просто дает класс конструктора (у вас было это typeid(this) Но все равно неправильно, так как он просто даст вам тип_инфо указателя). Это считается динамическим типом объекта во время строительства.

Другое различие Существуют, что виртуальные функции, называемые во время строительства, не будут заканчиваться в полученном классе, но в классе, где вызов сделан во время строительства.

Другие советы

Йоханнес объясняет, почему это не работает.

В качестве возможного обходного пути вы можете пройти указатель на полученный экземпляр класса к Parent Конструктор с использованием списка инициализации:

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

Однако в Parent Конструктор, если вы разыгрываете этот указатель, typeid все равно скажут вам, что его динамический тип Parent. Отказ Вы можете, однако, сделать Parent Конструктор шаблона:

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

    // ...
};

Этот шаблон конструктора будет создан для каждого производного типа класса, а также T будет правильный тип полученного класса.

Этот подход становится сложнее с несколькими уровнями наследования, и он требует, чтобы вы проходили this Указатель на конструктор базового класса явно, но это один из способов «решить» проблему.

Вам необходимо позвонить в AddInstance от конструкторов дочерних классов для указателя «Это», чтобы иметь тип класса ребенка. Но это навязывает каждому ребенку класс, что они должны реализовать этот «интерфейс» вашего.

C ++ не поддерживает отражение как Java, поэтому это не может быть легко сделано в общем моде.

Вы можете заставить его работать, передавая имя класса от полученного класса, как ниже.

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

Остальная часть кода остается такой же, как то, что вы предоставили.

Это хватает ваша потребность? Использует 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top