在C++继承中访问成员函数

Eri*_*Luo 24 c++ inheritance private

我对以下关于继承的小程序感到困惑:

#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
}
Run Code Online (Sandbox Code Playgroud)
  1. 我想不通为什么D::f()是私有的,D公共继承B,所以公共职能fB
    也公开在D(我知道没有继承,成员访问是私人默认)
  2. f是一个虚函数B,所以如果我们打电话b.f(),我们实际上打电话D::f(),但正如图中所提到的,为什么D::f()即使它是私人的,也可以被调用?

任何人都可以详细解释简单的继承问题吗?

Gui*_*cot 21

这必须做到这一点,虚拟调度是一个运行时概念.该类B并不关心哪个类扩展它,并且它不关心它是私有的还是公共的,因为它无法知道.

我无法弄清楚为什么D :: f()是私有的,D是公共继承自B,因此B中的公共函数f在D中也是公共的(我知道没有继承,默认情况下成员访问是私有的)

D::f()是私人的,因为你把它变成了私人.此规则不受继承或虚拟分派的影响.

f是B中的虚函数,所以如果我们调用bf(),我们实际调用D :: f(),但正如图中所提到的,为什么D :: f()能够被调用,即使它是私有的?

因为实际上,在调用时b.f(),编译器不知道实际调用哪个函数.它将简单地调用该函数f(),并且由于它B::f是虚拟的,因此将在运行时选择被调用的函数.运行时程序没有关于哪个功能是私有还是受保护的信息.它只知道功能.

如果在运行时选择了该函数,则编译器无法在编译时知道将调用哪个函数,并且无法知道访问说明符.实际上,编译器甚至不会尝试检查被调用的函数是否是私有的.访问说明符可能在编译器还没有看到的某些代码中.

如您所见,您不能D::f直接打电话.这正是私人所做的:禁止直接访问会员.但是,您可以通过指针或引用间接访问它.您使用的虚拟调度将在内部执行.


M.M*_*M.M 11

访问说明符仅适用于函数名称,它们对通过其他方式调用函数的方式或时间没有一些限制.如果通过除名称之外的某些方式(例如,函数指针)使私有函数可用,则可以在类外部调用私函数.

对于使用classkeyword 声明的类,默认的访问说明符是private.您的代码与以下内容相同:

// ...
class D: public B
{
private:
  int f() { return 2; }
};
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,f是私人的D.对于B具有相同名称的任何函数,访问说明符的含义没有区别.在你的头脑是清楚的B::f(),并D::f()有两种不同的功能.

virtual关键字的作用是,如果f()没有在B引用D对象的引用上调用范围限定符,那么即使它解析为B::f(),实际上D::f()也会调用它.

此过程仍然使用访问说明符B::f():在编译时检查访问; 但是关于调用哪个函数可能是运行时间问题.


Tem*_*Rex 6

C++标准有一个确切的例子:

11.5访问虚函数[class.access.virt]

1虚函数的访问规则(第11条)由其声明确定,不受稍后覆盖它的函数规则的影响.[ 例如:

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
} 
Run Code Online (Sandbox Code Playgroud)

- 结束例子 ]

无法解释清楚.


Pau*_*zie 5

给出的答案说明了正在做什么,但为什么你会想要这样做,基类调用private虚函数?

好吧,有一种称为模板方法模式的设计模式 ,它使用这种技术,它具有一个在派生类中调用私有虚函数的基类.

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();
}
Run Code Online (Sandbox Code Playgroud)

这允许我们不将类的自定义步骤暴露Dpublic接口,但同时允许B使用public函数调用这些函数.