1

The following code:

#include <stdio.h>
class Parent
{
public:
    virtual void func() {printf("Parent\n");}
};

class Child1 : public Parent
{
    virtual void func() {printf("Child1\n");}
};

class Child2 : public Parent
{
    virtual void func() {printf("Child2\n");}
};

int main(int argc, char* argv[])
{
    Parent & obj = Child1();
    obj.func();
    obj = Child2();
    obj.func();
    return 0;
}

yields the following results:

expected: Child1 Child2.

actual: Child1 Child1. 

(compiled on VS2010)

I guess that the vptr is not changed by the assignment. It there a way to cause it to be re-created (other than using a pointer to Parent and assigning to it using new)?

thanks

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
OSH
  • 2,847
  • 3
  • 25
  • 46

5 Answers5

3

You're calling the default assignment operator on obj, which is still of type Child1, with an argument of type Child2. The object itself is still of type Child1. You can verify this by implementing operator = on all 3 classes, and inserting a print statement there.

hochl
  • 12,524
  • 10
  • 53
  • 87
  • Thanks. Is there a way of using polymorphism on a ref var? – OSH Nov 22 '11 at 10:29
  • @OrenS. You are using polymorphism. That's why the call to Child1::func works. But you don't have an object of type Child2, but Child1. – Luchian Grigore Nov 22 '11 at 10:31
  • 3
    The only way you can do **rebindable** polymorphics is with pointers. For hopefully obvious reasons, I recommend using smart pointers. – moshbear Nov 22 '11 at 10:31
1

References cannot be reseated - they refer to the same object for their entire lifetime. If you want something that can change the object it refers to then you need to use a [smart] pointer instead of a reference.

What you're doing here is slicing an instance of Child2 by assigning it to an instance of Child1.

Community
  • 1
  • 1
JoeG
  • 12,994
  • 1
  • 38
  • 63
1
Parent & obj = Child1();

You create a reference to an object of type Child1. This is like saying

Child1 c1;
Parent& obj = c1;

obj is now just a different name for c1, which is an object of type Child1.

obj = Child2();
obj.func();

Now, this is like saying

c1 = Child2();
c1.func();

so you see, you're still calling func on an object of type Child1.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
1

Two fundamental properties in C++: an object, once created, never changes its type, and a reference, once initialized, always refers to the same object.

What's happening here is that you are calling the compiler supplied non-virtual operator= for Parent, which is almost certainly not what you wanted. More generally, however, assignment and inheritance don't work well together (precisely because you can't change the type of an object); most of the time, when using inheritance, you should ban assignment (by inheriting from boost::noncopyable, for example). It's possible to implement value semantics for a polymorphic class, using the letter/envelope idiom, but it's a heavy solution, and rarely appropriate.

(I might add that your code doesn't compile with a C++ compiler. You're initializing a reference to a non-const with a temporary, which isn't legal C++. Allowing this is a Microsoft extension.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

What you are doing should give an error in compilation. You can not assign a temporary variable (created by Child2()) to a reference variable. You have to create an instance before of Child2, and assign that variable to the reverence.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • @OrenS. I missread the error, it's actually for the `Parent & obj = Child1();` line I get an error. – Some programmer dude Nov 22 '11 at 10:38
  • 1
    `g++` doesn't compile this, but of course you can always create a variable of type `Child1` and assign from there. Fascinating that VS2010 compiles this in the first place. – hochl Nov 22 '11 at 10:38