2016-08-29 5 views
1

Я создаю общую библиотеку в Qt5 C++. Чтобы позволить будущим обновлениям сохранять двоичную совместимость, я хотел бы использовать технику d-указателя. Однако я не знаю, как его применять, когда есть состав классов. Примеры, которые я нашел, включая один here, объясняют только случай наследования класса. Мой вопрос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(); 
+0

Из связанного: проблема «Никогда не изменяйте размер ** экспортированного класса C++ **». Решение: «Хитрость заключается в том, чтобы сохранить размер ** всех открытых классов ** константы библиотеки, только сохраняя единственный указатель. Этот указатель указывает на частную/внутреннюю структуру данных, которая содержит все данные». –

ответ

1

Из связанной: Проблемы "Никогда не изменить размер экспортированного класса C++".
Решение: «Хитрость заключается в том, чтобы сохранить размер всех общедоступных классов константы библиотеки, сохраняя только один указатель. Этот указатель указывает на частную/внутреннюю структуру данных, которая содержит все данные».

Пока ваш класс не показан потребителям вашей библиотеки, не стесняйтесь идти D-pointerless. Под «показанным потребителям» я имею в виду «с их полным определением, доступным декларациями в заголовках, которые должны быть включены в код потребителя». Возможно, условия государственные/частные страдают от «семантической перегрузки» здесь, давайте использовать «выставлены»/«непрозрачные» (см ** сноска)

В вашем примере, как B и C подвергаются, поэтому они должны быть доступны «только указателями».

То же самое касается myLib класс. Что еще хуже: экземпляры myLib могут быть получены по значению, потому что конструктор public. Это означает, что я могу сделать что-то вроде:

myLib libObj; 
libObj.getB(4)->getC(2)->getVar(); 

, который сделает невозможным иметь «падение замен, ни перекомпиляций необходимых» из будущих выпусков myLib.


Я предлагаю заставлять потребителей проходить заводской метод для получения экземпляров myLib (или с помощью «singleton»).Что-то на линии:

class myLib { 
private: 
    myLib() { 
    } 

public: 

    static myLib* createInstance() { 
    return new myLib(); 
    } 
}; 

** В качестве примера «открытых/непрозрачных деклараций» - class B является разоблачить в библиотеке потребитель (который будет знать B -s будет иметь .. гм ... интимное), но о 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 непрозрачен (в отличие от выставленного) для потребителя библиотеки.

+0

Спасибо за ответ, Адриан! Позвольте мне проверить, правильно ли я прав. Если какой-либо класс каким-то образом раскрывается пользователю библиотеки, будь то напрямую (вручную создавая его экземпляры) или косвенно (как в моем случае, путем запроса экземпляров, созданных основным классом библиотеки), он является общедоступным, то есть экспортируется, следовательно должен быть d-pointerified, так сказать, чтобы гарантировать, что его размер не изменится в будущих выпусках. Это правильно? К сожалению, я не получил часть, начинающуюся с ** Но **. И еще один вопрос. Ли частные атрибуты класса входят в частную структуру или методы? – scopchanov

+0

@scopchanov ", чтобы гарантировать, что его размер не изменится в будущих выпусках. Правильно?" Чтобы быть более точным, «Чтобы на потребительский код не влияли изменения размера в будущих выпусках». Я буду рассматривать другие вопросы в отдельных комментариях. –

+0

@scopchanov «И еще один вопрос: не входят ли частные атрибуты класса в частную структуру или методы?» «Частные/защищенные/общедоступные» квалификаторы стандартного доступа не имеют никакого отношения к этому вопросу. Когда мы говорим о «публичных структурах данных, экспортируемых библиотекой», мы имеем в виду «все, что потребитель библиотеки узнает о классах/структурах, включая заголовки, предоставленные этой библиотекой» - следует ли их называть «экспортировать»? При этом я отредактирую свой ответ, чтобы уточнить условия, в которых изменяется размер экспортируемых структур. –