TransWikia.com

Overloading of functions in C++ code when using extern "C"

Stack Overflow Asked by Farhad on January 8, 2021

I want to load libraries at run time. I have a base class "Base" and two derived classes "Derived1" and "Derived2" which should be loaded at runtime. I am using the approach from this answer with some small modifications. The code compiles perfectly when I define only one derived class, but it fails to compile when several derived classes are defined. The compilation error is the following:

multiple definitions of 'create'

I think that the problem is "C" doesn’t allow overloading of function names. How would one solve this problem?

The important point is that since I don’t know how many .so files exist, I want to have one handler for all .so files. The details of the code are given below:

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;
}
}

Dynamic shared library handler: 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;
}

2 Answers

What you're trying to do is to have the same function in two different loadable modules. But what you're doing instead is putting both implementations (with the same name and signature!) of this function into the main module, which of course results in multiple definition error.

What you should do instead is put the create functions into the *.cpp files, i.e. derived1.cpp and derived2.cpp, omit their definitions from the *.hpp files, and compile the shared objects from these *.cpp files. I've modified your project to achieve this, see the live demo.

Correct answer by Ruslan on January 8, 2021

The problem is not extern "C". The problem is you have multiple definitions of the same function.

Base * create() is indistinguishable from Base * create()

Answered by Caleth on January 8, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP