9

这是一个让我烦恼的代码示例:

class Base {
  protected:
    virtual void foo() = 0;
};

class Derived : public Base {
  private:
    Base *b; /* Initialized by constructor, not shown here
                Intended to store a pointer on an instance of any derived class of Base */

  protected:
    virtual void foo() { /* Some implementation */ };
    virtual void foo2() {
      this->b->foo(); /* Compilator sets an error: 'virtual void Base::foo() is protected' */
    }
};

您如何访问受保护的覆盖功能?

谢谢你的帮助。:o)

4

6 回答 6

11

Protected members in a base-class are only accessible by the current object.
Thus, you are allowed to call this->foo(), but you are not allowed to call this->b->foo(). This is independent of whether Derived provides an implementation for foo or not.

The reason behind this restriction is that it would otherwise be very easy to circumvent protected access. You just create a class like Derived, and suddenly you also have access to parts of other classes (like OtherDerived) that were supposed to be inaccessible to outsiders.

于 2011-01-12T19:04:58.187 回答
6

通常,您会使用 来执行此操作Base::foo(),它指的是当前实例的基类。

但是,如果您的代码需要按照您尝试的方式执行并且不允许这样做,那么您需要将 foo() 公开或将 Derived 设为 Base 的朋友。

于 2011-01-12T18:26:22.463 回答
3

一种解决方案是声明一个静态受保护函数Base,将调用重定向到私有/受保护函数(foo在示例中)。

让我们说:

class Base {
protected:
    static void call_foo(Base* base) { base->foo(); }
private:
    virtual void foo() = 0;
};

class Derived : public Base {
private:
    Base* b;
protected:
    virtual void foo(){/* Some implementation */};
    virtual void foo2()
    {
        // b->foo(); // doesn't work
        call_foo(b); // works
    }
};

这样,我们就不会破坏封装,因为设计者Base可以明确选择允许所有派生类相互调用foo,同时避免放入foo公共接口或明确将所有可能的子类Base变成朋友。

此外,无论是否foo是虚拟的,或者是私有的还是受保护的,此方法都有效。

是上面代码的运行版本的链接,这里是相同想法的另一个版本,具有更多的业务逻辑。

于 2016-10-24T10:19:32.923 回答
1

它有点脆弱,但是使用您在此处定义的类,这不起作用吗?

virtual void foo2() {
  reinterpret_cast<Derived *>(this->b)->foo(); 
}

reinterpret_cast 指向基础对象的 VTABLE,并通过此成员访问器调用它。

于 2013-09-10T09:09:58.117 回答
0

您使用范围运算符 (Base::foo()) 显式调用基本函数。但是在这种情况下,Base 类没有定义 foo(它是纯虚拟的),因此当您说this->b->foo();b 是指向 Base 而不是 Derived 的指针时,实际上没有要执行的函数。

于 2011-01-12T18:31:40.017 回答
0

您如何访问受保护的覆盖功能?

- - 从哪里?

您只能通过继承访问受保护的成员(同一类的方法除外)。比如说你有一个class Derived1继承自的Derived,然后Derived1可以调用的对象foo()

编辑:关于受保护的访问说明符的MSDN 文章。

于 2011-01-12T18:49:40.053 回答