我今天陷入困境,似乎无法解决.我正在编译一个共享库,其中包含一个模板类(Derived< T>,其基础是Base)和这个类的某些显式实例.我希望图书馆用户从这个模板类扩展.当我尝试将用户的实例从Base *动态化为Derived< T> *时,会出现此问题.
我把问题缩小到了这个MWE:
共享库包含以下文件:
Base.h
#ifndef BASE_H_ #define BASE_H_ class Base { public: Base(); virtual ~Base(); }; #endif /* BASE_H_ */
Derived.h
#ifndef DERIVED_H_ #define DERIVED_H_ #include <Base.h> template <typename T> class Derived : public Base { public: Derived(); virtual ~Derived(); }; #endif /* DERIVED_H_ */
Derived.cpp
#include <Derived.h> template <typename T> Derived<T>::Derived() : Base() { } template <typename T> Derived<T>::~Derived() { } // explicit instantiations template class Derived<float>; template class Derived<double>; template class Derived<long double>;
Helper.h
#ifndef HELPER_H_ #define HELPER_H_ #include <Base.h> class Helper { public: Helper(Base* m); virtual ~Helper(); }; #endif /* HELPER_H_ */
Helper.cpp
#include <Helper.h> #include <Base.h> #include <Derived.h> #include <iostream> using namespace std; Helper::Helper(Base* m) { cout << "after received " << m << endl; cout << "after fom: " << dynamic_cast< Derived<float>* >(m) << endl; cout << "after dom: " << dynamic_cast< Derived<double>* >(m) << endl; cout << "after ldom: " << dynamic_cast< Derived<long double>* >(m) << endl; cout << "===" << endl; } Helper::~Helper() { }
而使用该库的简单代码可以是:
TEST.CPP
#include <Derived.h> #include <Helper.h> #include <iostream> using namespace std; class MyModel : public Derived<double> { public: MyModel() : Derived<double>() { }; virtual ~MyModel() { }; }; int main(int argc,char *argv[]) { MyModel om1; cout << "created mymodel " << &om1 << endl; cout << "before fom: " << dynamic_cast< Derived<float>* >(&om1) << endl; cout << "before dom: " << dynamic_cast< Derived<double>* >(&om1) << endl; cout << "before ldom: " << dynamic_cast< Derived<long double>* >(&om1) << endl; cout << "===" << endl; Helper root(&om1); return 0; }
问题是当我创建一个共享库并链接test.cpp时,dynamic_cast将失败.以下是一个示例输出:
created mymodel 0x7fff5fbff3e0 before fom: 0 before dom: 0x7fff5fbff3e0 before ldom: 0 === after received 0x7fff5fbff3e0 after fom: 0 after dom: 0 // <<< Here I expected it to succeed and return a non-null pointer after ldom: 0 ===
但是,如果我将整个库和示例一起编译,则转换成功:
created mymodel 0x7fff5fbff3e0 before fom: 0 before dom: 0x7fff5fbff3e0 before ldom: 0 === after received 0x7fff5fbff3e0 after fom: 0 after dom: 0x7fff5fbff3e0 after ldom: 0 ===
我的问题是:为什么dynamic_cast失败?
而且,在我想维护一个类结构的前提下,我们要继续使用一个共享库:如何从Base *中成功获取Derived< some type> * cast?
解决方法
我假设你在Linux / GCC上,因为在Windows上它应该“只是工作”.
它不与GCC“正常工作”,因为GCC中的性能RTTI支持依赖于指针比较.这一切都在this GCC FAQ年解释,包括如何解决.编辑:虽然,这个FAQ表示它不适用于dlopen(),而显式链接到共享库应该工作;所以也许还有别的东西,比如下面提到的bug.
我发现一些其他链接可以帮助:
dynamic_cast an interface from a shared library which was loaded by lt_dlopen(libtool) doesn’t work
dynamic cast with interfaces
C++ dynamic_cast bug in Mac OS 10.6 Snow Leopard