2012-02-05 6 views
2

J'ai appris que
type fields is an error-prone technique somewherequels sont les champs de type

Je Google beaucoup, mais aucun résultat satisfaisant .Bien que je connais le sens de type et fields individuellement. Je pense que champ de type signifie champ d'un type particulier, comme

class marks; 
class test { 
marks number; 
bool pass; 
} 

Ici, selon moi, le champ de type est numéro et passe. Si cela est juste, en quoi la composition est-elle différente? Aussi ce qui est type field technique ?? Comment est-ce que l'erreur est sujette?

S'il vous plaît donnez-lui une véritable signification. Donne aussi un exemple pour montrer sa nature perverse et quels sont ses substituts ??

+1

Bonjour, peu importe combien j'essaie de ne pas comprendre ce que vous voulez dire et ce que vous essayez de demander. Pouvez-vous s'il vous plaît essayer de réécrire la question d'une manière plus intelligible? – Lefteris

+1

Ceci est une Question valide.Si vous ne comprenez pas ce que le PO essaie de demander, ne votez pas cela comme * Pas un vrai Q * ou * Non Constructif *, ce n'est pas l'un d'entre eux. –

+0

@AIs Je n'ai pas baissé l'OP. J'ai juste demandé des éclaircissements à sa question parce que je ne comprenais pas à quoi il faisait allusion. de toute façon la réponse de Silo semble être ce que le PO demandait. Je ne savais pas qu'ils se réfèrent à cette pratique en tant que champs de type – Lefteris

Répondre

6

Vous faites presque certainement référence à des champs de type comme discuté dans le livre The C++ Programming Language par Bjarne Stroustrup. Un champ de type dans ce contexte serait simplement une variable de quelque sorte dans une classe de base qui indique le type réel de ses sous-classes. Voici un exemple:

class Pet 
{ 
public: 
    enum PetType { Dog, Cat, Bird, Fish }; 

    void ToString() 
    { 
     switch(type) 
     { 
     case Pet::Dog: std::cout << "Dog" << std::endl; break; 
     case Pet::Cat: std::cout << "Cat" << std::endl; break; 
     case Pet::Bird: std::cout << "Bird" << std::endl; break; 
     case Pet::Fish: std::cout << "Fish" << std::endl; break; 
     } 
    } 

private: 
    PetType type; // A type field. 
}; 

class Dog : public Pet 
{ 
public: 
    Dog() { type = Dog; } 
}; 

// And so on... 

void Test(const Pet& p) { p.ToString(); } 
int main() 
{ 
    Dog d; 
    Test(d); 
    return 0; 
} 

C'est une façon extraordinairement fragile pour mettre en œuvre une méthode ToString(). Chaque fois que vous devez ajouter une classe dérivée de Pet, vous devez mettre à jour l'énumération PetType et la méthode ToString(). Par exemple, si je besoin d'une sous-classe Turtle, je besoin de faire ces changements:

// ... 
enum PetType { Dog, Cat, Bird, Fish, Tutle /* Added */}; 
void ToString(const Pet& p) 
{ 
    switch(p.type) 
    { 
    case Pet::Dog: std::cout << "Dog" << std::endl; break; 
    case Pet::Cat: std::cout << "Cat" << std::endl; break; 
    case Pet::Bird: std::cout << "Bird" << std::endl; break; 
    case Pet::Fish: std::cout << "Fish" << std::endl; break; 
    case Pet::Turtle: std::cout << "Turtle" << std::endl; break; // Added 
    } 
} 
// ... 
class Turtle : public Pet 
{ 
public: 
    Turtle() { type = Turtle; } // Added 
}; 

Imaginez si la classe Pet avait plus de fonctions que tout ToString(); l'entretien devient un cauchemar. C'est beaucoup de code que l'on doit changer, mais l'important est que pour avoir une classe Turtle, j'ai besoin de modifier la classe Pet. Cela signifie que plus de tests, de révision de code, etc. sont nécessaires. C'est une violation claire de the open/closed principle. C'est pourquoi les champs de type sont extrêmement sujets aux erreurs.

Une façon significativement supérieure serait d'utiliser les fonctions virtual:

class Pet 
{ 
public: 
    virtual void ToString() = 0; 
}; 

class Dog : public Pet 
{ 
public: 
    virtual void ToString() { std::cout << "Dog" << std::endl; } 
}; 

class Turtle : public Pet 
{ 
public: 
    virtual void ToString() { std::cout << "Turtle" << std::endl; } 
}; 

// And so on... 

void Test(const Pet& p) { p.ToString(); } 
int main() 
{ 
    Turtle t 
    // Will call Turtle::ToString(), even though 
    // Test() was only given a const Pet& 
    Test(t); 
    return 0; 
} 

Notez que le code ci-dessus ne nécessite aucun enum supplémentaire s ou switch déclarations. Appeler Pet::ToString() appellera l'implémentation correcte de ToString() pour Dog s, Cat s, etc. automatiquement, avec beaucoup moins de code. Je n'ai même pas besoin de changer la classe Pet; Je peux simplement déposer une classe Turtle si nécessaire, à condition que Pet ait été définie. Pour une utilisation éventuellement légitime des champs de type, see this Stack Overflow question and the answers to that question

+1

+1. J'étais sur le point d'ajouter une réponse mais je l'ai supprimée parce que votre réponse semblait prometteuse. Pour être complet, vous pouvez expliquer pourquoi la première approche est * fragile *, comment elle viole les principes * SOLID * Design menant à une mauvaise conception. –

+0

Chien() {type = Chien; } comment un membre privé a accès !!!!!!!!! –

Questions connexes