Подтвердить что ты не робот

Пример частного/публичного заголовка?

Может кто-нибудь, пожалуйста, дайте мне пример того, как работают публичные и частные заголовки? Я читал в сети, но я не могу найти много полезной информации с примерами кодов. Мне сообщили, что я должен использовать частные заголовки для разделения публичной и частной частей моего кода для создания статической библиотеки. После некоторого чтения у меня есть общее представление о том, как это работает, но по-настоящему оценит хороший пример, чтобы начать меня. В частности, я не совсем понимаю, как поместить функции интерфейса в мой общий заголовок и частные переменные/функции в моем закрытом заголовке? Спасибо!

EDIT:

Возможно, я не правильно формулирую свой вопрос, но я имел в виду, например, что у меня есть myMath.h и myMath.cpp, а myMath.h:

class myMath{
public:
    void initialise(double _a, double _b);
    double add();
    double subtract();

private:
    double a;
    double b;
};

И myMath.cpp имеет реализации функций. Как я могу сделать так, чтобы myMath.h имел только три публичные функции, а частные переменные были определены в другом файле (например, myMath_i.h), и эти три файла были такими, что после создания статической библиотеки, Пользователям требуется только myMath.h. Это также означает, что myMath.h не может # включить myMath_i.h. Так что-то вроде:

myMath.h:

class myMath{
public:
    void initialise(double _a, double _b);
    double add();
    double subtract();
}

и myMath_i.h:

class myMath{
private:
    double a;
    double b;
}

Конечно, это невозможно, потому что тогда я буду переопределять класс myMath...

4b9b3361

Ответ 1

У вас есть два файла заголовка MyClass.h и MyClass_p.h и один исходный файл: MyClass.cpp.

Давайте посмотрим, что внутри них:

MyClass_p.h:

// Header Guard Here
class MyClassPrivate
{
public:
    int a;
    bool b;
    //more data members;
}

MyClass.h:

// Header Guard Here
class MyClassPrivate;
class MyClass
{
public:
    MyClass();
    ~MyClass();
    void method1();
    int method2();
private:
    MyClassPrivate* mData;
}

MyClass.cpp:

#include "MyClass.h"
#include "MyClass_p.h"

MyClass::MyClass()
{
    mData = new MyClassPrivate();
}

MyClass::~MyClass()
{
    delete mData;
}

void MyClass::method1()
{
    //do stuff
}

int MyClass::method2()
{
    return stuff;
}

Храните свои данные в MyClassPrivate и распространяйте MyClass.h.

Ответ 2

Вы можете объявить все интерфейсы и константы, которые вы хотите предоставить пользователю библиотеки, в отдельный файл заголовка (или набор файлов) и поместить его в подкаталог "inc" - эти заголовки будут "общедоступными". Вы также будете использовать другие файлы заголовков, чтобы объявлять классы и вещи, которые вы не хотите раскрывать, поскольку эти данные являются деталями реализации - вы поместите эти файлы в подкаталог "src" - они будут "private".

Таким образом, пользователю будет дан намек на то, что он должен включать только публичные заголовки - те, которые находятся в "inc" , и только те заголовки содержат то, что ему действительно нужно, в то время как все остальные заголовки "private" и вне его интереса, если он не хочет читать в ходе реализации.

Когда вы публикуете свою библиотеку как двоичную - статическую или динамическую библиотеку, вы копируете только содержимое "inc" и результат компиляции - этого достаточно для пользователя, и таким образом он не видит ваших источников реализации.

Ответ 3

Публичные заголовки - это те, которые нужны пользователям библиотеки. Частные заголовки - это те, которые необходимы для компиляции библиотеки, но которые не нужны пользователям библиотеки. Выполнение раскола может быть довольно сложным, и многие библиотеки просто не беспокоят.

Ответ 4

Я действительно нашел подход с двумя заголовками и одним источником хрупким. Если вы забыли обновить заголовок "public" после изменения заголовка 'private', ваш код может компилироваться, а затем segfault где-то еще во время выполнения. У меня это случалось со мной несколько раз, поэтому я предпочитаю писать код, который не будет компилироваться, если все не будет правильно.

MyClass.cpp реализуется следующим образом:

#define MYCLASS_IMPL
#include "MyClass.h"

// Implementation follows
...

MyClass.h - интересный бит:

#ifdef MYCLASS_IMPL
#include everything needed for the private: section
#endif

#include everything needed for the public: section only

class MyClass
{
public:
    // Everything that public

#ifdef MYCLASS_IMPL
private:

    // Implementation details

#endif
};

Если цель состоит в том, чтобы скрыть детали реализации (например, закрытую библиотеку), вам может потребоваться использовать подход с двумя заголовками. Если вы не хотите перетаскивать зависимости только для использования класса, подход с одним заголовком может быть простым и надежным решением.


Чтобы ответить на вопрос Артона: прошло некоторое время с тех пор, как я посмотрел на это, но я думаю, что проблема связана с созданием объектов на основе общедоступного заголовка, а затем с учетом другого размера объекта с закрытым заголовком. Во время выполнения смещение в объект не будет соответствовать, что приведет к разрыву памяти. Кажется, что ответ erenlender охватывает этот случай с помощью пары public/private class.

Ответ 5

Мне было интересно то же самое, поскольку я перехожу с C на С++ в качестве основного языка программирования. Я думаю, лучший способ - использовать интерфейсы (абстрактные классы на С++): вы публикуете публичный интерфейс, а ваша частная реализация просто использует интерфейс в качестве базового класса.