2010-02-16 11 views
24

Qualcuno può darmi un esempio di come funzionano gli header pubblici e privati? Ho fatto qualche lettura in rete ma non riesco a trovare molte informazioni utili con i codici di esempio. Mi è stato consigliato di utilizzare intestazioni private per separare le parti pubbliche e private del mio codice per la creazione di una libreria statica. Dopo alcune letture ho un'idea generale di come funziona, ma apprezzerei davvero un buon esempio per iniziare. In particolare, quello che non capisco è come mettere le funzioni dell'interfaccia nella mia intestazione pubblica e le variabili/funzioni private nella mia intestazione privata? Grazie!Esempio di intestazione privata/pubblica?

EDIT:

Forse non sono formulazione mia domanda giusta, ma quello che volevo dire è, per esempio, ho myMath.h e myMath.cpp, e myMath.h ha:

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

private: 
    double a; 
    double b; 
}; 

E myMath.cpp ha le implementazioni delle funzioni. Come posso fare in modo che myMath.h abbia solo le tre funzioni pubbliche, e le variabili private siano definite in un altro file (es. MyMath_i.h), e questi tre file sono in modo tale che dopo aver creato una libreria statica, solo myMath.h è necessario per gli utenti. Questo significa anche che myMath.h non può #include myMath_i.h. Quindi, qualcosa di simile a:

myMath.h:

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

e myMath_i.h:

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

Naturalmente questo non è possibile perché poi sarò ridefinire il myMath di classe ...

risposta

18

Si dispone di due file di intestazione MyClass.h e MyClass_p.h e un file di origine: MyClass.cpp.

consente di dare un'occhiata a quello che c'è dentro di loro:

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; 
} 

Conservare i dati in MyClassPrivate e distribuire MyClass.h.

+1

Questo va oltre la semplice fornitura di intestazioni pubbliche e private e mostra anche l'idi di pImpl: pubblico/privato è necessario per questo, ma pImpl non è richiesto. –

+1

@AndrewAylett, come faresti senza pimpl? –

+0

@LyndenShields, intendevo che è possibile avere intestazioni pubbliche e private per motivi diversi da pimpl, quindi la dimostrazione di pimpl sta dimostrando un uso specifico per intestazioni pubbliche/private, non l'idea generica. –

9

È possibile dichiarare tutte le interfacce e le costanti che si desidera esporre all'utente della libreria in un file di intestazione separato (o un set di file) e inserirle nella sottodirectory "inc" - quelle intestazioni saranno "pubbliche" ". Userai anche altri file header per dichiarare classi e cose che non vuoi esporre poiché sono i dettagli di implementazione - metti questi file nella sottodirectory "src" - quelli saranno "privati".

In questo modo all'utente verrà dato un suggerimento che deve includere solo le intestazioni pubbliche - quelle che sono in "inc" e solo quelle intestazioni contengono le cose di cui ha realmente bisogno, mentre tutte le altre intestazioni sono "private" e fuori dalla sua area di interesse a meno che non voglia leggere l'implementazione.

Quando si pubblica la libreria come file binario (libreria statica o dinamica), si copiano solo i contenuti "inc" e il risultato della compilazione - quelli sono sufficienti per l'utente e in questo modo non vede le origini dell'implementazione.

2

Le intestazioni pubbliche sono quelle necessarie agli utenti della libreria. Le intestazioni private sono quelle necessarie per compilare la libreria, ma che non sono necessarie agli utenti della biblioteca. Eseguire la divisione può essere abbastanza complicato e molte librerie semplicemente non danno fastidio.

0

Mi stavo chiedendo la stessa cosa da quando sto passando da C a C++ come il mio linguaggio di programmazione principale. Immagino che il modo migliore sia usare le interfacce (classi astratte in C++): pubblichi un'interfaccia pubblica e la tua implementazione privata usi l'interfaccia come classe base.

2

Ho effettivamente trovato l'approccio two-header-one-source per essere fragile. Se si dimentica di aggiornare l'intestazione "pubblica" dopo aver modificato l'intestazione "privata", il codice può essere compilato e quindi segfault da qualche altra parte in fase di esecuzione. Mi è capitato di capitarmi un paio di volte, quindi preferisco scrivere codice che non verrà compilato a meno che non sia tutto corretto.

MyClass.cpp è implementata in questo modo:

#define MYCLASS_IMPL 
#include "MyClass.h" 

// Implementation follows 
... 

MyClass.h è il bit interessante:

#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 
}; 

Se l'obiettivo è quello di nascondere i dettagli implementativi (per esempio una libreria chiusa), potrebbe essere necessario seguire l'approccio a due testate. Se non si desidera trascinare le dipendenze solo per utilizzare una classe, l'approccio a singola intestazione può essere una soluzione semplice e solida.


di rispondere a domande di Arton: E 'stato un po' da quando ho guardato questo, ma penso che il problema aveva a che fare con istanziare gli oggetti in base all'intestazione pubblico, quindi assumendo una dimensione oggetto diverso con il privato intestazione. In fase di esecuzione, un offset nell'oggetto non corrisponderebbe, causando uno scontro di memoria. Sembra che la risposta di Erenlender copra questo caso con una coppia di classi pubbliche/private.

+0

Puoi dare un semplice esempio per "Se ti dimentichi di aggiornare l'intestazione 'pubblica' dopo aver cambiato l'intestazione 'privata', il tuo codice potrebbe essere compilato, e quindi ..."? Grazie! – Arton