微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++ instanceof 适用于父类,但不适用于子类

如何解决C++ instanceof 适用于父类,但不适用于子类

我正在学习使用虚幻引擎开发游戏的 C++。

我正在使用从 C++ equivalent of instanceof 复制的下一个代码来检查对象是否是类的实例:

template<typename Base,typename T>
inline bool instanceof(const T*) {
    return std::is_base_of<Base,T>::value;
}

我有以下方法签名:

void OnHit(UPrimitiveComponent* HitComp,AActor* OtherActor,UPrimitiveComponent* OtherComp,FVector normalImpulse,const FHitResult& Hit);

在上述方法中,我想检查 OtherActor 是否是类 Paddle 的实例。 Paddle 继承自 APawn,后者继承自 AActor

OtherActorAPaddle 实例时,以下代码返回 false:

if (instanceof<APaddle>(OtherActor))

为了检查 instanceof 是否有效,我尝试了以下代码,并且有效(返回 true):

if (instanceof<AActor>(OtherActor))

为什么它不适用于子类 (APaddle)?

解决方法

您的 isinstanceof 只会检查静态情况。请注意,您的函数的结果实际上并不取决于参数 isinstanceof,即对象本身。它只取决于参数/对象的类型

您需要的是动态检查。为此,有 dynamic_cast

像这样

template<typename Base,typename T>
inline bool instanceof(const T* t) {
    return dynamic_cast<const Base*>(t) != nullptr;
}

但请注意:要使其正常工作,您需要 Base 中的虚函数。如果 Base 不是虚拟基类,则 C++ 中无法执行 instanceof 检查。

,

在提出 SO 问题时,一个最小的完整可验证示例通常是一个好主意。这是我的尝试:

struct AActor {};
struct APawn:AActor {};
struct APaddle:APawn {};

APaddle paddle;
AActor* OtherActor = &paddle;

assert( instanceof<APaddle>(OtherActor) );
assert( instanceof<AActor>(OtherActor) );

第一个断言是假的,第二个是真的,你想知道为什么吗?

std::is_base_of 检查类型信息,而不是实例信息。

return std::is_base_of<Base,T>::value;

APaddle 的情况下,这是

return std::is_base_of<APaddle,AActor>::value;

询问“APaddleAActor 的基类吗?”很明显不是。

AActor 情况下:

return std::is_base_of<AActor,AActor>::value;

C++ 认为 TT 的基类——你是你自己的基类(!)——至少在这个特性中是这样。所以它返回真。

函数从不检查传入的指针,因此您的 AActor 指针实际上是 APaddle 的事实无关紧要。

如果您想动态测试类型是否匹配,您 (a) 必须确保您的类型是多态的,并且 (b) 应该重新考虑,以及 (c) 使用 dynamic_cast

struct AActor {
  virtual ~AActor() {}
};
struct APawn:AActor {};
struct APaddle:APawn {};

// is the argument pointing to an instance of the type X?
template<class X,class T>
bool instanceof(T const* ptr) {
  return nullptr != dynamic_cast<X const*>(ptr);
}

现在您的代码按预期工作。请注意,dynamic_cast 并不总是有效;在某些情况下,它是不明确的,无法进行类型转换,或者类型不够多态。 C++ 不要求所有对象(无论是结构体还是类)都支持内置的运行时类型信息 (RTTI),并且不支持它的类型无法(通过动态转换)查询它们的真实类型。

对于 (b),查询多态对象的确切类型违反了 LSP,并将继承层次结构与算法实现以一种不能很好扩展的方式耦合。

举一个由 (b) 引起的例子,假设你有水果,水果最初可以是苹果或橙子。

您使用一堆动态转换编写代码,以确定您正在处理的水果是苹果还是橙子,并以不同的方式处理它。

然后您想添加新班级,普通话。普通话应该像橙子一样,但在幕后却有着完全不同的实现。

您的每个动态演员都将您的普通话检测为非橙色。

另一方面,如果你有一个

virtual bool IsOrange() const = 0;

在你的界面中,并用它来检测橙子而不是动态转换,然后普通话可以自由地假装是橙子而不是真正的橙子。

这要求您的界面实际上足以解决您的问题。

顺便说一句,您使用的网站是由不擅长 C++ 的人编写的,请考虑使用其他资源。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。