Статическая библиотека: скрытие приватных членов от заголовочного файла
Я хочу скомпилировать часть моего кода в виде статической библиотеки для включения в другой проект. Конечно, мне придется распространять скомпилированную библиотеку и файл заголовка, содержащий объявление класса и открытые члены, но я не знаю, возможно ли переместить все закрытые члены и объявления в место, отличное от файла заголовка.
Пример:
В файле project.h:
class MyClass
{
public:
MyClass();
void Give_me_an_input(int);
int Get_your_output();
private:
int a, b;
int MySecretAlgorithm();
};
В файле.cpp:
MyClass::MyClass()
{
a = 1;
b = 0;
}
void MyClass::Give_me_an_input(int c)
{
b = c;
}
int MyClass::Get_your_output()
{
return MySecretAlgorithm();
}
int MyClass::MySecretAlgorithm()
{
return (a + b);
}
Есть ли способ переместить всех частных пользователей int a, b;
а также int MySecretAlgorithm();
в место, отличное от файла заголовка?
2 ответа
Указатель на идиому реализации может использоваться в таком сценарии, обычно называемом pimpl. Основная идея состоит в том, чтобы извлечь детали реализации из объявления и просто иметь непрозрачный указатель на детали реализации.
std::unique_ptr
используется в следующем примере; но вы можете, конечно, просто использовать обычные указатели.
// my_class declaration unit.
class my_class {
private:
class impl;
unique_ptr<impl> pimpl;
public:
};
// my_class implementation unit
class my_class::impl {
int whatever;
int whenever;
};
my_class::my_class(): pimpl( new impl )
{
}
За эти годы я видел несколько хаков, чтобы сделать это, но я не думаю, что они того стоят. Если ваша библиотека достаточно короткая (то есть: ни один метод не вызывается миллиард раз в микросекунду); и вы можете переписать куски вашего кода...
Вы могли бы рассмотреть возможность сделать все общедоступные вещи абстрактным классом (все виртуальные = 0) и затем извлечь из него ваши конкретные классы.
Недостатки этого: - Все ваши публичные звонки становятся виртуальными (некоторые оптимизации могут обойти это, но не часто). - Вы больше не можете "обновлять" свои классы, вам нужно реализовать фабричный шаблон.
Проблема с любым другим хаком, с которым я знаком, состоит в том, что они в основном объявляют методы в одном наборе заголовков, а затем повторно объявляют те же вещи с "реальной" реализацией в частных заголовках - в зависимости от компоновщика, чтобы соответствовать имена. Пара проблем здесь:
Поддержание этого беспорядка - отстой. Вы не можете использовать #ifdef, потому что похоже, что вы хотите физически скрыть свою реализацию. Таким образом, у вас есть двойное ведение или шаг сборки, который генерирует ваши публичные заголовки.
Может использоваться только через указатель. Вы должны играть в игры, делая конструкторы приватными и при этом сохраняя фабрику, потому что компилятор не будет генерировать структуры нужного размера, если вы разрешите клиенту генерировать его по значению (или даже с новым).
Наконец, однажды я увидел хак, когда программист пытался объявить байтовый массив в закрытой области класса public, чтобы клиентский код мог все же объявить его по значению или "новый" сам. Это страдает от всех предыдущих проблем, плюс вам, вероятно, не нужно "знать" размер структур, так как они зависят от упаковки и выравнивания. Ваш "шаг сборки" должен был бы более или менее иметь компонент времени выполнения, который использовал sizeof() - и теперь у вас есть проблема с управлением версиями, если вы хотите изменить размер структуры / класса.