У меня есть библиотека C ++ .so. Мой сотрудник работает над программой на c, которая будет вызывать библиотеку c ++ из своей программы на c. Я сказал ему, чтобы он создал Wrapper.h и Wrapper.cpp и использовал указатель для передачи объектов c ++ в своей программе c. Однако я обнаружил, что он пытается изменить исходный код нашей библиотеки c ++, добавив Wrapper.cpp и заголовок в нашу библиотеку .so напрямую. Например:
class A{ SetValueA(int); }
class B{ SetValueB(int); }
В своем Wrapper.cpp он написал так:
A a;
B b;
extern "C" SetValueA(int) {a.SetValueA(int); }
extern "C" SetValueB(int) {b.SetValueB(int); }
Затем он перекомпилировал нашу библиотеку c ++ и включил в свою программу Wrapper.h.
То, что я сказал ему, это сделать так:
В моем Wrapper.cpp
extern "C" {
A* newClassA() {
return new A();
}
void SetValueA(A* v, int i) {
v->SetA(i);
}
B* newClassB() {
return new B();
}
void SetValueB(B* v, int i) {
v->SetB(i);
}
void deleteClassA(A* v) {
delete v;
}
void deleteClassB(B* v) {
delete v;
} }
Затем я просто скомпилировал мой Wrapper.cpp и связал его с нашей библиотекой c ++. В своей программе на c ему просто нужно включить Wrapper.h и скомпилировать его код на c, а затем скомпилировать Wrapper.o и main.o (из main.c) с помощью компилятора c ++.
Его решение тоже работает, он жаловался, что, как я сказал ему, больше работает. Но я не хочу, чтобы он изменил нашу библиотеку c ++, потому что никто другой не будет использовать класс Wrapper из библиотеки c ++. Можете ли вы сказать мне, какой из них лучше и почему?
Да, мне также не нравится, как он использует глобальную переменную в своей оболочке.
Я не понимаю, почему необходимо изменить какой-либо библиотечный файл для использования глобальных переменных: необходимое изменение должно быть ограничено Wrapper.cpp
который явно является частью оболочки.
Тем не менее, я не верю в использование какого-либо [изменяемого] глобального объекта. Они имеют тенденцию быть проблемой по-разному. То есть я бы согласился с тем, что правильный подход к созданию обертки — это эффективная работа с необходимым управлением на протяжении всей жизни. Я понимаю, что правильно распределить управление жизненным циклом в C сложнее, чем в C ++. Решением этой проблемы является использование C ++, а не создание ненужных зависимостей (я знаю, что этот аргумент обычно не работает с программистами на C).
Оболочка, которую написал ваш коллега, конечно же, неразборчива из-за использования глобальных переменных, которые привносят множество проблем в вашу библиотеку.
Однако я считаю, что хорошо написанная библиотека должна экспортировать интерфейс C самостоятельно, даже если она использует C ++ для внутреннего использования. По той простой причине, что интерфейс C может быть импортирован практически на любой язык, в то время как интерфейс C ++ требует, чтобы пользовательский код был C ++. Кроме того, использование этого вида оболочки в пользовательском коде может привести к распространению различных версий wrapper.cpp, которые по-разному являются неполными и устаревшими.
Таким образом, я бы включил код в соответствии с вашими wrapper.cpp в вашу библиотеку. И я бы, конечно, переместил его ближе к коду, который он упаковывает, вместо того, чтобы связать все это в один большой, толстый wrapper.cpp. Таким образом, гораздо проще проверить, все ли ваши публичные методы были правильно упакованы.