问题 为什么静态方法会覆盖基类非静态方法?


struct B {
  void foo () {}
};

struct D : B {
  using B::foo;
  static void foo () {}
};

int main ()
{
  D obj;
  obj.foo();  // calls D::foo() !?
}

会员方法和 static 成员方法完全不同有两个原因:

  1. static 方法不会覆盖 基础中的虚函数 class
  2. 两者的函数指针签名 案件不同

当一个方法被一个对象调用时,成员方法逻辑上不应该有更高的偏好吗? (只是C ++允许 static 使用object调用的方法, 它会被视为被覆盖的吗? 方法 ?)


5824
2018-06-16 06:39


起源



答案:


您所看到的规则在ISO / IEC 14882:2003 7.3.3 [namespace.udecl] / 12中有所描述:

当一个 使用声明 将基类中的名称带入派生类范围,派生类中的成员函数覆盖和/或隐藏基类中具有相同名称和参数类型的成员函数(而不是冲突)。

没有这个规则,函数调用将是模糊的。


9
2018-06-16 06:56



适用于 static 会员呢?如果是,那么为什么呢 static 方法冲突 virtual 方法 ? - iammilind
@iammilind因为这仅适用于using声明。 - Let_Me_Be
@iammilind: virtual 和 static 在这一点上没有任何区别,因为只是重载决议决定了你应该调用哪个函数 D 目的。 - CB Bailey
这是最不明显的事情:在进行非静态分辨时,根本不需要考虑静态方法,但这只是事情的运作方式。 - Eamon Nerbonne
@Eamon:这完全是“脆弱”基类的问题。问题源于可以使用a调用静态方法的事实 dot。从这一点开始, 藏 是强制性的,否则 引入  foo 在基类中可能会破坏 所有 客户代码。 - Matthieu M.


答案:


您所看到的规则在ISO / IEC 14882:2003 7.3.3 [namespace.udecl] / 12中有所描述:

当一个 使用声明 将基类中的名称带入派生类范围,派生类中的成员函数覆盖和/或隐藏基类中具有相同名称和参数类型的成员函数(而不是冲突)。

没有这个规则,函数调用将是模糊的。


9
2018-06-16 06:56



适用于 static 会员呢?如果是,那么为什么呢 static 方法冲突 virtual 方法 ? - iammilind
@iammilind因为这仅适用于using声明。 - Let_Me_Be
@iammilind: virtual 和 static 在这一点上没有任何区别,因为只是重载决议决定了你应该调用哪个函数 D 目的。 - CB Bailey
这是最不明显的事情:在进行非静态分辨时,根本不需要考虑静态方法,但这只是事情的运作方式。 - Eamon Nerbonne
@Eamon:这完全是“脆弱”基类的问题。问题源于可以使用a调用静态方法的事实 dot。从这一点开始, 藏 是强制性的,否则 引入  foo 在基类中可能会破坏 所有 客户代码。 - Matthieu M.


这里的问题是您不能使用具有相同签名的非静态方法重载静态方法。

现在,如果你尝试:

struct D {
  void foo () {}
  static void foo () {}
};

它会触发错误。

我不确定为什么会这样 using B::foo 实际上它被忽略而没有触发错误/警告(至少在GCC 4.5.1上)。


1
2018-06-16 06:49