题
我想计算我班级的所有嘲讽情况,我试图这样做:
.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)
但这无论如何都是错误的,因为它只会为您提供指针的type_info)。这被认为是施工过程中对象的动态类型。
另一个区别是,在施工过程中调用的虚拟功能不会在派生的类中最终出现,而是在施工期间进行调用的类。
其他提示
约翰内斯解释了为什么这不起作用。
作为可能的解决方法,您可以将指针传递给派生的类实例 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;
}
不隶属于 StackOverflow