Я создаю общую библиотеку в Qt5 C ++. Чтобы будущие обновления сохраняли двоичную совместимость, я бы хотел использовать технику d-указателя. Тем не менее, я не знаю, как применять его, когда есть состав классов. Примеры, которые я нашел, в том числе один Вот, объяснить только случай наследования классов. Мой вопрос
Нужно ли создавать соответствующий закрытый класс для каждого класса в
библиотека (myLib, B и C) или только для основной (myLib) и как получить к ним доступ позже?
Вот мои настройки и желаемый функционал без частных классов:
myLib.h
#include "B.h"
class myLib;
{
public:
myLib();
B *getB(int n);
private:
QList<B *> m_b;
}
B.h
#include "C.h"
class B;
{
public:
B();
C *getC(int n);
private:
QList<C *> m_c;
}
C.h
class C;
{
public:
C();
int getVar();
private:
int m_var;
}
И где-то в основном приложении:
myLib *m_lib = new myLib();
int k = m_lib->getB(4)->getC(2)->getVar();
Из связанного: Проблема «Никогда не меняй размер экспортированный класс C ++».
Решение: «Хитрость заключается в том, чтобы сохранить размер все публичные занятия константы библиотеки, храня только один указатель. Этот указатель указывает на частную / внутреннюю структуру данных, которая содержит все данные. »
Пока ваш класс не показан потребителям вашей библиотеки, не стесняйтесь использовать D-указатель. Под «показанным потребителям» я подразумеваю «с их полным определением, доступным посредством объявлений в заголовках, предназначенных для включения в код потребителя». Возможно, термины public / private страдают от «семантической перегрузки» здесь, давайте использовать «Открытые» / «Непрозрачные» (см. ** сноска)
В вашем примере оба B
а также C
выставлены, поэтому они должны быть доступны «только по указателям».
То же самое касается myLib
учебный класс. Что хуже: случаи myLib
может быть получено по значению, потому что конструктор public
, Это означает, что я могу сделать что-то вроде:
myLib libObj;
libObj.getB(4)->getC(2)->getVar();
что сделает невозможным «падение замен, нет необходимости в перекомпиляции» из будущих выпусков myLib
,
Я предлагаю заставить потребителей пройти фабричный метод, чтобы получить примеры myLib
(или с «синглтоном»). Что-то на линии:
class myLib {
private:
myLib() {
}
public:
static myLib* createInstance() {
return new myLib();
}
};
** В качестве примера «открытая / непрозрачная декларация» — class B
подвергается библиотека потребителю (который будет знать B
-с будут .. гм … приватные части), но про class M
потребитель знает только то, что он существует, и библиотека будет указывать на него:
файл «myLib.hpp»
// M_type is a pointer to a class and that's all you,
// the consumer, need to know about it. You give me an M_type
// and ask specific questions about it and you'll
// get the details or access to data I choose to
// make available to you
typedef class M * M_type;
// Dear the library consumer, this class is public to you.
// You know I'm keeping a list of M_type, even if you also know
// you'll never get you hands directly on that list, because
// it has a private access. But having this information,
// **you can compute the sizeof(B)**.
class B {
public:
B();
M_type getM(int n);
const M_type getM(int n) const;
// that is one of the "questions" you can ask about an M_type
const char* getMLabel(const M_type var) const;
// I'm providing you with access to something that allows
// you to modify the amount stored by an M_type,
// even if you don't know (and never will) how
// I'm storing that amount
int& getMAmount(M_type var);
// You don't need to know how to create M-s, I'll
// be doing it for you and provide the index of the created
// M_type. Ask me with getM to get that pointer.
inr registerM(const char* label, int amount);private:
QList<M_type> ems;
};
Где-то глубоко в коде библиотеки будет существовать заголовок, который определяет, что class M
есть и myLib.cpp
будет включать его, но этот заголовок будет использоваться только для компиляции библиотеки и никогда не будет предоставлен с myLib двоичный релизы.
В качестве таких, class M
является непрозрачным (в отличие от открытого) для потребителя библиотеки.
Других решений пока нет …