使用 extern "C" 时 C++ 代码中的函数重载

Posted

技术标签:

【中文标题】使用 extern "C" 时 C++ 代码中的函数重载【英文标题】:Overloading of functions in C++ code when using extern "C" 【发布时间】:2020-10-01 10:48:33 【问题描述】:

我想在运行时加载库。我有一个基类“Base”和两个派生类“Derived1”和“Derived2”,它们应该在运行时加载。我正在使用来自this answer 的方法,并进行了一些小的修改。当我只定义一个派生类时,代码编译得很好,但是当定义了几个派生类时,它编译失败。编译错误如下:

multiple definitions of 'create'

我认为问题在于“C”不允许函数名重载。如何解决这个问题?

重要的一点是,由于我不知道存在多少个.so 文件,所以我想为所有.so 文件设置一个处理程序。详细代码如下:

base.hpp:

class Base 
public:
    virtual ~Base() 
    virtual void foo() const = 0;
;

using Base_creator_t = Base *(*)();

derived1.hpp:

#include "Interface.hpp"

class Derived1: public Base 
public:
    void foo() const override 
;

extern "C" 
Base * create() 
    return new Derived1;


derived2.hpp:

#include "Interface.hpp"

class Derived2: public Base 
public:
    void foo() const override 
;

extern "C" 
Base * create() 
    return new Derived2;


动态共享库处理程序:Derived_factory.hpp:

#include <dlfcn.h>

class Derived_factory 
public:
    Derived_factory(char* path) 
        handler = dlopen(path, RTLD_NOW);
        if (! handler) 
            throw std::runtime_error(dlerror());
        
        Reset_dlerror();
        creator = reinterpret_cast<Base_creator_t>(dlsym(handler, "create"));
        Check_dlerror();
    

    std::unique_ptr<Base> create() const 
        return std::unique_ptr<Base>(creator());
    

    ~Derived_factory() 
        if (handler) 
            dlclose(handler);
        
    

private:
    void * handler = nullptr;
    Base_creator_t creator = nullptr;

    static void Reset_dlerror() 
        dlerror();
    

    static void Check_dlerror() 
        const char * dlsym_error = dlerror();
        if (dlsym_error) 
            throw std::runtime_error(dlsym_error);
        
    
;

main.cpp:

#include "Derived_factory.hpp"
int main()
   Derived_factory factoryOne("Derived1.so");
      std::unique_ptr<Base> baseOne = factoryOne.create();
      baseOne->foo();
   Derived_factory factoryTwo("Derived2.so");
     std::unique_ptr<Base> baseTwo = factoryTwo.create();
     baseTwo->foo();
   return 0;

【问题讨论】:

您在头文件中定义(实现)create 函数。包含此头文件的每个源文件都将具有该定义。如果将头文件包含在两个不同的源文件中,它们都链接到一个库或可执行文件中,则会出现多个定义错误。在头文件中声明函数,并在单个源文件(每个库一个)中定义 derived1.hpp 包括interface.hpp。你的意思是base.hpp?请发布您的实际代码。 如你所说,C 不支持函数重载。您需要为函数的每个变体使用不同的名称(create_Derived1()create_Derived2() 等)。 【参考方案1】:

问题不是extern "C"。问题是你有多个相同函数的定义。

Base * create()Base * create() 无法区分

【讨论】:

【参考方案2】:

您要做的是在两个不同的可加载模块中具有相同的功能。但是您正在做的是将此函数的两个实现(具有相同的名称和签名!)放入主模块,这当然会导致多重定义错误。

您应该做的是将create 函数放入*.cpp 文件中,即derived1.cppderived2.cpp,从*.hpp 文件中省略它们的定义,并从这些@987654327 中编译共享对象@ 文件。我已修改您的项目以实现此目的,请参阅live demo。

【讨论】:

以上是关于使用 extern "C" 时 C++ 代码中的函数重载的主要内容,如果未能解决你的问题,请参考以下文章

extern "C"

DLL的Export和Import及extern "C"

在 C++ 中使用 C 函数 使用 extern "C"

尝试使用 c++ .so 库编译 c 代码,带有 extern "C" ... 段

深层揭密extern "C"

extern"C"的使用