How to define different types for the same class in C++

前端 未结 4 1507
臣服心动
臣服心动 2020-11-28 22:51

I would like to have several types that share the same implementation but still are of different type in C++.

To illustrate my question with a simple example, I woul

相关标签:
4条回答
  • 2020-11-28 23:02

    A common technique is to have a class template where the template argument simply serves as a unique token (“tag”) to make it a unique type:

    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>;
    

    Note that the tag classes don’t even need to be defined, it’s enough to declare a unique type name. This works because the tag isn’s actually used anywhere in the template. And you can declare the type name inside the template argument list (hat tip to @Xeo).

    The using syntax is C++11. If you’re stuck with C++03, write this instead:

    typedef Fruit<struct AppleTag> Apple;
    

    If the common functionality takes up a lot of code this unfortunately introduces quite a lot of duplicate code in the final executable. This can be prevented by having a common base class implementing the functionality, and then having a specialisation (that you actually instantiate) that derives from it.

    Unfortunately, that requires you to re-implement all non-inheritable members (constructors, assignment …) which adds a small overhead itself – so this only makes sense for large classes. Here it is applied to the above example:

    // 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>;
    
    0 讨论(0)
  • 2020-11-28 23:10

    There is also BOOST_STRONG_TYPEDEF.

    0 讨论(0)
  • 2020-11-28 23:12

    Use templates, and use a trait per fruit, for example:

    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
    

    Then have a single Fruit class which is typed on this trait eg.

    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;
    

    May be slightly overkill! ;)

    0 讨论(0)
  • 2020-11-28 23:21
    • C++11 would allow constructor inheritance: Using C++ base class constructors?
    • Otherwise, you can use templates to achieve the same, e.g. template<class Derived> class Fruit;
    0 讨论(0)
提交回复
热议问题