在共享库中显式化实例化模板化类和dynamic_cast

Yup*_*ing 10 c++ templates dynamic-cast shared-libraries

我今天偶然发现了一个问题,似乎无法解决.我正在编译一个共享库,其中包含一个模板化的类(Derived<T>,其基础是Base)以及该类的一些显式实例化.我希望库用户从这个模板化的类扩展.当我尝试将出现问题dynamic_cast的用户的情况下,从Base*Derived<T>*.

我已将问题缩小到这个MWE:

共享库包含以下文件:

Base.h

#ifndef BASE_H_
#define BASE_H_

class Base {
public:
    Base();
    virtual ~Base();
};

#endif /* BASE_H_ */
Run Code Online (Sandbox Code Playgroud)

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_ */
Run Code Online (Sandbox Code Playgroud)

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>;
Run Code Online (Sandbox Code Playgroud)

Helper.h

#ifndef HELPER_H_
#define HELPER_H_

#include <Base.h>

class Helper {
public:
    Helper(Base* m);
    virtual ~Helper();

};

#endif /* HELPER_H_ */
Run Code Online (Sandbox Code Playgroud)

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() {
}
Run Code Online (Sandbox Code Playgroud)

一个使用该库的简单代码可以是:

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;
}
Run Code Online (Sandbox Code Playgroud)

问题是,当我创建一个共享库并链接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
===
Run Code Online (Sandbox Code Playgroud)

但是,如果我一起编译整个库和示例,则转换成功:

created mymodel 0x7fff5fbff3e0
before fom: 0
before dom: 0x7fff5fbff3e0
before ldom: 0
===
after received 0x7fff5fbff3e0
after fom: 0
after dom: 0x7fff5fbff3e0
after ldom: 0
===
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么dynamic_cast失败了?

并且,在我希望维护类示例的类结构的前提下,继续使用共享库:如何Derived<some type>*从一个成功获取转换Base*

Ale*_*nov 4

我假设你使用的是 Linux/GCC,因为在 Windows 上它应该“正常工作”。

它并不“只适用于”GCC,因为为了提高性能,GCC 中的 RTTI 支持依赖于指针比较。此 GCC 常见问题解答中对此进行了全部解释,包括如何解决。编辑:不过,这个常见问题解答说它不起作用,dlopen()而与共享库的显式链接应该起作用;所以也许还有其他的问题,比如下面提到的错误。

我发现其他一些可能有帮助的链接:
dynamic_cast an interface from a shared library that was returned by lt_dlopen(libtool) does not workdynamiccast
with faces
C++dynamic_cast bug in Mac OS 10.6 Snow Leopard