共享库上的Dynamic_cast问题
Dynamic_cast troubles over shared libraries
我在共享库创建的对象上遇到了一些dynamic_cast
问题:
架构类似于:
class A;
class B : virtual public A; // one of the several interfaces
class C : public B; // defined only in the shared library
- 主应用程序加载共享库并请求新的对象
- 共享库创建一个新的
C
对象,但它返回dynamic_cast<A*>(pointerToCclass)
,因为主要应用程序不知道C
- 当主应用程序尝试向下转换到
B
时根据返回的CCD_ 6指针,它失败了
我怀疑在主代码和共享代码中创建的vtables之间的一些差异可能是原因。不管怎样,最初我并没有意识到这个问题,因为主要的应用程序调用方法void * A::getInterface( int ifEnum )
,因此共享库代码成功执行了下变频,并作为空指针返回。然后主应用程序执行reinterpret_cast
以将空指针绑定到所需接口。
到目前为止,当多继承模式(当C
实现多个接口时(似乎不稳定并导致Segmentation错误时,一切都有效。
我的怀疑是真的吗?有更好的方法或众所周知的方法来实现类似的体系结构吗?
谢谢
我附上了一些我的实际应用程序的语义化代码和基本的参与者。首先是常见的定义:
class A
{
public:
typedef A* (*getAobject_fn)(void);
static A * Load( char * filename ) {
void * objhlib = dlopen( filename, RTLD_NOW );
getAobject_fn fp = (getAobject_fn) dlsym( objhlib, "getAobject" );
return fp();
}
virtual A * Create() = 0;
virtual void * getInterface( int ifEnum ) = 0;
};
class B1 : virtual public A {
public:
// some inline or pure virtual functions here
};
class B2 : virtual public A {
public:
// some other inline or pure virtual functions here
};
共享库的头(实际上C类对主应用程序不可见,因为.so是在运行时加载的,.h不包括在主应用程序中(:
class C : public B1, public B2
{
public:
A * Create() { return new C; }
void * getInterface( int ifEnum ) {
if( ifEnum==INTERFACE_ID_B1 )
return dynamic_cast<B1*>(this);
if( ifEnum==INTERFACE_ID_B2 )
return dynamic_cast<B2*>(this);
return 0;
}
};
extern "C" { A * getAobject(); } // probably useless
在共享库的主体中:
C obj;
A * getAobject() { return dynamic_cast<A*>(&obj); } // equivalent to return &obj;
最后,在主要应用程序中:
// In the Init procedure
A * p = A::Load( "foo.so" );
A * pBobj = p->Create(); // pBobj is kept for the entire lifetime
B1 * b1 = reinterpret_cast<B1*>(pBobj->getInterface( INTERFACE_ID_B1 ));
B2 * b2 = reinterpret_cast<B2*>(pBobj->getInterface( INTERFACE_ID_B2 ));
// NOTE:
// b1 = dynamic_cast<B1*>(pBobj) and
// b2 = dynamic_cast<B2*>(pBobj)
// will fail
如何加载共享对象?g++使用RTTI信息来解析CCD_ 10。传统上在Unix中默认情况下,要加载的第一个符号将由所有的共享对象,所以不会有任何问题。这取决于dlopen
中使用的模式;如果RTLD_LOCAL
指定时,该共享对象中的符号(以及共享对象中由于加载而隐式加载的对象共享对象(在共享对象之外将不可见。(我在Java插件方面遇到过这个问题与RTLD_LOCAL
和dynamic_cast
共享的对象将不起作用交叉共享对象隐式加载的共享对象Java加载。(
关于主要可执行文件:大多数Unix链接器将可用的符号,就好像已加载可执行文件一样使用CCD_ 15。大多数,但不是全部;GNU链接器,用于例如,不这样做吗,以及主可执行文件中的符号不可用于共享对象。如果你需要他们可用,在生成时必须使用-rdynamic
选项可执行文件(转换为-export-dynamic
选项链接器(。或者,如果你需要打破应用程序分解为单独的共享对象,您可能考虑将几乎所有的东西都放在共享对象中,以及使得主可执行程序只不过是一个简单的库加载器,在所有共享对象上调用dlopen
,然后调用dlsym
要获取要执行的实际函数的地址,并通过地址呼叫它。(我们基本上就是这样解决了Java插件的问题。所有加载的Java我们的加载器模块,然后执行dlopen
。通过做它们明确地,我们可以控制dlopen
的选项。(
编辑:
重读你的问题,我不确定这是对的答复你正在通过void*
,这意味着你无法访问RTTI(甚至无法访问vtables(。规则关于void*
(C++规则,这次是而不是g++(是清楚的:使用void*
唯一能做的就是将其转换回原始指针类型。特别是Derived*
&rar;void*
&rar;Base*
是未定义的行为。如果只涉及单个继承,它通常会工作(但即便如此,它仍然是未定义的行为(,但不是否则因此,如果共享对象将A*
转换为void*
,并且void*
稍后转换为B*
有未定义的行为,不应该期望它工作。先将void*
转换为A*
,然后再进行转换到B*
应该工作。然而,更好的是:宣布函数返回A*
,而不是一个CCD_ 36。一般来说,你应该尽量避免void*
可能,尤其是在C++中。
- 警告处理为错误这里有什么问题
- 最小硬币更换问题(自上而下方法)
- 为"adjacent"变量赋值时出现问题
- 我的神经网络不起作用 [XOR 问题]
- 在Ubuntu 16.04上安装Cilk时出现问题
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 编译包含字符串的代码时遇到问题
- Project Euler问题4的错误解决方案
- 问题:什么是QAbstractItemView::NoEditTriggers的反面
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 如何理解C++标准N3337中的expr.const.cast子句8
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 一个关于在C++中重载布尔运算符的问题
- 首要问题的答案让值班员搞错了
- setlocale的C++土耳其字符串问题
- 如何重构类层次结构以避免菱形问题
- 基于boost的程序的静态链接——zlib问题
- 谁能帮助确定为什么这不能正确执行?如果问题与cast