Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: How to define a virtual function with generic return type?

Tags:

c++

oop

I'm trying to define a base a class in C++ that has pure virtual methods to be implemented by children classes.

I would like to define setter and getter functions for basic types in the base class, but I would like the derived class to be able to determine the basic type of the getter and setter. For instance my base class would look like this:

    class Value
    {
    public:
        Value();
        template <class T>;
        virtual T getValue() = 0;
        virtual void setValue(T val) = 0;
    }

and my child class would look something like this:

    class IntValue : public Value
    {
    public:
        IntValue();
        template <class T>
        T getValue() {return _val};
        void setValue(T val) {_val = val};
    private:
        int _val;
    }

Of course the above code does not work. Any ideas on how to achieve this? Thanks in advance.

like image 868
mbadawi23 Avatar asked Dec 27 '22 00:12

mbadawi23


2 Answers

If I understood your problem correctly, rewriting your code to

template <class T>
class Value
{
public:
    Value();
    virtual T getValue() = 0;
    virtual void setValue(T val) = 0;
};


class IntValue : public Value<int>
{
public:
    IntValue();

    int getValue() {return _val;}
    void setValue(int val) {_val = val;}
private:
    int _val;
};

should work

like image 160
J_D Avatar answered Dec 30 '22 09:12

J_D


What you're asking for is not possible. In order to generate the right entries in the vtbl (or whatever similar structure the compiler might be using), the compiler needs to know what entries are going to be needed in the base class specifically. You can't just return a different type in a derived class and expect the base class to "know" about it in that way; as that would require a modification of the definition of the function template in the base class.

An example of how you might do that kind of modification of the base class using a class template (rather than a function template) can be seen in J_D's answer, but that still doesn't match your problem description exactly, because you wouldn't be able to create a Value and treat it polymorphicly.

C++ templates are essentially "fancy-pants find and replace" with the type -- when the compiler instantiates the function template, it generates a plain function with the typenames replaced. Note that this is very different than C# or Java "generics", which are completely different and rely on runtime support and a layer of indirection to achieve a similar effect. (Note though that this "find and replace" respects precedence rules and such, unlike C preprocessor macros :) )

If you really think about it too, this pattern does not make sense. What would this really look like on the client side of things?

class Value
{
public:
    Value();
    //Imagine if this were possible...
    template <class T>;
    virtual T getValue() = 0;
    virtual void setValue(T val) = 0;
}

class IntValue : public Value
{
public:
    IntValue();
    int getValue() {return _val};
    void setValue(int val) {_val = val};
private:
    int _val;
}

class FloatValue : public Value
{
public:
    FloatValue();
    float getValue() {return _val};
    void setValue(float val) {_val = val};
private:
    float _val;
}

Now, you go to use this class:

void example(Value * ptr)
{
    //What could you possibly say the type of "bar" is? There's no type that works!
    ???? bar = ptr->getValue();
    delete ptr;
}

int main()
{
    example(new IntValue());
    example(new FloatValue());
}

As such, even if this were allowed, it wouldn't make much sense. You'd always have to downcast all the time, which would mean that the virtual keyword would be meaningless anyway.

like image 32
Billy ONeal Avatar answered Dec 30 '22 10:12

Billy ONeal