gpt4 book ai didi

c++ - 在运行时检查只有一种类型和 void* 的继承

转载 作者:搜寻专家 更新时间:2023-10-31 00:52:07 33 4
gpt4 key购买 nike

我需要一种方法来在运行时检查一个类型是否通过继承与匿名对象的类型相关,我的目的是空指针。

假设我有两种类型:

class Base
{
public:
virtual ~Base();
};

class Derived : public Base
{
public:
~Derived();
};

Base *base = new Derived();
Derived *derived = new Derived();

我需要实现以下功能:

template <typename T>
T *isRelated(void *obj, void *tag)
{
//If T is related to obj's real type (established based on tag value)
// return reinterpret_cast<T*>(obj);
//else
// return nullptr;
}

目前,我可以通过在 typetag 中存储任何一个值(在编译时确定并作为值返回)并比较是否相等来检查 obj 是否 与 T 是同一类型。 p>

换句话说,当前的 typetag 实现与此类似:

template <typename T>
void *getTypeTag();

template <>
void *getTypeTag<Base>()
{
return 1;
}

template <>
void *getTypeTag<Derived>()
{
return 2;
}

我可以在 typetag 中存储什么来检查继承关系?

我正在寻求一种可扩展的解决方案,因为会有很多具有频繁继承关系的类。

编辑/澄清:

  • 我正在使用第三方 API,它只会让我无效指针,因此基于类型化对象重载 isRelated 不是可能的
  • 动态转换是不可能的,因为它们在 T 和 void 之间不起作用*

最佳答案

我添加了另一个答案,它不依赖于未定义的行为。


警告:下面的答案取决于未定义的行为

C++14 标准: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf

Chapter 10, Section 5:

The order in which the base class subobjects are allocated in the most derived object (1.8) is unspecified

按照这个逻辑,我的回答中的reinterpret_cast 将依赖于未定义的行为来工作。此外,考虑到正在转换 void* - 似乎无法在不知道原始类型的情况下将其安全地转换为基类。


提出了一种可能的解决方案,效果很好 - 但它在以下方面存在限制:

  • 我必须使用反射(reflect)原始类型继承的继承模式来专门化 TypeTagSpec
  • 验证发生在类型层,而不是对象指针层(这在最后一段中阐明)

考虑到设计的示例类 Base 和 Derived,假设我们将再添加一个类“Unrelated”:

// Some class which is not related to our inheritance check, for testing later
class Unrelated
{
public:
virtual ~Unrelated(){}
};

现在,后续的专用 TypeTagSpec 结构将被实例化并作为 void *tag 传递给某些 API:

// This is the base class, and we will initially cast all void *tag objects to this type
struct TypeTag
{
virtual ~TypeTag(){}
};

// Unspecialized template derives from TypeTag, to give us a way 'up' the inheritance
template <typename T>
struct TypeTagSpec : TypeTag
{
virtual ~TypeTagSpec(){}
};

// Specialized testing typetag for Unrelated type, used for testing
template <>
struct TypeTagSpec<Unrelated> : TypeTag
{
virtual ~TypeTagSpec(){}
};

// Specialized Base typetag, nothing special
template <>
struct TypeTagSpec<Base> : TypeTag
{
virtual ~TypeTagSpec(){}
};

// Magic here - specialized tagtype for Derived actually inherits from Base typetag, giving a clear inheritance line
template <>
struct TypeTagSpec<Derived> : TypeTagSpec<Base>
{
virtual ~TypeTagSpec(){}
};

这给我们留下了代码:

// The solution
template <typename T>
T *isRelated(void *obj, void *tag)
{
const TypeTag *typetag = reinterpret_cast<TypeTag*>(tag);
if(dynamic_cast<const TypeTagSpec<T>*>(typetag))
return reinterpret_cast<T*>(obj);
return nullptr;
}

TEST(TypeTag, Inheritance)
{
Derived *derived = new Derived();
TypeTag *typetag = new TypeTagSpec<Derived>();

// Test begins here
void *obj = derived;
void *tag = typetag;

EXPECT_EQ(isRelated<Base>(obj, tag), derived);
EXPECT_EQ(isRelated<Derived>(obj, tag), derived);
EXPECT_EQ(isRelated<Unrelated>(obj, tag), nullptr);
// Test ends here

delete derived;
delete typetag;
}

重要的是要注意,问题是查找类型是否相关,因此此测试将通过:

 auto *base = new Base();
auto *tag = new TypeTagSpec<Base>();
EXPECT_EQ(isRelated<Derived>(base, tag), base);

在这个测试中,isRelated 仍然会返回一个指向 base 的指针;在实践中,这个指针可能并不总是有效/可用,这取决于正在转换的类。因为我的用例涉及向上转换类型层关系检查,所以我不关心这个对象有效性的细微差别——而且从类型角度(而不是对象角度)来看,这种关系在技术上仍然有效。

旁注:谁在提出我的原始问题后 5 分钟内就否决了我的原始问题,谁是微不足道的,并且比提供帮助更快乐。

关于c++ - 在运行时检查只有一种类型和 void* 的继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52867773/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com