我遇到类似以下的问题:
When is static cast safe when you are using multiple inheritance?
multiple inheritance: unexpected result after cast from void * to 2nd base class
但是我真的不明白为什么它不起作用,因为我正在做建议的事情(回溯到原始类型)。
还涉及模板。
我有一个模板对象的通用容器,我将其实现为std::string
ID和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;
}
在主代码中,我有类似的东西可以将对象添加到地图并根据类型调用适当的方法:
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();
}
该字符串明确标识正在使用哪个类作为模板,以便回调可以转换回正确的类型。
只要我传递给addClass
之类的B
对象,即从纯虚拟模板类A
继承单个继承,一切都可以正常工作。
一旦我传递了一个像C
这样的对象,即具有A
和D
的多重继承,我进行转换的callback
就会产生SEGFAULT,甚至虽然我没有编译错误。
更新。显然,问题出在std::shared_ptr
的使用中,而不是强制转换本身。这是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");
}
如果我用实际对象替换共享指针,一切都很好:
Hello from B using t1: 10
Hello from C using t2: 8
但是在我的原始代码中,我需要共享指针,因为在运行时有一些条件可以决定是否构建它们……
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})
答案 0 :(得分:1)
代码存在的问题是共享指针为空,因此通过它们进行间接访问的行为是不确定的。
您可以使用std::make_shared
创建共享对象。
但是请记住,一旦最后一个共享指针被破坏,共享对象就会被破坏,这时指向地图中对象的任何指针(如果有)都将悬空。