في محاولة لحساب مثيلات الاستخلاص ، لا يعمل Type_id

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

  •  04-10-2019
  •  | 
  •  

سؤال

أريد أن أحسب جميع حالات derivers من صفي ، أحاول أن أفعل ذلك مثل:

.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