【问题标题】:Why is it allowed to static_cast a method of a derived class to a method of the base class?为什么允许将派生类的方法静态转换为基类的方法?
【发布时间】:2020-04-01 08:42:13
【问题描述】:

例子

struct B1{int x; void f(){x = 1;}};
struct D : B1{int x; void f(){B1::x = 2;}};

using Dmp = void(D::*)();
using B1mp = void(B1::*)();

int main()
{
    Dmp dmp = &D::f;
    D d;
    (d.*dmp)(); // ok

    B1mp b1mp = static_cast<B1mp>(dmp); // hm, well that's weird
    B1 b1;
    (b1.*b1mp)();

    dmp = &B1::f; // ok
}

而且这个例子编译运行得很好,不会出现问题。但是等等,现在我要在D::f 中使用D::x,现在——任何事情都可能在运行时发生。

是的,你也可以static_cast一个指向基的指针指向一个派生的指针。

static_cast<D*>( (B1*)0 )

但是在这里你可以使用 RTTI 来检查类型,或者如果可能的话只使用dynamic_cast

【问题讨论】:

  • 即使D::f 不使用任何其他D 成员,程序也有未定义的行为。写b1.*b1mp获取对象中不存在的成员是无效的,不管该成员的定义是什么。

标签: c++ methods language-lawyer function-pointers static-cast


【解决方案1】:

是的,static_cast 允许许多可能以“不安全”方式使用的东西,例如将void* 转换为另一种对象指针类型,将Base* 转换为Derived*,还有这个。

虽然static_castreinterpret_castconst_cast 相比可以被认为是“相对安全”,但它仍然是一个演员表。和所有类型转换一样,它代表了一个忽略类型系统的一些安全要求的请求,然后程序员负责仔细和正确地使用它。

【讨论】:

  • 然后由程序员负责仔细和正确地使用它。这就是事情发生严重错误的地方。在整个编程范围内。
  • @vini 如果我们能拥有一种完全安全、用途极其广泛且极具表现力的语言,该语言有助于高效实施和愉快使用。
【解决方案2】:

void f(B *b) {
  static_cast<D*>(b)->d_method();
  b->static_cast<void (B::*)()>(&D::d_method)();
}

您假设bD 在每种情况下的程度完全相同。能够转换指向成员的指针允许 调用者 在传递给期望成员指针的函数时从 any 派生类中指定任何函数基地。

【讨论】:

  • bstatic_cast&lt;D*&gt;(b) 具有不同的地址,但是当将指针转换为指向方法时,不会进行偏移,使其成为 UB。
  • @Adler:这不是我对expr.static.cast/12 的解读(及其引用的 [expr.mptr.oper]/4)。您可以see the adjustment 获取指向数据成员的指针;指向成员函数的指针更复杂,但确实存储了 this 的偏移量。
猜你喜欢
  • 1970-01-01
  • 2013-05-30
  • 2012-05-24
  • 2015-04-08
  • 2010-09-12
  • 2011-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多