Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在共享库中显式实例化模板化类和动态_强制转换_C++_Templates_Shared Libraries_Dynamic Cast - Fatal编程技术网

C++ 在共享库中显式实例化模板化类和动态_强制转换

C++ 在共享库中显式实例化模板化类和动态_强制转换,c++,templates,shared-libraries,dynamic-cast,C++,Templates,Shared Libraries,Dynamic Cast,我今天遇到了一个我似乎无法解决的问题。我正在编译一个共享库,其中包括一个模板类(派生的,其基是基)和该类的一些显式实例化。我希望库用户从这个模板类扩展。当我尝试将用户实例从Base*转换为Derived*时,问题就出现了 我已将问题缩小到这个MWE: 共享库包含以下文件: Base.h 导出的.h 但是,如果我同时编译整个库和示例,则转换将成功: created mymodel 0x7fff5fbff3e0 before fom: 0 before dom: 0x7fff5fbff3e0 bef

我今天遇到了一个我似乎无法解决的问题。我正在编译一个共享库,其中包括一个模板类(
派生的
,其基是
)和该类的一些显式实例化。我希望库用户从这个模板类扩展。当我尝试将用户实例从
Base*
转换为
Derived*
时,问题就出现了

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

共享库包含以下文件:

Base.h

导出的.h

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

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\u cast
为什么失败了


而且,在我想维护一个类似于示例的类结构并继续使用共享库的前提下:我如何才能成功地从
Base*
获取
派生的*
转换?

我假设您在Linux/GCC上,因为在Windows上它应该“正常工作”

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

我发现的其他一些链接可能会有所帮助:



这一点也不奇怪。即使对于普通的非模板类,也不应该期望RTTI跨共享库边界工作。对于某些编译器,在某些操作系统上,使用某些编译器或链接器选项,它可能会工作,但一般来说,它不会工作,也不需要工作(在标准中明确未指定)。即使你让它发挥作用,从长远来看,它也是不可持续的

根据我的经验,RTTI无法跨越共享库边界的情况远远超过它可以跨越的情况

解决办法是:

  • 将这些派生类型的所有对象构造限制在使用动态_cast的共享库代码中(此解决方案很难管理)

  • 根本不要使用dynamic_cast(此解决方案是理想化的,很少适用)

  • 不要使用共享库(评估共享库是否真的是您所需要的,或者从您的共享库中公开一个更高级别的接口,该接口不公开要派生的多态类型(这似乎表明“开放式体系结构”更适合您的应用程序))

  • 定义您自己的RTTI系统和铸造操作员(这可能很难,取决于您的技能,但代码并不多,许多主流项目都使用此解决方案,您可以找到大量关于如何实现这一点的示例)


缩小范围的建议。。。1) 绝对确保传递给编译器的选项对于lib组件和程序组件是相同的。。。它们可以影响形成的受控制符号。2) 使用“”工具从库对象和程序对象中转储符号。。。您应该会看到库组件(已定义)和测试代码(未定义)的相同损坏符号我在mac下使用gcc,我还没有尝试Linux/gcc。我来看看你的链接。我昨晚用Linux/GCC4.4.5和4.5.2试过了,结果是开箱即用。在MacOSX/GCC4.2.1上,它没有。为了在Mac上解决这个问题,我按照您的链接使用了
-mmacosx version min=10.4
选项。奇怪的是,
-Wl,-no_compact_linkedit
标志对我不起作用,但我相信这可能是由CMake处理其编译器/链接器标志的方式造成的。我仍然在寻找一台使用GCC4.2.1的旧linux机器,以便进行测试。感谢您的帮助您能举出一些主流项目的例子来定义自己的RTTI系统吗?LLVM、Boost.Serialization、大多数GUI工具,如Qt和VCL/CLX、DynObj和我自己的项目(这不是主流)。谢谢Mikael。我正在认真考虑最后一个选择。。。我得先用枕头检查几个晚上。@MikaelPersson:这只适用于
模板
类,还是适用于共享库中定义的任何类?
#ifndef DERIVED_H_
#define DERIVED_H_    
#include <Base.h>

template <typename T>
class Derived : public Base {
public:  
    Derived();
    virtual ~Derived();
};

#endif /* DERIVED_H_ */
#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>;
#ifndef HELPER_H_
#define HELPER_H_

#include <Base.h>

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

};

#endif /* HELPER_H_ */
#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() {
}
#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;
}
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
===