为什么使用 static_cast(*this) 转换到基类会创建一个临时副本?

26

我正在阅读 Effective C++,看到了这个例子:

class Window {                                // base class
public:
  virtual void onResize() { ... }             // base onResize impl
  ...
};

class SpecialWindow: public Window {          // derived class
public:
  virtual void onResize() {                   // derived onResize impl;
    static_cast<Window>(*this).onResize();    // cast *this to Window,
                                              // then call its onResize;
                                              // this doesn't work!

    ...                                       // do SpecialWindow-
  }                                           // specific stuff

  ...

};

这本书中提到:

你可能没有想到的是,它不会在当前对象上调用该函数!相反,强制类型转换会创建一个基类部分的新临时副本*this,然后在副本上调用onResize!

为什么static_cast(上面的代码)要创建一个新的副本?为什么不能只使用对象的基类部分?


1
如果将其转换为 static_cast<Window&>(*this).onResize();,那么我认为它会使用当前对象。(请注意 &)。不过我不确定。 - Aaron McDaid
1
static_cast<Window*>(this)->onResize(); 这一行代码也可以运行,但是正确的写法是 Window::onResize(); - Trass3r
4个回答

32

因为这段代码要求创建一个新对象。这段代码想要从*this创建一个Window对象,这可以通过Window拷贝构造函数完成。

你实际想要的是:

static_cast<Window&>(*this).onResize(); 
//                ^
//                note the &

这意味着我想从*this创建一个Window& - 这是从派生类的引用*this是一个SpecialWindow&)到Window&引用的隐式转换。

然而,更好的方法是只调用你想要调用的成员函数onResize()的具体版本:

Window::onResize(); // equivalent to this->Window::onResize();

为什么不只使用对象的基类部分呢?这难道不是真正的答案,因为标准规定了这样做吗?它可以采用不同的方式,但这就是我们必须接受的 - 不管好坏(实际上这破坏了我的尝试,通过函数指针解决虚拟基成员函数的问题,这让我跌跌撞撞地来到这里)。 - Aconcagua

8

这是因为代码将值 Window 转换而不是引用 Window&。根据标准,这种转换的形式等同于调用 (C++11 §5.2.9/4 = C++03 §5.2.9/2)

Window __t (*this);
__t.onResize();

该语句调用Window类的复制构造函数,并对该复制品执行onResize操作。

(调用超类方法的正确方法是

Window::onResize();

)


2
因为你正在转换实际对象而不是指针或引用。 这就像将 double 转换为 int 一样,创建一个新的 int,而不是重用 double 的部分。

1

对比:

static_cast<Window>(*this)

使用:

static_cast<Window&>(*this)

一个调用复制构造函数,另一个不调用。那有帮助吗?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接