C++ 如何通过更好的抽象避免typeid?
我在代码中使用了typeid,但在我看来,如果我避免使用typeid,代码可能会更干净 如果我们想存储类的类型,为什么首先要选择面向对象的语言 但我一次又一次地看到这种模式,我不知道如何避免它 所以我在想,这段代码是否可以写得更干净,有更好的抽象 代码如下:C++ 如何通过更好的抽象避免typeid?,c++,C++,我在代码中使用了typeid,但在我看来,如果我避免使用typeid,代码可能会更干净 如果我们想存储类的类型,为什么首先要选择面向对象的语言 但我一次又一次地看到这种模式,我不知道如何避免它 所以我在想,这段代码是否可以写得更干净,有更好的抽象 代码如下: class A { public: string type; }; template <typename T> class B : public A { public: B() { type =
class A {
public:
string type;
};
template <typename T>
class B : public A {
public:
B() {
type = typeid(T).name();
}
};
class Registry {
private:
std::vector<A *> list;
public:
void append(A * a) {
int found = 0;
for (A * el : list) {
if (a->type == el->type) {
found = 1;
break;
}
}
if (!found)
list.push_back(a);
}
int size() {
return list.size();
}
};
int main(int argc, char **argv) {
Registry reg;
A * b_int1 = new B<int>();
A * b_int2 = new B<int>();
A * b_float = new B<float>();
reg.append(b_int1);
reg.append(b_int2);
reg.append(b_float);
cout << reg.size() << endl;
return 0;
}
A类{
公众:
字符串类型;
};
模板
B类:公共A{
公众:
B(){
type=typeid(T).name();
}
};
类注册表{
私人:
std::向量表;
公众:
无效附加(A*A){
int=0;
对于(A*el:列表){
如果(a->type==el->type){
发现=1;
打破
}
}
如果(!找到)
列表。推回(a);
}
int size(){
返回list.size();
}
};
int main(int argc,字符**argv){
注册处注册;
A*b_int1=新的b();
A*b_int2=新的b();
A*b_float=新的b();
注册附加(b_int1);
注册附加(b_int2);
注册附加(b_浮动);
cout如果您不想要访客,但您想要快速的RTTI,我建议您查看以下文件:
这个想法是:
- 每个类都为自己的类型分配了一个不同的素数(例如,
a::my_type=2
;B::my_type=3
)
- 然后为每个类另外分配其类型与基类值(如果有)的乘积(例如,
A::can\u cast=A::my\u type
;B::can\u cast=B::my\u type*A::can\u cast;
)
这解决了是相同的\u动态的(
,是基本的\u动态的()
问题优雅:前者变成==
,后者变成%
要检查对象是否属于从给定类派生的类,可以使用动态\u cast
并将结果与null ptr
进行比较。不幸的是,鉴于我们需要检查未知类型的这一事实,我们需要必须对类A
的每个后代执行一次这样的比较方法,但可以使用#define
简化
总而言之,我可能会这样写:
#define TYPE_COMPARISON \
virtual bool compare(A* rhs) \
{ \
return dynamic_cast<decltype(this)>(rhs) != nullptr; \
}
class A {
public:
TYPE_COMPARISON
};
template <typename T>
class B : public A {
public:
TYPE_COMPARISON
};
class Registry {
private:
std::vector<A *> list;
public:
void append(A * a) {
int found = 0;
for (A * el : list) {
if (a->compare(el) && el->compare(a)) {
found = 1;
break;
}
}
if (!found)
list.push_back(a);
}
int size() {
return list.size();
}
};
#定义类型#比较\
虚拟布尔比较(A*rhs)\
{ \
返回动态_cast(rhs)!=nullptr\
}
甲级{
公众:
类型比较
};
模板
B类:公共A{
公众:
类型比较
};
类注册表{
私人:
std::向量表;
公众:
无效附加(A*A){
int=0;
对于(A*el:列表){
如果(a->比较(el)&&el->比较(a)){
发现=1;
打破
}
}
如果(!找到)
列表。推回(a);
}
int size(){
返回list.size();
}
};
此外,这种方法允许您定义是否应将特定的子类视为与其父类不同。typeid(T).name()
这不能保证是有意义的…所以最好只存储返回的类型信息。@loro,更像是不稳定类层次结构的反模式。除非实现a循环访问者模式,但这只是回到使用RTTI。为什么a不是多态的?@arash Comparetypeid(*a)
和typeid(*el)
在append
中。基类中至少需要一个虚拟函数。析构函数是一个流行的选择。@arash:“基本上,我们不想在一个列表中存储两个相同类型的对象。”…为什么?在需要(多态)列表的地方,您在做什么值,但每个值都必须是不同的类型?在我看来,如果你需要“一次又一次地”这样做,那么你在类型上似乎做错了什么。