考虑以下代码段:
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;
}
aRef 和 bRef 都会被分配 *按钮,但为什么两个输出会有所不同。 分配参考类型和非参考类型有什么区别?
答案 0 :(得分:10)
您遇到了切片问题。
Window bRef =*button;
这里bRef不是引用而是对象。当您将派生类型分配到bRef上时,您正在对派生部分进行切片,只留下一个由CommandButton构造的Window对象。
正在发生的事情是,使用编译器生成的类Window的复制构造函数在上面的语句中创建了bRef。所有这些构造函数都是将成员元素从RHS复制到新构造的对象。由于该课程不包含任何成员,因此没有任何事情发生。
旁注:具有虚拟成员的类也应该有一个虚拟析构函数。
答案 1 :(得分:7)
aRef
有Window
静态类型,但CommandButton
动态类型bRef
只是Window
类型的对象( CommandButton
'部分'在副本中丢失)< / LI>
这通常被称为object slicing,它通常通过使基类抽象(通过提供纯虚函数)或不可复制(例如使用boost::noncopyable
)来防止,因为任何一种解决方案都会使代码无法在第Window& aRef = *button;
行编译。
现在,为什么bRef.Create()
拨打Window::Create
?好吧,Window
中只有bRef
,所以实际上没有太多选择。这基本上就是声明Window
并在其上调用Create
:bRef
从CommandButton
实例复制的事实无关紧要,因为CommandButton
部分是丢失在副本中。
我会试着通过引用标准(10.3 / 6)来使这个更清楚:
[注:解释电话 虚函数取决于 它所对象的类型 叫(动态类型),而 解释一个电话 非虚拟成员函数取决于 仅限指针的类型或 表示该对象的引用( 静态类型)(5.2.2)。 ]
只有通过指针或引用间接,对象的静态类型才能与其动态类型不同。
答案 2 :(得分:2)
Window bRef=*button;
bRef.Create(); // Output: Base class Window
bRef
的静态和动态类型仅为Window
。虚拟机制仅适用于引用和指针。 bRef
是一个对象而不是引用或指针。
答案 3 :(得分:1)
Window bRef=*button;
bRef.Create(); // Output: Base class Window
此处bRef
不是button
的引用(您只是将其命名为)。 bRef只获取Window
的基础子对象。