Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对空心铸件的运行时检查*_C++_Object_Dynamic Cast_Typechecking_Runtime Type - Fatal编程技术网

C++ 对空心铸件的运行时检查*

C++ 对空心铸件的运行时检查*,c++,object,dynamic-cast,typechecking,runtime-type,C++,Object,Dynamic Cast,Typechecking,Runtime Type,假设我有一个void*包含一个指向未知类的指针。我想使用dynamic\u cast对我实际拥有的类类型进行运行时检查。例如: class Foo {}; void* bar = new Foo; 如果我尝试执行dynamic\u cast(bar) “void*”:动态强制转换的表达式类型无效 但是我需要dynamic\u cast,因为在我的实际情况下,我不确定bar实际上是Foo* 我已经读过,解决这个问题的一个方法是为bar可能包含的所有对象创建一个基类,重新解释\u cast指向该

假设我有一个
void*
包含一个指向未知
类的指针。我想使用
dynamic\u cast
对我实际拥有的类类型进行运行时检查。例如:

class Foo {};

void* bar = new Foo;
如果我尝试执行
dynamic\u cast(bar)

“void*”:动态强制转换的表达式类型无效

但是我需要
dynamic\u cast
,因为在我的实际情况下,我不确定
bar
实际上是
Foo*

我已经读过,解决这个问题的一个方法是为
bar
可能包含的所有对象创建一个基类,
重新解释\u cast
指向该基类的指针,然后尝试从指向
Foo
的对象指针中执行
动态\u cast


这对我来说很困难,因为存储在
bar
中的对象并非都在我的控制之下。(因为尝试重新创建Java会让我心痛。)还有其他方法可以做到这一点吗?

为了确保dynamic_cast编译并工作,您应该使用虚拟方法创建一个抽象类或接口类

#include <cassert>

class Bar
{
public:
    Bar() = default;
     virtual ~Bar() = default;
};

class Foo : public Bar
{
public:
    Foo() = default;
    virtual ~Foo() = default;
};

int main()
{
    Bar* bar = new Foo;
    Foo* foo = dynamic_cast<Foo*>(bar);
    assert(foo != nullptr);
}
#包括
分类栏
{
公众:
Bar()=默认值;
virtual~Bar()=默认值;
};
Foo类:公共酒吧
{
公众:
Foo()=默认值;
virtual~Foo()=默认值;
};
int main()
{
Bar*Bar=新的Foo;
Foo*Foo=动态施法(条形);
断言(foo!=nullptr);
}

据我所知,您需要一个多态对象,但不需要公共基类

对于这一点,已经有一个相当标准的习惯用法-它被称为
boost::any

boost::any
携带您的对象和一些类型信息。该接口允许您查询该类型,并尝试将any转换为您要查找的类型


动态强制转换
用于将多态对象强制转换为一个类,该类的对象类型与您试图强制转换为其父对象的对象类型相同

void*
与此完全不同。 使用指向void的指针,您实际上是在剥离所有类型信息

dynamic\u cast
知道有一个基类,可以通过RTTI进行类型检查

当你抛出一个空指针时,你对编译器说:“是的,你知道内存中的这个位置吗?好吧,把它当作这个类型使用。”如果内存无效,就会调用UB

你有三个选择

选项1 使用接口。 嗯,多态基类是执行
动态\u cast
的唯一方法。没有别的办法,没有黑客,这是唯一的办法。就这么简单

struct Base { virtual ~Base() = default; };

struct Derived : Base {};

// ...

void test (Base* base) {
    auto derived = dynamic_cast<Derived*>(base);

    if (derived) {
        // derived is valid here.
    }
}
struct Base{virtual~Base()=default;};
派生结构:基{};
// ...
空隙试验(基准*基准){
自动导出=动态_铸造(基础);
if(派生){
//这里的派生表达式有效。
}
}
选项2 用指针标识类型 我使用一种方法为每个类型指定一个唯一的标识符,并使用该标识符验证强制转换。在没有任何RTTI的情况下完成

using type_id_t = void(*)();
template <typename T> void type_id() {}

// now we can use a map or a vector.
std::vector<std::pair<type_id_t, void*>> vec;

template<typename T>
void insertToMyVector(T* obj) {
    vec.emplace_back(type_id<T>, obj);
}

template<typename T>
T* getObj(int index) {
    auto item = vec[index];

    return static_cast<T*>(item.first == &type_id<T> ? item.second : nullptr);
}

// ...

int main () {
    auto foo = new Foo;

    insertToMyVector(foo);

    auto maybeFoo = getObj<Foo>(0);

    if (maybeFoo) {
        // you have a valid Foo here
    }
}
使用类型_id_t=void(*)();
模板无效类型_id(){}
//现在我们可以使用地图或向量。
std::vec;
模板
void insertToMyVector(T*obj){
向量安放(类型id,obj);
}
模板
T*getObj(整数索引){
自动项=向量[索引];
返回静态_cast(item.first==&type_id?item.second:nullptr);
}
// ...
int main(){
自动foo=新foo;
插入式TomyVector(foo);
自动maybeFoo=getObj(0);
如果(maybeFoo){
//你这里有一个有效的Foo
}
}
选项3 为任何类型生成派生类 这是非常有用的,因为它可以容纳任何类型,同时保持类型安全。我看起来像解决方案1,但提供了更多的灵活性。技巧是使用模板为任何类型生成派生类。优点是你可以持有任何类型,但可能会使你复杂一点

struct Base { virtual ~Base() = default; };

template<typename T>
struct Derived : Base {
    Derived(T&& obj) : _obj{std::move(obj)} {}
    Derived(const T& obj) : _obj{obj} {}

    T& get() {
        return _obj;
    }

    const T& get() const {
        return _obj;
    }

private:
    T _obj;
};

// ...

void test (Base* base) {
    auto derived = dynamic_cast<Derived<int>*>(base);

    if (derived) {
        int i = derived->get();
        // derived is valid here, and we can safely access the int
    }
}
struct Base{virtual~Base()=default;};
模板
派生结构:基{
派生(T&&obj):_obj{std::move(obj)}{
派生(const T&obj):_obj{obj}{
T&get(){
返回对象;
}
常量T&get()常量{
返回对象;
}
私人:
T_obj;
};
// ...
空隙试验(基准*基准){
自动导出=动态_铸造(基础);
if(派生){
int i=派生->获取();
//在这里派生是有效的,我们可以安全地访问int
}
}

然后你需要一些额外的状态来告诉你它是什么类型。设计一个接口/抽象类并声明该类型的bar。相关:即使添加一个基类,我相信
dynamic\u cast
解决方案只有当指针真正指向从该基类派生的东西时才有效;如果你想坚持这么多,你应该让你的接口接受指向基的指针,而不是空指针!好吧,这就是断开连接。我认为“可能存储在bar中的对象不都在我的控制之下”意味着您甚至在调用时都没有控制它(即,不仅类不在您的控制之下,而且强制转换到
void*
的调用点也不在您的控制之下)。如果你控制了呼叫点,那么是的,你可以保证你使用包装器。但是我认为你的评论不止这些,对吗?具体来说,
Bar
子对象需要是另一个对象的包装器。这在这里起作用,但不能解决OP的问题,因为OP无法控制传递给其函数的某些对象。因此,他不能让它们来自一个共同的对象。1是在问题的链接中提出的,不是一个理想的解决方案。2是第一次提出的,但不是解决我问题的好办法。3是所描述的解决方案,是迄今为止最有前途的。2可以通过使用改进,3可以通过添加强制转换操作符而不是
get
operator T(){return\u obj;}
我宁愿添加
operator*
operator->
而不是转换操作符。或者使转换运算符显式可以