2010-02-16 4 views
24

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

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 ...

ответ

18

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

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

MyClass_p.h:

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

MyClass.ч:

// 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.

+1

Это не только предоставление публичных и закрытых заголовков, но и отображение идиомы pImpl - для этого необходимо публичное/частное, но pImpl не требуется. –

+1

@AndrewAylett, Как бы вы сделали это без pimpl? –

+0

@ LyndenShields, я имел в виду, что у вас могут быть публичные и закрытые заголовки по причинам, отличным от pimpl, поэтому демонстрация pimpl демонстрирует конкретное использование для публичных/закрытых заголовков, а не для общей идеи. –

9

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

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

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

2

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

0

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

2

Я на самом деле считаю, что подход с двумя заголовками и одним источником является хрупким. Если вы забыли обновить заголовок «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's public 

#ifdef MYCLASS_IMPL 
private: 

    // Implementation details 

#endif 
}; 

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


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

+0

Не могли бы вы привести простой пример для «Если вы забыли обновить заголовок« public »после изменения« закрытого »заголовка, ваш код может компилироваться, а затем ...»? Благодаря! – Arton

Смежные вопросы