Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Classe abstraite ou pimpl ?

21 réponses
Avatar
Fabien LE LEZ
Bonjour,

Si je veux cacher les entrailles d'une classe, et ne montrer à son
utilisateur que les fonctions publiques, j'ai en gros le choix entre :

- l'idiome pimpl :

// .h
class C
{
public:
void f();
private:
class Implementation;
Implementation* pimpl;
};

// .cpp
void C::f()
{
pimpl-> f();
}

- l'idiome "classe de base abstraite" :

// .h
class C
{
public:
virtual void f()= 0;
};

// .cpp
class Implementation: public C
{
void f()
{
// Le code ici
}
}


Mon problème, c'est que je viens de m'apercevoir que je choisis entre
ces deux méthodes plus ou moins au hasard, suivant celle qui me vient
à l'esprit en premier.
Y a-t-il des critères rationnels pour choisir ?
Note : il s'agit généralement de classes à sémantique d'entité, non
copiables.

Merci d'avance...

10 réponses

1 2 3
Avatar
Charles Brossollet
J'utilise les deux, moi aussi, et je pense que du moment qu'il n'y a
pas de nécessité de faire hériter ta classe, c'est kif-kif. Mais si
tu veux hériter, la classe abstraite s'impose naturellement.
Avatar
Fabien LE LEZ
On 25 Sep 2005 02:39:06 -0700, "Charles Brossollet"
:

et je pense que du moment qu'il n'y a
pas de nécessité de faire hériter ta classe, c'est kif-kif.


De toutes façons, dans les deux cas le code client n'a pas à hériter
de ma classe.

Et l'idiome pimpl peut aussi gérer l'héritage : il suffit de faire
dériver une classe de la classe "Implementation".

Avatar
Stan
"Fabien LE LEZ" a écrit dans le message de news:

Bonjour,

Si je veux cacher les entrailles d'une classe, et ne montrer à son
utilisateur que les fonctions publiques, j'ai en gros le choix entre :

- l'idiome pimpl :

// .h
class C
{
public:
void f();
private:
class Implementation;
Implementation* pimpl;
};

// .cpp
void C::f()
{
pimpl-> f();
}

- l'idiome "classe de base abstraite" :

// .h
class C
{
public:
virtual void f()= 0;
};

// .cpp
class Implementation: public C
{
void f()
{
// Le code ici
}
}


Mon problème, c'est que je viens de m'apercevoir que je choisis entre
ces deux méthodes plus ou moins au hasard, suivant celle qui me vient
à l'esprit en premier.
Y a-t-il des critères rationnels pour choisir ?


Le premier cas permet une séparation physique de l'interface et de
l'implémentation,
ce qui ce traduit aussi par un gain de temps de re-compilation ( si on
modifie l'implémentation ).


--
-Stan

Avatar
Richard Delorme
Bonjour,

Si je veux cacher les entrailles d'une classe, et ne montrer à son
utilisateur que les fonctions publiques,


Quel intérêt de cacher l'implémentation ?

[...]
Mon problème, c'est que je viens de m'apercevoir que je choisis entre
ces deux méthodes plus ou moins au hasard, suivant celle qui me vient
à l'esprit en premier.
Y a-t-il des critères rationnels pour choisir ?


J'ai l'impression que cela ressemble au choix plus général entre "is-a"
(une classe B hérite d'une classe A) et "has-a" (une classe B contient
une classe A). En dehors de quelques cas d'école, je ne crois pas qu'il
y ait de critères rationnels autre qu'empiriques pour choisir.

--
Richard

Avatar
Marc Boyer
Fabien LE LEZ a écrit :
Bonjour,

Si je veux cacher les entrailles d'une classe, et ne montrer à son
utilisateur que les fonctions publiques, j'ai en gros le choix entre :
- l'idiome pimpl :
- l'idiome "classe de base abstraite" :


J'aurais tendance à préférer la classe de base abstraite, car:
- l'indirection générée par la virtualité est gérée par le
compilateur, donc possiblement plus efficacement.
- le compilateur peut signaler quand on a oublié d'instancier
une méthode

Mais bon, ce sont les avantages que je vois, je peux ne pas voir
les désavantages.

Marc Boyer
--
À vélo, prendre une rue à contre-sens est moins dangeureux
que prendre un boulevard dans le sens légal. À qui la faute ?

Avatar
Fabien LE LEZ
On Mon, 26 Sep 2005 09:47:44 +0200, "Stan" :

Le premier cas permet une séparation physique de l'interface et de
l'implémentation,
ce qui ce traduit aussi par un gain de temps de re-compilation


N'est-ce pas aussi le cas du deuxième ?

D'ailleurs, sous Windows au moins, le deuxième cas semble idiomatique
quand l'implémentation se trouve dans une DLL.

Avatar
Stan
"Fabien LE LEZ" a écrit dans le message de news:

On Mon, 26 Sep 2005 09:47:44 +0200, "Stan" :

Le premier cas permet une séparation physique de l'interface et de
l'implémentation,
ce qui ce traduit aussi par un gain de temps de re-compilation


N'est-ce pas aussi le cas du deuxième ?



Pour ce qui est de la séparation physique de l'interface et de
l'implémentation,
dans le premier cas, tu peux ne fournir qu'un fichier obj et un fichier
d'inclusion
et là, tu es sûr que les détails de l'implémentations seront masqués.

C'est ce qui se pratique parfois.

--
-Stan


Avatar
Aurelien Regat-Barrel
Moi je vois une assez grosse différence: la classe virtuelle possède
obligatoirement une sémantique de référence, avec allocation dynamique
(et il manque le code de la factory dans ton code), alors que le pimpl
peut être utilisé par valeur.
Au niveau de l'implémentation, je trouve le pimpl moins agréable :
gestion de l'allocation du pimpl, déclaration/implémentation d'une
classe dans un .cpp, ça fait un code un peu plus lourd je trouve.

--
Aurélien Regat-Barrel
Avatar
JBB
Fabien LE LEZ wrote:
Bonjour,

Si je veux cacher les entrailles d'une classe, et ne montrer à son
utilisateur que les fonctions publiques, j'ai en gros le choix entre :

- l'idiome pimpl :

// .h
class C
{
public:
void f();
private:
class Implementation;
Implementation* pimpl;
};

// .cpp
void C::f()
{
pimpl-> f();
}

- l'idiome "classe de base abstraite" :

// .h
class C
{
public:
virtual void f()= 0;
};

// .cpp
class Implementation: public C
{
void f()
{
// Le code ici
}
}


Mon problème, c'est que je viens de m'apercevoir que je choisis entre
ces deux méthodes plus ou moins au hasard, suivant celle qui me vient
à l'esprit en premier.
Y a-t-il des critères rationnels pour choisir ?
Note : il s'agit généralement de classes à sémantique d'entité, non
copiables.

Merci d'avance...

Si on lieu d'un fonction f() tu en as 50, tu gagnera peut etre un peu

de temps à faire de la classe de base abstraite.

En plus dans le methode pimpl tu peut te tromper dans l'indirection:
ex : void C::f() { pimpl-> g();) //encore une victime du copier coller

pimpl est donc un peu plus souple mais peut donc entrainer plus d'erreur.

Apres il faut voir aussi si tu as l'intention de deriver de C (utiliser
pimpl) , ou si tu veux pouvoir utiliser plusieurs interfaces C, avec des
classes d'implementation differentes (utiliser la classe abstraite).

Avatar
Fabien LE LEZ
On Mon, 26 Sep 2005 15:16:35 +0200, "Stan" :

dans le premier cas, tu peux ne fournir qu'un fichier obj et un fichier
d'inclusion


Et pourquoi est-ce impossible dans le deuxième cas ?

1 2 3