如何查找多态基类向量中包含的对象的类型?
how to find type of an object contained in a vector of polymorphic base class?
假设我有一个超级多态基类 Shape,其中许多其他形状类都是从它派生的。
现在,如果我有一个 Shape 指针向量,其中包含指向不同形状类型列表的指针,如下所示:
vector<Shape*> p; // p contains pointer to many different shape objects
我知道要访问向量 p 中每个形状的方法和成员,我需要使用 dynamic_cast。
但是,如果我不知道向量 p 在运行时实际包含什么怎么办? 如何在运行时安全地找到向量 P 中包含的对象的类型?
我也知道我可以检查 dynamic_cast 的强制转换是否返回 NULL 以获得成功。 但这是否意味着要在向量 p 中找到我的形状对象的实际类型 我必须做这样的事情:
if (dynamic_cast<Circle*> p[i] !=NULL){
// do stuff
}
else if (...) {
}
并对所有其他形状类型重复此模式?
但是如果我有 100 种可能的形状,这就会变得很麻烦。 在朗姆泰姆有更好的方法来实现这一目标吗?
PS-考虑以下场景:
假设我需要遍历 Shape* 向量,例如将所有圆形对象放在一个单独的向量和向量中......现在我需要知道对象的实际类型。检查许多形状的 typeid 和 dynamic_casts 的返回是不切实际的。
您可以在typeinfo
标头中使用typeid
。
例如,请参阅以下问题:如何在运行时确定C++的实际对象类型;
然而,实际的问题是"为什么你需要知道对象的实际类型?":这是AFAIK不需要那么频繁需要这样的功能,因为多态性已经允许管理绝大多数用例。
我知道可以访问矢量中每个形状的方法和成员 p,我需要使用dynamic_cast。
不,不一定! 在您的情况下,假设Shape
有一个area
方法,在Circle
和Rectangle
(它们都扩展了Shape
类)中(重新)定义,也许以下内容就足够了:
std::vector<Shape*> shapes;
Rectangle rect(...);
Circle circle(...);
shapes.push_back( &rect );
shapes.push_back( &circle );
shapes[0]->area(); // --> calls Rectangle::area()
shapes[1]->area(); // --> calls Circle::area()
我想出了我并不真正自豪的解决方案,但也许它将有助于创建更好的解决方案。 我试图实现的关键是摆脱明确的dynamic_cast并让这个工作。不过,仍然需要两次命名您的 derieved 类型。 此外,它使用被告知很慢的std::function
。需要C++14。 我相信有一种方法可以通过巧妙地使用模板来做到这一点。或者至少摆脱type_switch<A>::cast<B>
车道。无论如何,代码:
#include <iostream>
#include <functional>
#include <typeindex>
#include <unordered_map>
// Basic inheritance cases
struct A
{
virtual void foo() = 0;
};
struct B : public A
{
void foo() override { }
void bfoo() {
std::cout << "B specificn";
}
};
struct C : public A
{
void foo() override { }
};
template <typename T>
struct type_switch
{
using Func = std::function<void(T&)>;
using Pair = std::pair<std::type_index, Func>;
using Map = std::unordered_map<std::type_index, Func>;
Map map;
type_switch(std::initializer_list<Pair> l) : map(l.begin(),l.end())
{
}
void call(T& a)
{
map[typeid(a)](a);
}
// allows for "oneliner", without explicit 'call', but it could end in creation of
// new type_switch on every loop iteration etc.
type_switch(T&a, std::initializer_list<Pair> l) : type_switch(l){
call(a);
}
template <typename T2>
static Func cast(std::function<void(T2&)> f)
{
static_assert(std::is_base_of<T, T2>::value, "Invalid cast operation on functors, T2 is not base of T");
// lot of functor copyings...
return[f = std::move(f)](T& t) {
f(static_cast<T2&>(t));
};
}
};
int main()
{
B b;
C c;
int local = 0;
type_switch<A> sw = {
{ typeid(B), type_switch<A>::cast<B>( [&local](auto& a) { // auto will deduce into B! No explicit casting
std::cout << "Handle b, local value is " << local << 'n';
a.bfoo(); // B specific
local++; // some outer scode operation
}) } ,
{ typeid(C), type_switch<A>::cast<C>([&local](auto& a) { // auto will deduce into C! No explicit casting
std::cout << "Handle c, local value is " << local << 'n';
local++; // some outer scode operation
})
},
/* // this one would trigger static_assert
{ typeid(int), type_switch<A>::cast<int>([&local](auto& a) { // auto will deduce into C! No explicit casting
std::cout << "Handle int, local value is " << local << 'n';
local++; // some outer scode operation
})
},*/
};
sw.call(b);
sw.call(c);
return 0;
}
- 是否需要删除包含对象的"pair"?
- 如何在h文件中包含.o对象文件
- 指针数据类型变量如何包含对象?
- C++ 矢量不显示包含对象的数据
- 唯一 ptr 将所有权移动到包含对象的方法
- 通过引用返回包含对象的向量
- 仅在删除包含对象的向量时调用自定义»析构函数«
- QML中包含对象的QABSTRACTLISTMODEL的缺点
- std::list::merge() 对于包含对象的列表失败
- 从 std::aligned_union_t 获取指向包含对象的指针
- 通过QLIST迭代并在包含对象上调用函数
- 检查子对象的地址是否在包含对象的边界内是否合法
- std::vector 调用在重新分配时无论如何都包含对象的析构函数?
- C++ 如何获取对包含对象的引用
- 从包含对象指针的列表中删除
- 对于数据成员,如果包含对象已在动态内存中,则动态分配此变量(或不动态分配)之间是否有任何区别
- C++标准库容器相对于所包含对象的线程安全性
- 包含对象的结构的向量
- 包含对象的 C++ 结构
- 正在计算包含对象的此指针