我在派生类B::foo()
中的成员函数D::foo()
的定义中使用了调用D
。 It works,但由于我以前从未使用过这个,所以我想知道标准中引用这个结构的引用。
#include <iostream>
class B {
public:
virtual void foo() = 0;
};
inline void B::foo() { std::cout << "B::foo()" << '\n'; }
class D : public B {
public:
void foo() { std::cout << "D::"; B::foo(); }
};
int main() {
D d;
d.foo();
}
修改
这question与我的问题无关!
答案 0 :(得分:3)
使用B::foo
语法调用函数通常是完全合法的。
C ++标准中详述的例外情况是,当您使用纯虚函数执行不通过B::foo
进行调用时,您不必定义它。 10.4 / 2 :(来自@jrok)
[...]只有在使用或(12.4)调用qualified-id语法(5.1)时才需要定义纯虚函数。 [...]
B::foo()
语法是使用qualified-id语法调用foo
的示例。请注意,这与执行虚拟表查找的(this->*&B::foo)()
语法不同。
纯虚函数不是&#34;将函数设置为空指针&#34;尽管有=0
语法。相反,它将其标记为&#34;为了实例化此类,我要求后代覆盖此方法&#34;。碰巧,编译器倾向于将纯虚函数的虚函数表设置为指向一个错误处理程序,该错误处理程序设置一个错误(至少在调试中),你进行了一个纯虚函数调用,因为设置起来非常便宜up,它诊断在后代类实例生存期之前或之后的构造/销毁过程中对所述方法的调用。
即使您的父级定义了方法,也可以将方法标记为纯虚拟。这只表示您的子实现必须再次覆盖它。即使您定义了方法,也可以将方法标记为纯虚拟。同样,这只是告诉您的孩子实现他们必须覆盖它。
作为奖励答案,我们为什么要这样做?有时,您希望在基类中实现部分实现,以便在子实现之前或之后调用。其他时候您需要默认实现。在每种情况下,您都希望将某些代码耦合到此方法,并且您希望强制子级覆盖它。
您可以在名为virtual
或before_foo
的不同非default_foo
方法中实施before / after / default,或者您可以这样做。
在其他时候,在深层次结构中,从上面继承的某些方法的实现可能不再有效。所以你要=0
表明孩子们必须再次覆盖它。
这两种情况都是极端情况。
我使用这种技术的最后一点是我想要消除(bar->*&Bar::foo)()
烦恼。我重写Bar::foo
来(this->*&Bar::foo)()
,允许bar->Bar::foo()
做正确的事情&#34;神奇地&#34;。
答案 1 :(得分:0)
我没有仔细阅读标准,以便能够确定您所说的电话是合法的。但是,使用完全限定名称创建函数必须起作用。使用隐式限定名称只是一种快捷方式。
在您的主要功能中,当您致电:
d.foo();
等同于
d.D::foo();
第一个是隐式限定为'D :: foo'。第二个明确限定为D:foo
。你也可以打电话
d.B::foo();
这将绕过D::foo()
并直接转到B::foo()
。