Question

Consider the following class structure:-

    class foo {
    public:
      int fun () {
        cout << "in foo" << endl;
      }
    };

    class bar_class1:public foo {
    public:
      int fun () {
        cout << "in bar_class1" << endl;
      }
    };

    class bar_class2:public foo {
    public:
      float fun () {
        cout << "in bar_class2" << endl;
      }
    };

    main () {
      foo * foo_pointer = new bar_class1();
      foo_pointer->fun();
    }

The output of the above program is in foo. Is there a way, that using a pointer of type foo * which actually points to an object of type bar_class1 or bar_class2, we can call the fun function of the derived class instead of the base class? I am not able to make the fun function virtual in the base class foo since, then there is a return type conflict for function foo in the derived class bar_class2.

Was it helpful?

Solution

Here's my comments as an answer.

You cannot do that.

If that kind of polymorphism were possible, wouldn't that break horribly when code calls foo::fun (expecting an int) on an object whose actual type is bar_class2 and thus gets a float? Do you want to simply throw away type safety?

If you want different return types, sounds like you want a template. But you cannot use templates quite in the way that you want to use foo(). Static polymorphism (templates) and run time polymorphism (late binding) don't mix well. You need to redesign your oop structure.

If you absolutely hate type safety, you can sort of do this with void pointers. But for the love of Flying Spaghetti Monster, don't ever do this in c++. Please close your eyes before reading the following code to avoid exposure.

#include <iostream>

class foo {
public:
    virtual void* fun() = 0;
    virtual ~foo(){};
};

class bar_class1: public foo {
public:
    void* fun() {
        return &value;
    }
private:
    int value = 1;
};

class bar_class2: public foo {
public:
    void* fun() {
        return &value;
    }
private:
    float value = 1.1;
};

int main() {
    foo* foo_pointer1 = new bar_class1();
    foo* foo_pointer2 = new bar_class2();

    // in c++ compiler must know the type of all objects during compilation
    std::cout << *reinterpret_cast<int*>(foo_pointer1->fun()) << '\n';
    std::cout << *reinterpret_cast<float*>(foo_pointer2->fun()) << '\n';
    delete foo_pointer1;
    delete foo_pointer2;
}

OTHER TIPS

Perhaps similar to the existing answer, I really hope you realize changing your design is better than this mess, but I believe it's the best you're going to get. I force you to specify the return type at the callsite (e.g., someFoo->fun<int>()), since you're going to have to know it anyway, and dispatch based on that. Any funny business and you'll get an exception. Also keep in mind the performance of this is, I imagine, less than desirable.

#include <cassert>
#include <stdexcept> 
#include <type_traits> 

struct foo {       
    virtual ~foo() = default;

    template<typename T, typename = typename std::enable_if<std::is_same<T, int>::value>::type, typename = void>
    T fun();

    template<typename T, typename = typename std::enable_if<std::is_same<T, float>::value>::type>
    T fun();
};

struct bar_class1 : foo {
    int fun() {
        return 2;
    }
};

struct bar_class2 : foo {
    float fun() {
        return 3.5f;
    }
};

template<typename T, typename, typename Dummy>
T foo::fun() {
    if (auto *p = dynamic_cast<bar_class1 *>(this)) {
        return p->fun();
    } else if (dynamic_cast<bar_class2 *>(this)) {
        throw std::invalid_argument("Mismatching dynamic type.");
    } else {
        return 1;
    }
}

template<typename T, typename>
T foo::fun() {
    auto *p = dynamic_cast<bar_class2 *>(this);

    if (dynamic_cast<bar_class1 *>(this) || !p) {
        throw std::invalid_argument("Mismatching dynamic type.");
    } else if (auto *p = dynamic_cast<bar_class2 *>(this)) {
        return p->fun();
    }

    assert(false); //should never get here, but compiler doesn't know that
}

If you'd like the main function, I've written a complete sample.

To answer your question: No, late binding isn't possible without deciding the return type. ...at least not in a reasonable manner, see user2079303's great counter-example. But...

you may change your code (for example) into something like the following, using the keyword virtual and equalize the return type for instance to void:

class foo 
{
public:
    virtual void fun(std::ostream& out) {
        out << "in foo" << std::endl;
    }
};

so you can decide the output type later:

class intFoo: public foo 
{
public:
    void fun(std::ostream& out)  {
        // output an int
        out << "in bar_class1. data: " << data << endl;
    }
    int data;
};

class floatFoo: public foo 
{
public:
    void fun(std::ostream& out)  {
        // output a float 
        out << "in bar_class2. data: " << data << endl;
    }
    float data;
};

For brevity, I double-use the output stream - now a parameter of the function fun() - function to demonstrate type-dependent portion of your derived class. In your application, the parameter will probably be of another, more useful type.

The function fun is not a virtual function since you didn't use the keyword "virtual" to decorate it. So, the compile will determine which function to call at compiling time. So, there is no way to tell the compiler to call another function because the compiler will use its static type, i.e. the variable definition type -- foo *.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top