1

I have an Interface (there missing a lot of members, but mind the fact this interface is mandatory). I will need 5 classes inheriting from it, which will have a _value attribute. So, ins\ tead of implement 5 classes(for char, short, int, float, double), I thought about a template class :

class my_interface
{
public:
    virtual [various_types]    getValue() const = 0;
};

template<typename T>
class my_class : public my_interface
{
private:
    T    _value;
public:
    my_class(T value) : _value(value) {} // initialize the attribute on construct
    virtual T        getValue() const { return _value; }
};

...so that something like that could work :

void                my_function()
{
    my_inteface*    a = new my_class<char>(42);
    my_interace*    b = new my_class<short>(21);
    int             result;

    result = a->getValue() + b->getValue();
}

But I don't see how I could do. It seems you can't make templates on interface pure virtual. To me, the only way that could work would be to make getValue() to always return a double, since it is the highest sized type I need. However, I don't like that solution.

kirly
  • 101
  • 1
  • 2
  • 5
  • possible duplicate of [C++ Virtual template method](http://stackoverflow.com/questions/7968023/c-virtual-template-method) – MatthiasB Feb 21 '14 at 11:00
  • Do you need all arithmetic operations on your types or is it limited? You have always the problem that you don't know the actual type of a subclass. – MatthiasB Feb 21 '14 at 11:01
  • Your problem is you cannot have such like `[various_types]` as return type of a virtual function at all, unless you make `my_interface` a template class also. – πάντα ῥεῖ Feb 21 '14 at 11:04
  • This not possible because C++ is a statically typed language and return types cannot be derived from the dynamic type. You might want to have a look at Boost.Variant and/or Boost.Any for implementations of similar problems. However, nobody can say if it is what you need, because you did not give us the original problem behind this: tell us *what* you want to achieve, not *how* you try to solve it. – Arne Mertz Feb 21 '14 at 11:05
  • @MatthiasBonora: sorry but I need an interface, not an abstract class, In fact, you understood, I was talking about arithmetic operators overloading. So yes, I will need all arithmetic operations. – kirly Feb 21 '14 at 11:16
  • @πάνταῥεῖ: In my case, it would be inconvenient to make my_interface a template – kirly Feb 21 '14 at 11:17

5 Answers5

1

If you have just one methods (getValue()) on your interface then you only need the template class implementation.

However if you want to an interface like this:

std::string getValue();
int getValue();
long getValue();

Then you are out of luck as you cannot overload a function name based only on the return type. Alternatively you could create a wrapper type.

EDIT

By wrapper type what I mean is that if getValue is required to return multiple types you could do it in a number of ways using a wrapper class that encapsulates your required functionality rather than add it to your top level interface. It could look something like this:

enum ValType{
  INT, CHAR, STR, DEQUE
};

class Wrapper{
private:
  union S{
    int intVal;
    char charVal;
    std::string stringVal;
    std::deque dequeVal;
    ~S() {}
  } theVal;

  ValType heldType;
public:
  void setVal(int value){ heldType = INT; theVal.intVal = value; }
  void setVal(char value){ heldType = CHAR; theVal.charVal = value; }
  // ... and so on
  int getIntVal() const {
    if(heldType!=INT) 
      throw std::runtime_error("Cop on");
    return theVal.int;
  }
  // and so on
}

Then your interface is

public class my_interface{
  virtual Wrapper getVal();
}

You are not really gaining much here as the user will still have to call the correct child member of Wrapper. You could also just represent the return values as a string if you wanted.

Note that using unions you need to be careful of the caveats: http://en.cppreference.com/w/cpp/language/union

EDIT 2: You could do this with a templated return

template<typename = T>
const T& getVal(const T& typeToAllowMethodOverriding) const;
Dennis
  • 3,683
  • 1
  • 21
  • 43
  • No I said there were other methods in that interface. But what do you mean by a wrapper type? – kirly Feb 21 '14 at 11:55
  • oh ok, I understand what you did here. But as you said, getting values is as difficult as for the class template... In fact, I think the good thing to do would be something like return a templated object which contains the value. But I have the same trouble: my interface could not have a method which returns a templated type... – kirly Feb 23 '14 at 22:39
  • Yes you can return a template type but only if you know the type when calling it. You would still need to provide a mechanism to override the method correctly (using a parameter). See EDIT 2 – Dennis Feb 24 '14 at 09:18
0

Remember that 'virtual ...' means "make a function pointer in the class that I will use to call the correct derived class". It is just a pointer -- so you have to agree on the return type before you call it. C++ doesn't have the dynamic types and reflection of other languages - it has to know what the return type is before making the call.

Rob
  • 3,315
  • 1
  • 24
  • 35
0

You could make class my_interface a template class as well:

template<typename T>
class my_interface
{
public:
    virtual T getValue() const = 0;
};

This will generate an interface and a class for every type T that you use.

Simon Bosley
  • 1,114
  • 3
  • 18
  • 41
  • 1
    Does this work? my_interface and my_interface would be different types, thus eliminating the point of the interface – MatthiasB Feb 21 '14 at 11:12
  • Well only if you have multiple subclasses of the same type, but if there is only one subclass per type then it's not really a viable solution – Simon Bosley Feb 21 '14 at 11:24
0
    template<typename U>
class my_interface
    {
    public:

        virtual  U  getValue() const = 0;
    };

    template<typename T>
    class my_class : public my_interface<T>
    {
    private:
        T    _value;
    public:
        my_class(T value) : _value(value) {} // initialize the attribute on construct

           T getValue() const { return  _value; }
    };

It works for all types but for string type you have to do specialization of templates

Iqbal Haider
  • 310
  • 1
  • 3
  • 9
0

I think your best shot will be to use/implement something like boost::variant.

typedef boost::variant<char, short, int, float, double> Value;

class my_interface
{
public:
    virtual Value getValue() const = 0;
};

template<typename T>
class my_class : public my_interface
{
private:
    T    _value;
public:
    my_class(T value) : _value(value) {} // initialize the attribute on construct
    virtual Value getValue() const { return _value; }
};

Then you could implement the arithmetic operators:

Value operator+(const Value &lhs, const Value &rhs) {
    //Check the internal types of lhs and rhs and perform the operation
}

You can also wrap the boost::variant in another class, to provide conversion operators to the basic types.

C. E. Gesser
  • 811
  • 6
  • 12