145 votes

Techniques d'effacement de type

(Avec le type d'effacement, je veux dire de cacher certains ou de la totalité de la nature de l'information concernant une catégorie, un peu comme Boost.Tout.)
Je veux obtenir une prise de type effacement des techniques, tout en partageant également ceux, qui, je le sais. Mon espoir est un peu pour trouver quelques fous technique que quelqu'un a pensé de son/ses heures les plus sombres. :)

La première et la plus évidente, et souvent pris approche, que je connais, sont des fonctions virtuelles. Juste masquer la mise en œuvre de votre classe à l'intérieur d'une interface de classe de la hiérarchie. De nombreuses bibliothèques Boost de le faire, par exemple Boost.Tout cela pour masquer votre type et coup de pouce.Shared_ptr cela pour masquer l' (de)de répartition de la mécanique.

Ensuite, il ya l'option avec des pointeurs de fonction de type "modèle" de fonctions, tout en maintenant l'objet réel en void* pointeur, comme Boost.La fonction n'est pour masquer le vrai type de l'foncteur.

Pour l'instant, parce que les deux exemples sont assez long, je vais le lien vers Ideone avec classe et un exemple de code pour les deux implémentations. Si il y a un souhaite juste comprendre la source de cette question, merci de laisser un commentaire en le disant. :) Le code peut être trouvé ici. (Les exemples sont ni complète, ni réellement sans danger à utiliser. Ils montrent juste le type d'effacement de la technique.)

Donc pour ma question:
Quel autre type d'effacement des techniques de connaissez-vous? Veuillez fournir, si possible, avec un exemple de code, cas d'utilisation, votre expérience avec eux et peut-être les liens pour d'autres lectures. Ce serait vraiment génial et merci d'avance pour toutes les réponses!

Modifier
(Puisque je n'étais pas sûr que de l'ajouter comme une réponse, ou tout simplement de modifier la question, je vais le faire le plus sûr.)
Une autre bonne technique pour masquer le type réel de quelque chose sans fonctions virtuelles ou void* tripoter, est l'un GMan emploie ici, en rapport avec ma question sur exactement comment cela fonctionne.

110voto

Marc Mutz - mmutz Points 10367

Tous les types d'effacement des techniques en C++ sont fait avec des pointeurs de fonction (de conduite) et void* (pour les données). Les "différentes" méthodes tout simplement diffèrent dans la façon dont ils ajouter de la sémantique à sucre. Des fonctions virtuelles, par exemple, sont seulement sémantique de sucre pour

struct Class {
    struct vtable {
        void (*dtor)(Class*);
        void (*func)(Class*,double);
    } * vtbl
};

oie: des pointeurs de fonction.

Cela dit, il y a une technique que j'aime particulièrement, cependant: Il est shared_ptr<void>, tout simplement parce qu'il souffle l'esprit de gens qui ne connaissent pas, vous pouvez le faire: Vous pouvez stocker des données dans un shared_ptr<void>, et de toujours avoir le bon destructeur appelé à la fin, parce que l' shared_ptr constructeur est une fonction de modèle, et utiliser le type de l'objet réel passé pour la création de la deleter par défaut:

{
    const shared_ptr<void> sp( new A );
} // calls A::~A() here

Bien sûr, c'est juste l'habituel void*/fonction-type de pointeur d'effacement, mais très commodément emballés.

55voto

Anthony Williams Points 28904

Fondamentalement, ce sont vos options: fonctions virtuelles ou des pointeurs de fonction.

Comment stocker les données et de les associer avec les fonctions peuvent varier. Par exemple, vous pouvez stocker un pointeur vers la base, et ont la classe dérivée contiennent les données et la fonction virtuelle implémentations, ou vous pouvez stocker les données ailleurs (par exemple dans un séparément tampon alloué), et demandez à la classe dérivée de fournir la fonction virtuelle implémentations, qui prennent un void* qui pointe vers les données. Si vous enregistrez les données dans un autre tampon, puis vous pouvez utiliser des pointeurs de fonction, plutôt que des fonctions virtuelles.

Stocker un pointeur vers la base fonctionne bien dans ce contexte, même si les données sont stockées séparément, s'il y a de multiples opérations que vous désirez appliquer à votre type effacement de données. Sinon vous vous retrouvez avec plusieurs pointeurs de fonction (un pour chaque type effacé fonctions), ou des fonctions avec un paramètre qui indique l'opération à effectuer.

26voto

Matthieu M. Points 101624

Je considérerais également (comme void* ) l'utilisation du "stockage brut": char buffer[N] .

En C ++ 0x, vous avez std::aligned_storage<Size,Align>::type pour cela.

Vous pouvez y stocker tout ce que vous voulez, à condition qu'il soit suffisamment petit et que vous traitiez correctement l'alignement.

20voto

Andrzej Points 1388

Voir cette série de billets pour un (assez courte) liste de type d'effacement des techniques et de la discussion sur le compromis: La Partie I, La partie II, La partie III, La partie IV.

Celui que je n'ai pas vu encore mentionné est Adobe.Poly, et coup de pouce.Variantequi peut être considéré comme un type d'effacement, dans une certaine mesure.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X