компиляция с измененным заголовочным файлом

У меня есть заголовочный файл с определением класса и некоторые включает. Класс содержит несколько открытых функций и несколько закрытых переменных. Класс компилируется в исполняемый файл.

Допустим, кто-то берет этот заголовочный файл и создает «публичную» копию. Он удаляет все включенные и закрытые переменные (использует предварительные объявления для неопределенных символов). Затем он компилирует свой собственный код (который вызывает публичные функции рассматриваемого класса) из файла заголовка «public» и создает файл .so.

Будет ли эта библиотека работать правильно

  • если это связано с исполняемым файлом?
  • если он динамически загружается во время выполнения?

0

Решение

Как объяснено в комментариях, то, что вы буквально описали, не сработает, но цель разумна. Насколько я понимаю, вы хотите скрыть детали реализации класса, предоставляя фиксированный интерфейс для плагинов, чтобы разработка кода плагина могла быть отделена от остальной части программы.

Вы не можете просто буквально скрыть данные и функции закрытого члена, задав ложный заголовок. Прежде всего, нарушение ODR, как указывает Игорь Тандетник. Это не просто произвольное правило. Личные данные влияют на объем памяти, необходимый для хранения объекта, и, следовательно, на то, как код должен обрабатывать этот объект. Относительные адреса как открытых, так и частных функций должны быть известны в общей реализации полиморфизма vtable.

Нам нужно косвенное Наш интерфейс сообщит клиентскому коду, каковы его публичные функции, и просто о том, что ему нужно место для хранения указателя на класс реализации. Детали класса реализации не должны быть известны. Это идиома. Вот схема того, как это можно использовать с динамической загрузкой.

main.cpp

#include <iostream>
#include <dlfcn.h>

#include "interface.h"
typedef int (bar_type)(const Interface&);

int main() {
#ifndef EXE_INPUT
#define EXE_INPUT 5
Interface interface(EXE_INPUT);
#endif

void* plugin = dlopen("plugin.so", RTLD_LAZY);
if (plugin == NULL) {
std::cout << dlerror() << std::endl;
return 1;
}

bar_type* bar_ptr = (bar_type*)dlsym(plugin, "bar");
if (bar_ptr == NULL) {
std::cout << dlerror() << std::endl;
return 1;
}

const int ret = (*bar_ptr)(interface);

std::cout << "The value from the plugin is " << ret << std::endl;
}

interface.h

#ifndef INTERFACE_H
#define INTERFACE_H
class Implementation;

class Interface
{
public:
Interface(const int);
~Interface();
int foo(int) const;
private:
Implementation* imp_ptr;
};
#endif

interface.cpp

#include "interface.h"
struct Implementation {
Implementation(const int v)
:   v(v)
{}

int foo(const int w) {
return v * w;
}

int v;
/* this struct is not exposed, do whatever you want here */
};

Interface::Interface(const int v)
:   imp_ptr(new Implementation(v))
{}

Interface::~Interface() {
delete imp_ptr;
}

/* if this signature changes or other functions get added
* to Interface, plugin must be recompiled */
int Interface::foo(const int w) const {
return imp_ptr->foo(w);
}

plugin.cpp

#include "interface.h"#include "plugin.h"
extern "C" int bar(const Interface& i)
{
#ifndef PLUGIN_INPUT
#define PLUGIN_INPUT 11
return i.foo(PLUGIN_INPUT);
#endif
}

plugin.h

#ifndef PLUGIN_H
#define PLUGIN_H
#include "interface.h"extern "C" int bar(const Interface& i);
#endif

Компиляция и ссылка. Я случайно использую OS X. Для Linux удалите «-undefined dynamic_lookup».

g++-4.8 -o main main.cpp interface.cpp
g++-4.8 -shared -fpic -undefined dynamic_lookup -ldl -o plugin.so plugin.cpp

Обратите внимание, что мы компилируем и ссылаемся отдельно. В частности, plugin.cpp не имеет представления о том, что находится в interface.cpp.

$ ./main
The value from the plugin is 55

Ты можешь измениться interface.cpp как вам угодно без необходимости перекомпилировать плагин. Динамическая загрузка здесь не является абсолютно необходимой. Это также будет работать с динамическим связыванием.

Предостережение: Стандарт C ++ предъявляет мало требований к тому, как пользовательские классы должны быть размещены в памяти. Если вы попытаетесь передать экземпляры пользовательских классов между плагином и основной программой, вы можете не получить того, что ожидаете, особенно если основная программа и плагин были скомпилированы с использованием разных компиляторов.

0

Другие решения


По вопросам рекламы [email protected]