将void *转换为具有多重继承的类 [英] cast void* to classes with multiple inheritance

查看:98
本文介绍了将void *转换为具有多重继承的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到类似以下问题:

When is static cast safe when you are using multiple inheritance?

多重继承:从void转换后的意外结果*到第二个基类

,但是我真的不明白为什么它不起作用,因为我正在做建议的事情(回溯到原始的

but I really don't understand why it does not work, since I'm doing what is suggested (cast back to the original type).

还涉及模板。

我有一个通用的模板对象容器,可以实现作为 std :: string ID和 void *

I have a generic container of templated objects which I implement as a map of std::string IDs and void*:

std::map<std::string, void*> mymap;

对象如下所示:

template <class T>
class A {
   virtual void f1(const T&) = 0;
};

class T1 {};
class T2 {};

class B : public A<T1> {
   void f1(const T1&) override;
} 

class D {
   virtual void f3 () {};
}

class C : public A<T2>,
          public D
{
   void f1(const T2&) override;
}

在主代码中,我有类似的东西可以将我的对象添加到根据类型映射并调用适当的方法。

In the main code, I have something like this to add my objects to the map and call the appropriate method depending on the type:

template <class T>
void addClass(A<T>& a, std::string id){
    std::pair<std::string, void*> pair(id, (void*)&a);
    mymap.insert(pair);
}

template<class T>
void callback(A<T>&a, std::string typeID) {
    static_cast<A<T>*>(mymap[typeID])->f1();
}

该字符串清楚地标识了将哪个类用作模板,因此回调可以强制转换回正确的类型。

The string unambiguously identifies what class is being used as a template, so that the callback can cast back to the correct type.

只要我传递给 addClass 对象,一切都可以正常工作 B ,即具有纯虚拟模板类 A 的单个继承。

Everything worked just fine as long as I passed to addClass objects like B, i.e. with single inheritance from the pure virtual templated class A.

一旦我传递了像 C 这样的对象,即具有 A 和<$的多重继承c $ c> D ,在我进行转换的回调中,即使我没有编译错误,也会产生SEGFAULT。

As soon as I pass an object like C, i.e. with multiple inheritance from A and D, the callback where I do the casting produces a SEGFAULT, even though I have no compilation errors.

更新。显然,问题出在 std :: shared_ptr 的使用中,而不是强制转换本身。这是MCVE。

UPDATE. Apparently, the problem was in the std::shared_ptr use rather than in the casting itself. Here is the MCVE.

classes.hpp

#pragma once
#include <iostream>
#include <map>

template <class T>
class A {
public:
   virtual void f1(const T&) = 0;
};

class T1 {
public:
    double t1 = 10.0;
};
class T2 {
public:
    short int t2 = 8;
};

class B : public A<T1> {
public:
   void f1(const T1&) override;
};

class D {
public:
   virtual void f3();
};

class C : public A<T2>,
          public D
{
public:
   void f1(const T2&) override;
};

class MyContainer{
public:
    std::map<std::string, void*> mymap;

    template<class T>
    void addClass(A<T>& t, std::string id);

    template<class T>
    void callback(T& t, std::string id);
};

template<class T>
void MyContainer::addClass(A<T> &a, std::string id){
    std::pair<std::string, void*> pair(id, (void*)&a);
    mymap.insert(pair);
}

template<class T>
void MyContainer::callback(T& t, std::string id){
    static_cast<A<T>*>(mymap[id])->f1(t);
}

classes.cpp

#include <classes.hpp>

void B::f1(const T1& t1){
    std::cout << "Hello from B using t1: " << t1.t1 << std::endl;
}

void C::f1(const T2 & t2){
    std::cout << "Hello from C using t2: " << t2.t2 << std::endl;
}

void D::f3() {
    std::cout << "Hello from D" << std::endl;
}

main.cpp

#include <iostream>
#include <classes.hpp>
#include <memory>
using namespace std;

int main()
{
    std::shared_ptr<B> b(new B()); // inherits from A<T1>
    std::shared_ptr<C> c(new C()); // inherits from A<T2> and D


    MyContainer container;
    // no need to specify the template,
    // it is implict from the class being passed
    container.addClass(*b, "t1");
    container.addClass(*c, "t2");

    T1 t1;
    T2 t2;

    container.callback(t1, "t1");
    container.callback(t2, "t2");

}

如果我将共享指针替换为实际对象,则一切罚款:

If i replace the shared pointer with actual objects, everything is fine:

Hello from B using t1: 10
Hello from C using t2: 8

但是在我的原始代码中,我需要共享指针,因为在运行时是否需要构建条件...

But in my original code I need the shared pointers because there are some conditionals at runtime to whether build them or not...

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
add_compile_options(-std=c++11)
project(casting_problem)
include_directories(include)
add_library(${PROJECT_NAME} SHARED classes.cpp)
add_executable(${PROJECT_NAME}_exe "main.cpp")
target_link_libraries(${PROJECT_NAME}_exe ${PROJECT_NAME})


推荐答案

您的代码存在的问题是共享指针为null,因此通过它们进行间接访问的行为未定义。

The problem with your code is that your shared pointers are null, and therefore behaviour of indirecting through them is undefined.

您可以使用 s创建共享对象td :: make_shared

但是请记住,一旦销毁了最后一个共享指针,共享对象就会被销毁。指向地图中对象(如果有)的所有指针都悬空了。

Keep in mind however, that the shared objects are destroyed as soon as last shared pointer is destroyed, at which point any pointers to the objects in your map (if any) are left dangling.

这篇关于将void *转换为具有多重继承的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆