1

I was a little surprised that the following code did not work as expected:

#include "stdio.h"

class RetA
{
public:
    virtual void PrintMe () { printf ("Return class A\n"); }
};

class A
{
public:
    virtual RetA GetValue () { return RetA (); }
};

class RetB : public RetA
{
public:
    virtual void PrintMe () { printf ("Return class B\n"); }
};

class B : public A
{
public:
    virtual RetA GetValue () { return RetB (); }
};

int main (int argc, char *argv[])
{
    A instance_A;
    B instance_B;
    RetA ret;

    printf ("Test instance A: ");
    ret = instance_A.GetValue ();
    ret.PrintMe (); // Expected result: "Return class A"

    printf ("Test instance B: ");
    ret = instance_B.GetValue ();
    ret.PrintMe (); // Expected result: "Return class B"

    return 0;
}

So, does virtual methods not work when returning a value? Should I revert to allocating the return class on the heap, or is there a better way?

(In reality I want to do this to let some different classes that inherits from a container class to return different iterator class instances depending on class ...)

Jonatan
  • 3,752
  • 4
  • 36
  • 47
  • I am not sure, as I am also new to C/C++, but are we allowed to have classes in C, it seems you are working in C as you have stdio.h and printf; if using C++, it is not good idea to mix C-ish printf and C++-ish-cout AFAIK, but I am not full sure though. I would like to know more about this from others. – seg.server.fault Aug 10 '09 at 09:18
  • 1
    if you know what you are doing, it is not a problem to "mix" C and C++ – Svetlozar Angelov Aug 10 '09 at 09:24

5 Answers5

17

Polymorphic behavior does not work by value, you need to return pointers or references for this to work.

If you return by value you get what is known as "slicing" which means that only the parent part of the object gets returned, so you've successfully striped a child object into a parent object, this is not safe at all.

Take a look at: What is object slicing?

Community
  • 1
  • 1
Arkaitz Jimenez
  • 22,500
  • 11
  • 75
  • 105
0

Do get dynamic overloading, you need to have the static type different of the dynamic type. You don't here. Return a reference or a pointer (and pay attention to the live time) instead of a value.

AProgrammer
  • 51,233
  • 8
  • 91
  • 143
0

Virtual is applicable to pointer or reference declaration of type, So change you code: virtual RetA& GetValue () or virtual RetA* GetValue (), But you issue not about virtual - you use "copy semantic".

Dewfy
  • 23,277
  • 13
  • 73
  • 121
0

you have to return pointer or address

virtual RetA GetValue () { return RetB (); }

if not, what you get from GetValue is a RetA not RetB.

ufukgun
  • 6,889
  • 8
  • 33
  • 55
0

Besides the already mentioned 'slicing' problem, the PrintMe method must also be virtual.

struct B 
{
   void print1() const { std::cout << "B" << std::endl; }
   virtual void print2() const { print1(); }
};
struct D : public B
{
   void print1() const { std::cout << "D" << std::endl; }
   virtual void print2() const { print1(); }
};
B& f() 
{
   static D d;
   return d; // the object returned is in fact a D, not a B
}
int main(){
   f().print1(); // B: calling a non-virtual method from a B reference
   f().print2(); // D: the method is virtual will exec B::print2
}
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489