问题
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?
回答1:
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.
回答2:
aRef
hasWindow
static type butCommandButton
dynamic typebRef
is simply an object of typeWindow
(theCommandButton
'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.
回答3:
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.
回答4:
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
.
来源:https://stackoverflow.com/questions/4524639/behavior-of-c-object-reference