Access of member functions in C++ inheritance
我只是对下面关于继承的小程序感到困惑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include<iostream> using namespace std; struct B { virtual int f() { return 1; } }; // f is public in B class D : public B { int f() { return 2; } }; // f is private in D int main() { D d; B& b = d; cout<<b.f()<<endl; // OK: B::f() is public, D::f() is invoked even though it's private cout<<d.f()<<endl; // error: D::f() is private } |
有人能详细解释这个简单的继承问题吗?
这与虚拟调度是一个运行时概念有关。类
I can't figure out why D::f() is private, D is public inherited from B, so the public function f in B
is also public in D(I know without inheritance, member access is private by default)
号
f is a virtual function in B, so if we call b.f(), we actually call D::f(), but just as the illustration mentioned, why D::f() is able to be invoked even though it's private?
号
因为实际上,当调用
如果函数是在运行时选择的,则编译器在编译时无法知道将调用什么函数,也无法知道访问说明符。实际上,编译器甚至不会尝试检查调用的函数是否是私有的。访问说明符可能在编译器尚未看到的某些代码中。
正如你所经历的,你不能直接打电话给
访问说明符只应用于函数名,它们不限制如何或何时可以通过其他方法调用函数。如果私有函数的名称(例如,函数指针)以外的其他方式可用,则可以在类外部调用它。
对于使用
1 2 3 4 5 6 | // ... class D: public B { private: int f() { return 2; } }; |
号
如你所见,
这个过程仍然使用
C++标准有一个确切的例子:
11.5 Access to virtual functions [class.access.virt]
1 The access rules (Clause 11) for a virtual function are determined by its
declaration and are not affected by the rules for a function that later
overrides it. [Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 class B {
public:
virtual int f();
};
class D : public B {
private:
int f();
};
void f() {
D d;
B* pb = &d;
D* pd = &d;
pb->f(); // OK: B::f() is public,
// D::f() is invoked
pd->f(); // error: D::f() is private
}-- end example]
号
解释不清楚。
给出的答案说明了正在做什么,但是为什么您会想要这样做呢,在基类调用
好吧,有一个名为模板方法模式的设计模式,它使用了这样一种技术,即拥有一个在派生类中调用私有虚函数的基类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | struct B { virtual ~B() {}; int do_some_algorithm() { do_step_1(); do_step_2(); do_step_3(); } private: virtual void do_step_1() {} virtual void do_step_2() {} virtual void do_step_3() {} }; class D : public B { void do_step_1() { // custom implementation } void do_step_2() { // custom implementation } void do_step_3() { // custom implementation } }; int main() { D dInstance; B * pB = &dInstance; pB->do_some_algorithm(); } |
这允许我们不向
这实际上与虚拟调度的关系不大,而与访问说明符的含义有关。
函数本身不是
因此,函数的命名不能超出类的范围,例如从
这就是它的工作原理。
why D::f() is able to be invoked even though it's private?
号
要理解虚拟功能机制,最好了解它通常是如何实现的。运行时的函数实际上不超过函数体的可执行代码所在的内存中的地址。要调用函数,我们需要知道它的地址(指针)。在内存中具有虚函数表示的C++对象包含所谓的VTABLE——指向虚拟函数的指针数组。
。
关键是在派生类vtable中重复(并且可以扩展)基类的vtable,但是如果覆盖了虚函数,则它的指针将在派生对象的vtable中替换。
当虚拟函数调用通过基类指针完成时,虚拟函数的地址计算为vtable数组中的偏移量。不进行其他检查,只取函数地址。如果它是一个基类对象,它将是基类函数的地址。如果它是派生类对象,它将是派生类函数的地址,不管它是否声明为私有。
这就是它的工作原理。
EDOCX1的成员(25)默认为public,EDOCX1的成员(11)默认为private。所以B中的