Autore Topic: [C++] Nascondere implementazione di una classe  (Letto 2275 volte)

Offline clros

  • ASM Lover
  • *****
  • Post: 457
  • Karma: +3/-1
    • Mostra profilo
[C++] Nascondere implementazione di una classe
« il: 11 Novembre 2011, 00:24:09 »
Ciao a tutti,
forse avevo già postato qst domanda tempo fa, cmq provo a rifarla (non ricordo più la risposta!)

Avrei la necessità di nascondere l'implementazione di una classe C++.

In un file include ho qualcosa del tipo:

typedef MyClass<int> MyClassInt;

Questo file .h è normalmente contiene anche i prototipi di funzione di una lib che sto scrivendo.
Ecco, vorrei poter non fornire anche l'implementazione (il codice) di MyClass.
E' possibile?
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »
Claudio CP La Rosa

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re: [C++] Nascondere implementazione di una classe
« Risposta #1 il: 11 Novembre 2011, 00:26:18 »
Il C++ comprende, in teoria, la compilazione dei template su file .cpp, ma l'unico compilatore che conosco a supportare realmente questa feature è clang (LLVM). Per tutti gli altri, devi includere il codice del template con il file .h
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline clros

  • ASM Lover
  • *****
  • Post: 457
  • Karma: +3/-1
    • Mostra profilo
Re: [C++] Nascondere implementazione di una classe
« Risposta #2 il: 11 Novembre 2011, 00:54:23 »
Citazione da: "TheKaneB"
Il C++ comprende, in teoria, la compilazione dei template su file .cpp, ma l'unico compilatore che conosco a supportare realmente questa feature è clang (LLVM). Per tutti gli altri, devi includere il codice del template con il file .h

Ok, sto vedendo ora che è prevista la keyword export per fare questo.
però, poichè non l'ha mai implementata quasi nessuno, nel C++11 è stata tolta. (tra l'altro funzionava solo con le classi template e non con le classi normali...)

Mi chiedo se esista una alternativa...
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »
Claudio CP La Rosa

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re: [C++] Nascondere implementazione di una classe
« Risposta #3 il: 11 Novembre 2011, 00:57:44 »
Non esiste :-)
Non un'alternativa "pulita" almeno... Con le classi normali si può fare benissimo, ma i template sono come le macro e non ci si può girare intorno più di tanto...
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline clros

  • ASM Lover
  • *****
  • Post: 457
  • Karma: +3/-1
    • Mostra profilo
Re: [C++] Nascondere implementazione di una classe
« Risposta #4 il: 11 Novembre 2011, 01:01:07 »
Citazione da: "TheKaneB"
Non esiste :-)
Non un'alternativa "pulita" almeno... Con le classi normali si può fare benissimo, ma i template sono come le macro e non ci si può girare intorno più di tanto...

Con le classi normali si può fare?
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »
Claudio CP La Rosa

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re: [C++] Nascondere implementazione di una classe
« Risposta #5 il: 11 Novembre 2011, 01:15:30 »
Si, ovviamente puoi fare una classe di interfaccia che contiene solo le API pubbliche, e a sua volta incapsula un puntatore ad una classe di implementazione privata (questo pattern si chiama Private Implementation, e si trova ad esempio nelle librerie Qt).

In sostanza, le API pubbliche possono includere il puntatore tramite banale forward reference, senza includere il relativo header. La parte in cpp ovviamente conterrà entrambi gli header (API pubblica + implementazione privata), e dal momento che potrai fornire solo il compilato, il suo codice rimane nascosto insieme alla definizione dell'implementazione privata.

Oltre che per nascondere l'implementazione, questo metodo è utile per switchare a runtime l'implementazione di alcune funzioni. Ad esempio ho usato nei miei engine questo metodo per poter cambiare al volo una implementazione con un'altra (per esempio sostituire un algoritmo con una versione approssimata più leggera a runtime in caso di degrado del framerate del gioco).

Un'altra tecnica è quella della composizione dei namespace. Ad esempio nelle API pubbliche metti solo determinate classi, mentre negli header privati della libreria includi ulteriori classi interne che non vuoi esporre all'esterno. Avrai così un'API pubblica che condivide lo stesso namespace, ma espone un numero inferiore di classi (ciascuna classe, però, deve essere identica nelle due versioni dell'header altrimenti ti compila codice non funzionante).

Questa seconda tecnica lavorando a compile time è più efficiente della prima, ma non ti consente di variare a runtime il comportamento della classe sostituendo la sua implementazione privata (ma non è detto che questa caratteristica sia utile nel tuo caso, è solo un appunto).

Credo ci siano altre 1-2 tecniche più complesse, che coinvolgono l'uso di una Factory di oggetti che istanzia a runtime oggetti di classi derivate e ti restituisce puntatori a classi astratte (quindi usa un header diverso nell'API pubblica, che contiene solo classi astratte, rispetto a quello usato nel .cpp), ma dipende tutto da cosa vuoi fare e a cosa ti serve.
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline clros

  • ASM Lover
  • *****
  • Post: 457
  • Karma: +3/-1
    • Mostra profilo
Re: [C++] Nascondere implementazione di una classe
« Risposta #6 il: 11 Novembre 2011, 14:11:07 »
Citazione da: "TheKaneB"
Si, ovviamente puoi fare una classe di interfaccia che contiene solo le API pubbliche, e a sua volta incapsula un puntatore ad una classe di implementazione privata (questo pattern si chiama Private Implementation, e si trova ad esempio nelle librerie Qt).

PIMPL!!!
Avevo letto qualcosa in merito sul libro di Sutter qualche anno fa...ma nn ricordavo più che esistesse una tecnica simile! Mamma mia comincio ad invecchiare di brutto!! :D

Citazione
In sostanza, le API pubbliche possono includere il puntatore tramite banale forward reference, senza includere il relativo header. La parte in cpp ovviamente conterrà entrambi gli header (API pubblica + implementazione privata), e dal momento che potrai fornire solo il compilato, il suo codice rimane nascosto insieme alla definizione dell'implementazione privata.
Si si ads riprendo "exceptional C++" e me lo ristudio per bene! ;)

Citazione
Oltre che per nascondere l'implementazione, questo metodo è utile per switchare a runtime l'implementazione di alcune funzioni. Ad esempio ho usato nei miei engine questo metodo per poter cambiare al volo una implementazione con un'altra (per esempio sostituire un algoritmo con una versione approssimata più leggera a runtime in caso di degrado del framerate del gioco).
Questa è una caratteristica che nn credo mi servirà ma è sempre utile sapere che si può fare!!

Citazione
Un'altra tecnica è quella della composizione dei namespace. Ad esempio nelle API pubbliche metti solo determinate classi, mentre negli header privati della libreria includi ulteriori classi interne che non vuoi esporre all'esterno. Avrai così un'API pubblica che condivide lo stesso namespace, ma espone un numero inferiore di classi (ciascuna classe, però, deve essere identica nelle due versioni dell'header altrimenti ti compila codice non funzionante).

Questa tecnica invece non mi pare di averla mai vista...dovrò provarla...

Citazione
Questa seconda tecnica lavorando a compile time è più efficiente della prima, ma non ti consente di variare a runtime il comportamento della classe sostituendo la sua implementazione privata (ma non è detto che questa caratteristica sia utile nel tuo caso, è solo un appunto).

Per "compile time" intendi che ci mette meno tempo a compilare? A Run-time le prestazioni tra PIMPL e questa tecnica invece differiscono? (non dovrebbe essere, però chiedo lo stesso..)

Citazione
Credo ci siano altre 1-2 tecniche più complesse, che coinvolgono l'uso di una Factory di oggetti che istanzia a runtime oggetti di classi derivate e ti restituisce puntatori a classi astratte (quindi usa un header diverso nell'API pubblica, che contiene solo classi astratte, rispetto a quello usato nel .cpp), ma dipende tutto da cosa vuoi fare e a cosa ti serve.

Penso vadano benissimo queste! Grazie! :)
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »
Claudio CP La Rosa

Offline TheKaneB

  • Human Debugger
  • *****
  • Post: 5292
  • Karma: +20/-23
    • Mostra profilo
    • http://www.antoniobarba.org
Re: [C++] Nascondere implementazione di una classe
« Risposta #7 il: 11 Novembre 2011, 14:23:07 »
per "compile time" intendo che una volta compilato e linkato, le tue classi funzioneranno normalmente come hanno sempre fatto.
Invece il Private Implementation prevede la dereferenziazione di un puntatore (da parte della classe di interfaccia pubblica) per richiamare i metodi della classe implementativa. Quindi la risoluzione dell'implementazione avviene a runtime (finchè non  dereferenzi il puntatore non saprai mai cosa ci sta nella parte privata) e comporta un microscopico overhead che puoi tranquillamente trascurare nella maggioranza dei casi.
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Offline clros

  • ASM Lover
  • *****
  • Post: 457
  • Karma: +3/-1
    • Mostra profilo
Re: [C++] Nascondere implementazione di una classe
« Risposta #8 il: 12 Novembre 2011, 01:23:26 »
@dsar: grazie per l'interessante spiegazione! :)

Mi chiedevo a questo punto se è possibile anche "nascondere" la definizione di un tipo. Esempio:

Codice: [Seleziona]
typedef std::map<qualcosa,qualcosaDiComplicato> mioTipo;
E' possibile fare in modo che il programmatore a cui è rivolto mioTipo possa usarlo senza sapere e vedere com'è definito?
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »
Claudio CP La Rosa

Offline Allanon

  • Administrator
  • Synthetic Voodoo
  • *****
  • Post: 3498
  • Karma: +17/-4
    • Mostra profilo
    • http://www.a-mc.biz
Re: [C++] Nascondere implementazione di una classe
« Risposta #9 il: 14 Novembre 2011, 07:56:33 »
tutto decisamente molto interessante :-)
« Ultima modifica: 01 Gennaio 1970, 02:00:00 da Guest »

Tags: