Behavior of C++ Object Reference
Asked Answered
M

4

5

Consider the following code segment:

class Window // Base class for C++ virtual function example
     {
       public:
          virtual void Create() // virtual function for C++ virtual function example
          {
               cout <<"Base class Window"<<endl;
          }
     };

     class CommandButton : public Window
     {
       public:
          void Create()
          {
              cout<<"Derived class Command Button - Overridden C++ virtual function"<<endl;
          }
     };

     int main()
     {
        Window *button = new   CommandButton;
        Window& aRef = *button;
        aRef.Create(); // Output: Derived class Command Button - Overridden C++ virtual function
        Window bRef=*button;
        bRef.Create(); // Output: Base class Window

        return 0;
     }

Both aRef and bRef get assigned *button, but why are the two output different. What is the difference between assigning to Reference type and non Reference type?

Mew answered 24/12, 2010 at 6:35 Comment(0)
S
10

You have encountered the slicing problem.

Window bRef   =*button;

Here bRef is not a reference but an object. When you assign a derived type onto bRef you are slicing the derived part off leaving you with just a Window object constructed form a CommandButton.

What is happening is that bRef is created in the above statement using the compiler generated copy constructor for the class Window. All this constructor does is copy member elements from the RHS to the newly constructed object. Since the class contains no members nothing is happening.

On a side note: A class with virtual members should also have a virtual destructor.

Sirius answered 24/12, 2010 at 6:41 Comment(5)
So, with this copy constructor late binding simply doesn't happen, right?Mew
Gunner: Late Binding is not relevant here. You are creating a new statically typed object not a dynamically typed object (for that you need a reference or a pointer).Sirius
virtual or protected destructor. In many designs member functions are called polymorphically without deleting polymorphically.Lashay
@Ben Voigt: Sure when you control aspects of the objects lifespan. But when you are learning not such a good idea as you are more likely to get it wrong.Sirius
If you mark the destructor protected, the compiler won't let you do it wrong.Lashay
G
7
  • aRef has Window static type but CommandButton dynamic type
  • bRef is simply an object of type Window (the CommandButton 'part' was lost in the copy)

This is commonly known as object slicing and it usually prevented by making base classes either abstract (by providing a pure virtual function) or non copyable (for example using boost::noncopyable), because either solution would make the code fail to compile on line Window& aRef = *button;.


Now, why does bRef.Create() call Window::Create ? Well, there is nothing more than a Window in bRef so there really isn't much of an alternative. This is essentially like declaring a Window and calling Create on it : the fact that bRef was copied from a CommandButton instance is irrelevant because the CommandButton portion was lost in the copy.

I'll try to make this clearer by quoting the standard (10.3/6) :

[Note: the interpretation of the call of a virtual function depends on the type of the object for which it is called (the dynamic type), whereas the interpretation of a call of a nonvirtual member function depends only on the type of the pointer or reference denoting that object (the static type) (5.2.2). ]

Only through a pointer or reference indirection can the static type of an object differ from its dynamic type.

Glow answered 24/12, 2010 at 6:42 Comment(0)
L
2
Window bRef=*button;
bRef.Create(); // Output: Base class Window

The static as well as dynamic type of bRef is Window only. Virtual mechanism works only with references and pointers. bRef is an object not a reference or a pointer.

Legaspi answered 24/12, 2010 at 6:41 Comment(0)
P
1
 Window bRef=*button;
 bRef.Create(); // Output: Base class Window

Here bRef is not the reference to button (you just named it so). bRef gets only the base subobject which is Window.

Pericarp answered 24/12, 2010 at 6:41 Comment(4)
But what is the effect of this assignment I am doing. Since *button was initialized using CommandButton, shouldn't this be compile error then?Mew
No. Your Window class has a copy constructor Window(const Window&). Since CommandButton is a Window, it can be the argument to that copy constructor.Density
@Slavik81 : Yes, so? How does it invalidate what I said?Pericarp
Sorry, I should have used an @Gunner because I was responding to himDensity

© 2022 - 2024 — McMap. All rights reserved.