una resueltos programacion poo orientada objetos miembros metodos ejercicios ejemplos codigo clases clase c++ types

resueltos - Cómo definir diferentes tipos para la misma clase en C++



metodos en c++ (4)

Me gustaría tener varios tipos que compartan la misma implementación pero que aún sean de diferente tipo en C ++.

Para ilustrar mi pregunta con un ejemplo simple, me gustaría tener una clase para manzanas, naranjas y plátanos, todos con las mismas operaciones y la misma implementación. Me gustaría que tuvieran diferentes tipos porque quiero evitar errores gracias a la seguridad de tipo.

class Apple { int p; public: Apple (int p) : p(p) {} int price () const {return p;} } class Banana { int p; public: Banana (int p) : p(p) {} int price () const {return p;} } class Orange ...

Para no duplicar código, parece que podría usar una clase base Fruit y heredar de ella:

class Fruit { int p; public: Fruit (int p) : p(p) {} int price () const {return p;} } class Apple: public Fruit {}; class Banana: public Fruit {}; class Orange: public Fruit {};

Pero luego, los constructores no son heredados y tengo que reescribirlos.

¿Hay algún mecanismo (typedefs, templates, inheritance ...) que me permita tener fácilmente la misma clase con diferentes tipos?



Una técnica común es tener una plantilla de clase donde el argumento de la plantilla simplemente sirve como un token único ("etiqueta") para que sea un tipo único:

template <typename Tag> class Fruit { int p; public: Fruit(int p) : p(p) { } int price() const { return p; } }; using Apple = Fruit<struct AppleTag>; using Banana = Fruit<struct BananaTag>;

Tenga en cuenta que las clases de etiqueta ni siquiera necesitan ser definidas, es suficiente para declarar un nombre de tipo único. Esto funciona porque la etiqueta isn realmente se usa en cualquier parte de la plantilla. Y puede declarar el nombre del tipo dentro de la lista de argumentos de la plantilla (hat tip para @Xeo).

La sintaxis de using es C ++ 11. Si está atrapado con C ++ 03, escriba esto en su lugar:

typedef Fruit<struct AppleTag> Apple;

Si la funcionalidad común requiere mucho código, desafortunadamente introduce bastante código duplicado en el ejecutable final. Esto se puede evitar teniendo una clase base común implementando la funcionalidad y luego teniendo una especialización (que en realidad se crea una instancia) que se deriva de ella.

Desafortunadamente, eso requiere que implementes de nuevo todos los miembros no heredables (constructores, asignación ...), lo que agrega una pequeña sobrecarga, por lo que solo tiene sentido para clases grandes. Aquí se aplica al ejemplo anterior:

// Actual `Fruit` class remains unchanged, except for template declaration template <typename Tag, typename = Tag> class Fruit { /* unchanged */ }; template <typename T> class Fruit<T, T> : public Fruit<T, void> { public: // Should work but doesn’t on my compiler: //using Fruit<T, void>::Fruit; Fruit(int p) : Fruit<T, void>(p) { } }; using Apple = Fruit<struct AppleTag>; using Banana = Fruit<struct BananaTag>;


Use plantillas y use un rasgo por fruta, por ejemplo:

struct AppleTraits { // define apple specific traits (say, static methods, types etc) static int colour = 0; }; struct OrangeTraits { // define orange specific traits (say, static methods, types etc) static int colour = 1; }; // etc

Luego, tenga una única clase de Fruit que se escriba en esta característica, por ejemplo.

template <typename FruitTrait> struct Fruit { // All fruit methods... // Here return the colour from the traits class.. int colour() const { return FruitTrait::colour; } }; // Now use a few typedefs typedef Fruit<AppleTraits> Apple; typedef Fruit<OrangeTraits> Orange;

Puede ser un poco exagerado! ;)


  • C ++ 11 permitiría la herencia del constructor: ¿ usar constructores de clase base C ++?
  • De lo contrario, puede usar plantillas para lograr lo mismo, por ejemplo, la template<class Derived> class Fruit;