【发布时间】:2011-05-24 14:49:43
【问题描述】:
我今天偶然发现了一个我似乎无法解决的问题。我正在编译一个共享库,其中包括一个模板类(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_ */
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>* 转换?
【问题讨论】:
-
缩小范围的建议... 1) 绝对确保传递给编译器的选项对于您的 lib 组件和您的程序组件是相同的...它们会影响管理符号的形成. 2) 使用“nm”工具从库对象和程序对象中转储符号...您应该看到库组件(已定义)和测试代码(未定义)的相同损坏符号
标签: c++ templates shared-libraries dynamic-cast