0

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.

Sagar Jha
  • 1,068
  • 4
  • 14
  • 24
  • 1
    Would it be possible for you to make it virtual and then have `bar_class2` implement `int fun()` and have it delegate to a private `float fun()`? – chris Feb 24 '14 at 14:55
  • 1
    Your example is a bit confusing, since the member functions have a return type, but they don't return anything, and the return value isn't used by the caller. – Vaughn Cato Feb 24 '14 at 14:57
  • @chris What you are suggesting is not clear. Can you please elaborate? – Sagar Jha Feb 24 '14 at 15:02
  • @VaughnCato The return value is being used in the actual setting. I can add it here, but I omitted it for simplicity. Also, the distinction between the different return types for the derived class methods is important. – Sagar Jha Feb 24 '14 at 15:04
  • @SagarJha, I guess I'll just make it an answer and you can see if it meets your needs. Except I just realized it would be trying to overload based on return type, so it might not work out. – chris Feb 24 '14 at 15:04
  • 1
    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? – eerorika Feb 24 '14 at 15:08
  • Yeah, the only other thing I can think of to handle it in the classes is to use `dynamic_cast`, unfortunately. You'll have to think about *why* it would come to that and not be supported more simply. – chris Feb 24 '14 at 15:11
  • @user2079303 No, we just want that the `fun` function of that class be called which is lowest in the inheritance tree (and the object is an instantiation of that class). Wouldn't that be safe? – Sagar Jha Feb 24 '14 at 15:17
  • @SagarJha: *"Also, the distinction between the different return types for the derived class methods is important"*. So, how do you use the return type ? – Jarod42 Feb 24 '14 at 15:20
  • 1
    @SagarJha no it wouldn't be safe. Because the caller wouldn't know the return type. Say you do this: `int result = foo_pointer->fun();` What if `fun` returns a float instead? How do you know whether you get float or int? C++ does not allow that. Compiler must know the type during compile time. – eerorika Feb 24 '14 at 15:21
  • @user2079303 Okay, I realize that now. The compiler cannot be sure at compile time, which derived class object the base class pointer is pointing to. It probably means, that I will have to use some work around to get what I want. – Sagar Jha Feb 24 '14 at 15:28

4 Answers4

4

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;
}
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Will these casty suggestion really help anybody? – Wolf Feb 24 '14 at 15:48
  • 1
    @Wolf It tells the asker that what he asks cannot be done in a type safe way. What he asks does not make any sense in a type safe language. I believe my answer helps anyone who considers this type of design to understand that they need to redesign (hopefully, the code helps them understand why they need to). How to do that redesign depends a lot on what they intend to do with their classes. It's impossible to tell what OP intends to do from his question. – eerorika Feb 24 '14 at 15:55
3

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.

chris
  • 60,560
  • 13
  • 143
  • 205
1

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.

Community
  • 1
  • 1
Wolf
  • 9,679
  • 7
  • 62
  • 108
  • 1
    This will cause an error due to `bar_class2::fun` overriding it, but having an incompatible return type. – chris Feb 24 '14 at 15:31
  • Sorry I overlooked this detail, it's corrected now. – Wolf Feb 24 '14 at 15:33
  • 1
    That doesn't address Sagar's problem either. The lack of return statements was just an oversight while creating a minimal example of the problem, as Sagar stated in a comment on the original question.The entire point of Sagar's question is that different return types are needed within an inheritance hierarchy. – jamessan Feb 24 '14 at 15:37
  • @jamessan but this is not possible - with late binding. – Wolf Feb 24 '14 at 15:43
  • Sure, but that doesn't change what Sagar is asking for. Changing the intent of his code to provide an answer, doesn't solve the problem. – jamessan Feb 24 '14 at 15:46
  • @Wolf +1 This is a good solution if OP wants to output the data into a stream. A more general case would probably be `fun` whose parameter is a functor that has `operator()` overloads for parameter types that any foo implementation might have. – eerorika Feb 24 '14 at 16:10
0

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 *.

nicky_zs
  • 3,633
  • 1
  • 18
  • 26