D-указатель и классы композиции в разделяемой библиотеке

Я создаю общую библиотеку в 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();

1

Решение

Из связанного: Проблема «Никогда не меняй размер экспортированный класс 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 является непрозрачным (в отличие от открытого) для потребителя библиотеки.

1

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

Других решений пока нет …