在运行时从指向基 class 的指针获取对象的类型
Get object's type from pointer to base class at runtime
我正在使用一个 class 库,其中所有 class 都是直接或间接地从基础 class Base
派生的,并且有一个名称。该库提供了一种按名称搜索对象的工具,这将 return 一个 Base*
.
有没有什么方法可以找到 returned 对象的类型,而无需像我在以下示例中那样使用 dynamic_cast
s 检查所有可能性?如果可能的话,我想避免这种情况,因为派生的 classes 有模板参数,这有很多可能性。
如果我至少能够在不知道模板类型的情况下找出 class 类型(T1
或 T2
,在下面的示例中),那也很好, IE。做类似 dynamic_cast<T1<i_dont_care>*>
.
的事情
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {}
};
template <typename T> class T1 : public Base {};
template <typename T> class T2 : public Base {};
Base *find_by_name() {
return new T2<int>();
}
int main() {
Base *b = find_by_name();
if (T1<int> *p = dynamic_cast<T1<int>*>(b)) {
cout << "T1<int>" << endl;
// do something meaningful with p
} else if (T1<double> *p = dynamic_cast<T1<double>*>(b))
cout << "T1<double>" << endl;
else if (T2<int> *p = dynamic_cast<T2<int>*>(b))
cout << "T2<int>" << endl;
else if (T2<double> *p = dynamic_cast<T2<double>*>(b))
cout << "T2<double>" << endl;
else
cout << "unknown" << endl;
delete b;
return 0;
}
注意上面的例子是简化的,即。在每个 if
中,我都会用 p
.
做一些有意义的事情
我确实意识到这从一开始就是糟糕的设计,但是我坚持使用这个库,而且我也没有办法改变它的实现。
有类似 typeid
http://en.cppreference.com/w/cpp/language/typeid 的东西,应用于多态表达式将在运行时评估其类型表示。
以下 wiki 示例:https://en.wikipedia.org/wiki/Run-time_type_information#dynamic_cast
#include <iostream>
#include <typeinfo> // for 'typeid'
class Person {
public:
virtual ~Person() {}
};
class Employee : public Person {
};
int main()
{
Person person;
Employee employee;
Person* ptr = &employee;
Person& ref = employee;
// The string returned by typeid::name is implementation-defined
// Person (statically known at compile-time)
std::cout << typeid(person).name() << std::endl;
// Employee (statically known at compile-time)
std::cout << typeid(employee).name() << std::endl;
// Person* (statically known at compile-time)
std::cout << typeid(ptr).name() << std::endl;
/* Employee (looked up dynamically at run-time
* because it is the dereference of a
* pointer to a polymorphic class) */
std::cout << typeid(*ptr).name() << std::endl;
// Employee (references can also be polymorphic)
std::cout << typeid(ref).name() << std::endl;
}
有一个typeid
operator, which returns an instance of std::type_info
,用它可以得到类型的名称。
但不确定这是否对您有帮助。首先,不能保证返回的名称在不同的实现中是相同的。第二 - 一旦你有了名字,你会做什么?您可能会将它与您的预定义名称进行比较,但这可能比一堆 dynamic_cast
慢。
如果您的 Base
class 或新的中间层级没有类型支持,dynamic_cast
是您的最佳选择。实际上它会非常快(通常只有一条比较指令)。
中间层是指:
class Base {
public:
virtual ~Base() {}
};
class T1Base : public Base {};
class T2Base : public Base {};
template <typename T> class T1 : public T1Base {};
template <typename T> class T2 : public T2Base {};
int main() {
Base *b = find_by_name();
if (dynamic_cast<T1Base*>(b))
cout << "T1" << endl;
else if (dynamic_cast<T2Base*>(b))
cout << "T2" << endl;
else
cout << "unknown" << endl;
delete b;
return 0;
}
我正在使用一个 class 库,其中所有 class 都是直接或间接地从基础 class Base
派生的,并且有一个名称。该库提供了一种按名称搜索对象的工具,这将 return 一个 Base*
.
有没有什么方法可以找到 returned 对象的类型,而无需像我在以下示例中那样使用 dynamic_cast
s 检查所有可能性?如果可能的话,我想避免这种情况,因为派生的 classes 有模板参数,这有很多可能性。
如果我至少能够在不知道模板类型的情况下找出 class 类型(T1
或 T2
,在下面的示例中),那也很好, IE。做类似 dynamic_cast<T1<i_dont_care>*>
.
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {}
};
template <typename T> class T1 : public Base {};
template <typename T> class T2 : public Base {};
Base *find_by_name() {
return new T2<int>();
}
int main() {
Base *b = find_by_name();
if (T1<int> *p = dynamic_cast<T1<int>*>(b)) {
cout << "T1<int>" << endl;
// do something meaningful with p
} else if (T1<double> *p = dynamic_cast<T1<double>*>(b))
cout << "T1<double>" << endl;
else if (T2<int> *p = dynamic_cast<T2<int>*>(b))
cout << "T2<int>" << endl;
else if (T2<double> *p = dynamic_cast<T2<double>*>(b))
cout << "T2<double>" << endl;
else
cout << "unknown" << endl;
delete b;
return 0;
}
注意上面的例子是简化的,即。在每个 if
中,我都会用 p
.
我确实意识到这从一开始就是糟糕的设计,但是我坚持使用这个库,而且我也没有办法改变它的实现。
有类似 typeid
http://en.cppreference.com/w/cpp/language/typeid 的东西,应用于多态表达式将在运行时评估其类型表示。
以下 wiki 示例:https://en.wikipedia.org/wiki/Run-time_type_information#dynamic_cast
#include <iostream>
#include <typeinfo> // for 'typeid'
class Person {
public:
virtual ~Person() {}
};
class Employee : public Person {
};
int main()
{
Person person;
Employee employee;
Person* ptr = &employee;
Person& ref = employee;
// The string returned by typeid::name is implementation-defined
// Person (statically known at compile-time)
std::cout << typeid(person).name() << std::endl;
// Employee (statically known at compile-time)
std::cout << typeid(employee).name() << std::endl;
// Person* (statically known at compile-time)
std::cout << typeid(ptr).name() << std::endl;
/* Employee (looked up dynamically at run-time
* because it is the dereference of a
* pointer to a polymorphic class) */
std::cout << typeid(*ptr).name() << std::endl;
// Employee (references can also be polymorphic)
std::cout << typeid(ref).name() << std::endl;
}
有一个typeid
operator, which returns an instance of std::type_info
,用它可以得到类型的名称。
但不确定这是否对您有帮助。首先,不能保证返回的名称在不同的实现中是相同的。第二 - 一旦你有了名字,你会做什么?您可能会将它与您的预定义名称进行比较,但这可能比一堆 dynamic_cast
慢。
如果您的 Base
class 或新的中间层级没有类型支持,dynamic_cast
是您的最佳选择。实际上它会非常快(通常只有一条比较指令)。
中间层是指:
class Base {
public:
virtual ~Base() {}
};
class T1Base : public Base {};
class T2Base : public Base {};
template <typename T> class T1 : public T1Base {};
template <typename T> class T2 : public T2Base {};
int main() {
Base *b = find_by_name();
if (dynamic_cast<T1Base*>(b))
cout << "T1" << endl;
else if (dynamic_cast<T2Base*>(b))
cout << "T2" << endl;
else
cout << "unknown" << endl;
delete b;
return 0;
}