Ниже приведен рабочий пример для вас.
Нет необходимости в extern "C"
связывании, поскольку вы можете точно найти и использовать искаженное имя C ++.
Кроме того, фабричные функции должны возвращать std::unique_ptr
, чтобы передать пользователю, чтотеперь они владеют объектом.Если только фабрика не хранит ссылку на объект, в этом случае std::shared_ptr
будет хорошим выбором.
Заголовок общей библиотеки:
// shared.h
#pragma once
#include <memory>
#include <string>
#include <iosfwd>
namespace shared {
struct Test {
virtual ~Test() = 0;
virtual void print(std::ostream&) const = 0;
// Factory function.
static std::unique_ptr<Test> create(std::string const& type);
};
inline std::ostream& operator<<(std::ostream& s, Test const& t) {
t.print(s);
return s;
}
} // namespace shared
Источник общей библиотеки:
// shared.cc
#include "shared.h"
#include <iostream>
namespace {
struct A : shared::Test {
void print(std::ostream& s) const override {
s << __PRETTY_FUNCTION__;
}
};
} // namespace
shared::Test::~Test() = default;
std::unique_ptr<shared::Test> shared::Test::create(std::string const& type) {
std::unique_ptr<Test> result;
if(type == "A")
result.reset(new A);
return result;
}
Создайте общую библиотеку и найдите искаженное имя Test::create
:
$ g++ -c -fPIC -W{all,extra,error} -std=c++11 shared.cc
$ g++ -o libshared.so -shared shared.o
$ nm --demangle --defined-only --dynamic libshared.so | grep Test::create
0000000000001894 T shared::Test::create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
$ nm --defined-only --dynamic libshared.so | grep 0000000000001894
0000000000001894 T _ZN6shared4Test6createERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Источник пользователя:
// test.cc
#include "shared.h"
#include <iostream>
#include <dlfcn.h>
struct DlClose { void operator()(void* handle) const { ::dlclose(handle); } };
using dl_ptr = std::unique_ptr<void, DlClose>;
int main() {
dl_ptr handle(::dlopen("./libshared.so", RTLD_NOW));
if(!handle)
std::abort();
using FactoryFn = std::unique_ptr<shared::Test>(std::string const&);
FactoryFn* shared_create = reinterpret_cast<FactoryFn*>(::dlsym(handle.get(), "_ZN6shared4Test6createERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE"));
if(!shared_create)
std::abort();
auto a = shared_create("A");
std::cout << *a << '\n';
}
Создайте и запустите код пользователя:
$ g++ -W{all,extra,error} -std=c++11 -o test -ldl test.cc
$ ./test
virtual void {anonymous}::A::print(std::ostream&) const