c++ - 向下转换从动态库返回的类型

标签 c++ c++11 c++14 dynamic-cast dynamic-library

我正在编写一个动态库,它返回指向基类的指针,但我想将它们向下转换为派生类。示例:

//Library code:
class A
{
public:
    A(void) = default;
    virtual ~A(void) = default;
    virtual void Foo(void)
    {
        std::cout << "A::Foo\n";
    };
};

class B : public A
{
public:
    B(void) = default;
    void Foo(void) override
    {
        std::cout << "B::Foo\n";
    }
    virtual void Bar(void)
    {
        std::cout << "B::Bar\n";
    }
};

class Factory
{
public:
    Factory(void) = default;
    virtual std::shared_ptr<A> CreateB(void)
    {
        return std::shared_ptr<A>{new B{}};
    }
};

extern "C" std::shared_ptr<Factory> CreateFactory(void)
{
    return std::make_shared<Factory>();
}


//Application code:
int main(int argc, char* argv[])
try
{
    auto handle = dlopen("./Dynamic.so", RTLD_LAZY);
    if (handle == nullptr)
    {
        throw std::runtime_error{dlerror()};
    }
    auto factoryaddress = 
        reinterpret_cast<std::shared_ptr<Factory>(*)(void)>(
        dlsym(handle, "CreateFactory"));
    if (factoryaddress == nullptr)
    {
        dlclose(handle);
        throw std::runtime_error{dlerror()};
    }
    auto factory = factoryaddress();
    auto a = factory->CreateB();
    a->Foo();
    auto b = std::dynamic_pointer_cast<B>(a);
    b->Bar();
    std::cin.get();
}

我明白了

/usr/include/c++/5/bits/shared_ptr.h:458: undefined reference to `typeinfo for B'
/usr/include/c++/5/bits/shared_ptr.h:458: undefined reference to `typeinfo for A'

最佳答案

我打赌你展示的代码与你实际尝试编译的代码不同。为了有构建时链接问题,你必须

  1. 使用 RTTI 支持进行编译,这是因为您使用了 dynamic_cast,并且
  2. 类中有一个非内联虚函数,您使用它的 RTTI 信息。

在您的代码中,所有内容都是内联的,但是如果您采用 ~A() 并将其放入单独的源文件(不在公共(public) header 中),您将收到此错误。

解决方案很简单,但有点难看。所有导出的类都必须内联所有虚函数。您可以拥有具有实际实现的私有(private)非内联非虚函数,并且只需从另一个调用一个。

这一切背后的原因是,如果翻译单元定义了该类的第一个非内联虚函数,则会发出 RTTI 信息(typeinfo 和一些其他符号)。在您的情况下,当您编译应用程序时,编译器看不到任何虚函数定义,并假定 typeinfo 位于其他某个目标文件中。这不是真的,因此链接器失败。

当所有虚函数都是内联时,RTTI 内容在引用该类的每个目标文件中作为弱(又名“comdat”部分)发出。因此,您可以在库和应用程序之间共享类,两者都将具有相同的弱 RTTI 符号。当应用程序加载库时,第二组重复的 RTTI 符号被丢弃,库代码链接到应用程序代码中已经存在的符号。这是常见的弱符号机制。

关于c++ - 向下转换从动态库返回的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35388625/

相关文章:

c++ - 为什么 char{} 和 char() 用作 char* 参数的临时变量?

c++ - 错误 : type 'std::__1::basic_string<char>' does not provide a call operator

c++ - 我如何在这个循环中使用 openMP?

c++ - 二叉树 - 根据级别打印元素

c++ - C++ 如何区分对全局变量的调用和全局变量的声明?

C++ 列表从位置删除元素并将其放在末尾

c++ - 快速 strlen 函数与别名规则

C++结构重新定义编译器错误

c++ - 带有映射的 Lambda 函数,其中键是元组,值是 double

c++ - 哪些枚举值在 C++14 中是未定义的行为,为什么?