2015-07-12 1 views
0

Je me demande s'il est possible d'avoir une classe qui utilise un template<typename T> avec des fonctions que le 'typename T' utilise par défaut. Je vais vous donner des exemples:Comment avoir deux (ou plus) instances d'un template typename class utilise la même fonction

tête:

includes all here 
extern template class Object<rectangleBase> 
extern template class Object(circleBase> 

struct rectangleBase 
{ 
    int width, height; 
    int posX, posY; 
}; 

struct circleBase 
{ 
    int radius; 
    int posX, posY; 
}; 

template<typename T> 
class Object { 
public: 
    Object(); 
    ~Object(); 

    void movePos(int x, int y); 

    void setPos(int x, int y); 

    T& returnObject() { 
     return object; 
    } 
private: 
    T object; 
}; 

Source:

includes all here 
template class Object<rectangleBase> 
template class Object<circleBase> 

Object<rectangleBase>::Object() { 
    rectangleBase* newObject; 
    newObject = new rectangleBase; 
    object = *newObject; 
} 

Object<circleBase>::Object() { 
    circleBase* newObject; 
    newObject = new circleBase; 
    object = *newObject; 
} 

void Object::movePos(int x, int y) { //here 
    object.posX += x; 
    object.posY += y; 
} 

void Object::setPos(int x, int y) { //here 
    object.posX = x; 
    object.posY = y; 
} 

Avec les fonctions setPos et movePos, est-il possible que les deux <rectangleBase> et <circleBase> peuvent utiliser la même fonction au lieu de Je dois écrire deux fois le même code parce qu'ils utiliseraient exactement le même code, j'ai montré où les fonctions sont dans le code.

Si ce n'est pas possible, existe-t-il une alternative?

+0

Pourquoi vous spécialisez-vous explicitement votre classe avec exactement le même comportement? – Quentin

+0

Désolé je ne vous suis pas @Quentin – Jack

+1

Je ne comprends pas la question: vous implémentez 'movePos' et' setPos' qu'une seule fois. Ce qui est vraiment inquiétant à propos de votre code, c'est que vous fuyez la mémoire: lorsque vous appelez 'new circleBase' et' new rectangleBase' vous ne libérez jamais cette mémoire. De plus, vous n'avez pas vraiment besoin d'appeler explicitement 'new' car si votre' T' a un constructeur par défaut (ou si vous écrivez une version spécialisée de 'Object ()'), 'object' sera toujours initialisé avec un objet vide (en ce moment vous faites également une copie et l'assigner à 'object'). –

Répondre

2

Avoir le même code pour plusieurs types de données différents (la programmation générique en un mot) est exactement ce que sont les modèles. Je pense que vous êtes trop penser à des choses.Ce qui suit est suffisant pour votre cas d'utilisation:

template<typename T> 
class Object { 
public: 
    Object() 
    : object() 
    { } 

    void movePos(int x, int y) { 
     object.posX += x; 
     object.posY += y; 
    } 

    void setPos(int x, int y) { 
     object.posX = x; 
     object.posY = y; 
    } 

    T& returnObject() { 
     return object; 
    } 
private: 
    T object; 
}; 

C'est tout ce dont vous avez besoin. Cela fonctionnera pour tout T qui est constructible par défaut, puis movePos et setPos peut être appelée si T a ces deux variables membres. Vous n'avez pas besoin de déclarer des spécialisations du tout. Compte tenu de ce qui précède, ce qui suit fonctionne bien:

Object<rectangleBase> r; 
r.setPos(5, 6); 

Object<circleBase> c; 
c.setPos(10, 20); 
s.movePos(10, 10); 
+0

Merci, vous aviez raison, je pensais trop. Le problème est maintenant résolu. Merci encore. @Barry – Jack

0

Oui, vous pouvez:

template <typename T> 
void Object<T>::movePos(int x, int y) { 
    object.posX += x; 
    object.posY += y; 
} 

Même vos constructeurs pouvez utiliser cette approche:

template <typename T> 
Object<T>::Object() { 
    // This in fact does nothing really different than the default 
    // constructor of object but leaks one instance of T. 
    T* newObject; 
    newObject = new T; 
    object = *newObject; 
} 

modèles ont généralement besoin de la mise en œuvre entière dans les fichiers d'en-tête, mais si vous êtes bien avec des types limités qui sont accepté, vous pouvez instancier explicitement les classes et ensuite vous pouvez avoir l'implémentation dans le fichier source:

Dans le fichier d'en-tête (n'importe où après le cours est définie):

extern template class Object<rectangleBase>; 
extern template class Object<circleBase>; 

Dans le fichier source (partout après les méthodes sont définies):

template class Object<rectangleBase>; 
template class Object<circleBase>; 

tout autre type que rectangleBase ou circleBase ne fonctionnera pas avec cette configuration.

+0

lors de la mise 'extern template classe Object ;' 'class' a une erreur disant' extern template ne peut pas suivre l'instanciation explicite de la classe "Object " 'et la même chose pour' Object '@StenSoft – Jack

+0

@Jack 'extern template class' doit être avant' template class'. Vous semblez avoir quelque peu mal '' include '' dans le fichier source. 'template class' doit être après' # include' du fichier d'en-tête ou il ne sait pas quoi instancier ('# include's devrait normalement être avant tout autre chose). – StenSoft

+0

code ci-dessus ont été changés à la façon dont je l'ai utilisé, est-ce exact? Si c'est le cas, 'class' me donne toujours la même erreur @StenSoft – Jack

0

Je ne sais pas quel est votre problème. Vous devez simplement implémenter vos fonctions, instancier le modèle et utiliser vos objets.

J'ai essayé, ça, ça fonctionne. S'il vous plaît, jetez un oeil: http://ideone.com/717044

#include <stdio.h> 

struct rectangleBase 
{ 
    int width, height; 
    int posX, posY; 
}; 

struct circleBase 
{ 
    int radius; 
    int posX, posY; 
}; 

template<typename T> 
class Object { 
public: 

    Object() { } 
    ~Object() { } 

    void movePos(int x, int y) 
    { 
     object.posX += x; 
     object.posY += y; 
    } 

    void setPos(int x, int y) 
    { 
     object.posX = x; 
     object.posY = y; 
    } 

    T& returnObject() { return object; } 

private: 
    T object; 
}; 

int main(int argc, char ** argv) 
{ 
    Object<rectangleBase> a; 
    Object<circleBase> b; 
    b.setPos(1,2); 
    printf("px: %d", b.returnObject().posX); 
} 

Si vous êtes intéressé nombre d'instances du compilateur de fonction susciteraient (ex: le code de vos fonctions est énorme), le compilateur le plus probable va générer autant de cas de code similaire à de nombreuses instanciations différentes. L'optimiseur peut en réduire certains. Mais si l'optimiseur le fait ou non, c'est difficile à dire.

L'approche lorsque vous utilisez des champs, des méthodes, des énumérations, etc. des types de paramètres du corps du modèle est appelée directement en utilisant des types dépendants. Oui, cette approche rend difficile ou impossible l'instanciation de votre modèle avec des types qui n'ont pas ce champ ou cette fonction membre. Néanmoins, ce modèle est largement utilisé.

+0

J'ai utilisé ce code et j'obtiens cette erreur 'rectangleBase :: rectangleBase (void): tentative de référence d'une fonction supprimée' @KirillKobelev – Jack

+0

Définissez (si nécessaire vide) le constructeur et les destructeurs dans vos types de paramètres. Ça devrait marcher. –

+0

Désolé, je ne comprends pas ce que vous voulez dire? @KirillKobelev – Jack