5

考虑以下代码段:

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被分配*button,但为什么两个输出不同。分配给引用类型和非引用类型有什么区别?

4

4 回答 4

10

您遇到了切片问题。

Window bRef   =*button;

这里 bRef 不是引用而是对象。当您将派生类型分配给 bRef 时,您正在切分派生部分,只留下一个由 CommandButton 构造的 Window 对象。

发生的情况是,bRef 是在上述语句中使用编译器为类 Window 生成的复制构造函数创建的。这个构造函数所做的只是将成员元素从 RHS 复制到新构造的对象。由于该类不包含任何成员,因此没有任何事情发生。

附带说明:具有虚拟成员的类也应该有一个虚拟析构函数。

于 2010-12-24T06:41:34.093 回答
7
  • aRefWindow 静态类型但CommandButton 动态类型
  • bRef只是一个类型的对象Window部分”在副本中丢失了CommandButton

这通常称为对象切片,它通常通过使基类抽象(通过提供纯虚函数)或不可复制(例如使用boost::noncopyable)来防止,因为任何一种解决方案都会使代码无法在线编译Window& aRef = *button;


现在,为什么bRef.Create()打电话Window::Create?好吧,没有什么比Windowin更多的了,bRef所以真的没有太多的选择。这本质上就像声明 aWindow并调用它:从实例复制Create的事实是无关紧要的,因为该部分在副本中丢失了。bRefCommandButtonCommandButton

我将尝试通过引用标准 (10.3/6) 来更清楚地说明这一点:

[注意:虚函数调用的解释取决于调用它的对象的类型(动态类型),而非虚成员函数调用的解释仅取决于指针的类型或表示该对象的引用(静态类型)(5.2.2)。]

只有通过指针或引用间接,对象的静态类型才能不同于其动态类型。

于 2010-12-24T06:42:09.697 回答
2
Window bRef=*button;
bRef.Create(); // Output: Base class Window

bRef只有静态和动态类型Window。虚拟机制仅适用于引用和指针。bRef是一个对象而不是引用或指针。

于 2010-12-24T06:41:11.243 回答
1
 Window bRef=*button;
 bRef.Create(); // Output: Base class Window

这里bRef不是对button(你刚刚这样命名)的引用。bRef 仅获取基础子对象,即Window.

于 2010-12-24T06:41:20.303 回答