2009-07-30 7 views
8

Possible en double:
What are the differences between Generics in C# and Java… and Templates in C++?C# génériques par rapport à C++ modèles

Quelles sont les différences entre les génériques C# par rapport à C++ modèles? Je comprends qu'ils ne résolvent pas exactement le même problème, alors quels sont les avantages et les inconvénients des deux?

+4

Quelle coïncidence, c'est mon sujet de blog pour aujourd'hui. http://blogs.msdn.com/ericlippert/archive/2009/07/30/generics-are-not-templates.aspx –

+1

cela a * eu * pour être exact en double. @Eric Lippert: Ooh, intéressant, va lui donner une lecture – jalf

Répondre

16

Vous pouvez envisager des modèles C++ être interprété, langage de programmation fonctionnelle déguisé en un système de médicaments génériques. Si cela ne vous fait pas peur, il devrait :)

Les génériques C# sont très restreints; vous pouvez paramétrer une classe sur un type ou des types, et utiliser ces types dans des méthodes. Ainsi, pour prendre un exemple de MSDN, vous pouvez faire:

public class Stack<T> 
{ 
    T[] m_Items; 
    public void Push(T item) 
    {...} 
    public T Pop() 
    {...} 
} 

Et maintenant, vous pouvez déclarer une Stack<int> ou Stack<SomeObject> et il va stocker des objets de ce type, en toute sécurité (pas de peur de mettre en SomeOtherObject par erreur).

En interne, le runtime .NET le spécialise en variantes pour les types fondamentaux comme int, et une variante pour les types d'objet. Cela permet à la représentation pour Stack<byte> d'être beaucoup plus petite que celle de Stack<SomeObject>, par exemple.

les modèles C de permettre une utilisation similaire:

template<typename T> 
class Stack 
{ 
    T *m_Items; 
    public void Push(const T &item) 
    {...} 
    public T Pop() 
    {...} 
}; 

Cela ressemble au premier coup d'œil, mais il y a quelques différences importantes. Tout d'abord, au lieu d'une variante pour chaque type fondamental et un pour tous les types d'objet, il existe une variante pour chaque type qui est instancié par rapport à. Cela peut être beaucoup de types! La différence majeure suivante est (sur la plupart des compilateurs C++) il sera compilé dans chaque unité de traduction dans laquelle il est utilisé. Cela peut beaucoup ralentir la compilation.

Un autre attribut intéressant des modèles de C++ est qu'ils peuvent être appliqués à d'autres choses que des classes - et quand ils le sont, leurs arguments peuvent être automatiquement détectés. Par exemple:

template<typename T> 
T min(const T &a, const T &b) { 
    return a > b ? b : a; 
} 

Le type T sera automatiquement déterminé par le contexte dans lequel la fonction est utilisée.

Ces attributs peuvent être utilisés à de bonnes fins, au détriment de votre santé mentale. Dans la mesure où un modèle C++ est recompilé pour chaque type contre lequel il est utilisé et que l'implémentation d'un modèle est toujours disponible pour le compilateur, C++ peut effectuer des inlining très agressifs sur les modèles. Ajouter à cela la détection automatique des valeurs de modèle dans les fonctions, et vous pouvez faire anonymous pseudo-functions en C++, en utilisant boost::lambda. Ainsi, une expression comme:

_1 + _2 + _3

produit un objet avec un de type sérieusement effrayant, qui a un opérateur() qui ajoute ses arguments. Il ya beaucoup d'autres coins sombres du système de gabarit C++ - c'est un outil extrêmement puissant, mais peut être pénible à penser, et parfois difficile à utiliser - en particulier quand il vous donne un message d'erreur de vingt pages. Le système C# est beaucoup plus simple - moins puissant, mais plus facile à comprendre et plus difficile à abuser.

+0

* Un autre attribut intéressant des templates de C++ est qu'ils peuvent être appliqués à des choses autres que des classes * - est-ce la même chose que C# nous permet de définir des génériques dans des fonctions (par exemple T SomeFunc (T input) {...} ')? – dotNET

3

http://blogs.msdn.com/csharpfaq/archive/2004/03/12/88913.aspx

En gros, une grande partie de la différence a à voir avec le fait que les modèles sont résolus à la compilation et génériques sont résolus lors de l'exécution.

+2

En fait, bien que les génériques puissent être instanciés à l'exécution (par réflexion, comme toute autre chose), beaucoup de choses sont comprises au moment de la compilation. Par exemple, le JIT produit une implémentation spécifique de 'List ' plutôt que d'utiliser une version courante effacée par type équivalente à 'List ' (c'est une façon de se différencier de Java). –

+0

@Earwicker: dites-moi à ce sujet. C'est pourquoi vous ne pouvez pas faire de promotion générique (c'est-à-dire concaténer une liste dans une liste ). La fonctionnalité existe dans la CLI, mais ils ont choisi de ne pas l'implémenter de cette manière en C# (une erreur, IMO). –

1

Ce blog entry from Eric Gunnerson couvre ce sujet tout à fait bien.

La plus grande différence immédiate est que les modèles sont une fonctionnalité de compilation tandis que les génériques sont une fonctionnalité d'exécution.