以下是让我烦恼的代码示例:
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)
答案 0 :(得分:10)
基类中的受保护成员只能由当前对象访问
因此,您可以拨打this->foo()
,但不允许您拨打this->b->foo()
。这与Derived
是否为foo
提供实现无关。
这种限制背后的原因是,它可以很容易地规避受保护的访问。你只需创建一个像Derived
这样的类,突然你也可以访问外部人员无法访问的其他类的部分(如OtherDerived
)。
答案 1 :(得分:6)
通常,您可以使用Base::foo()
来执行此操作,{{1}}引用当前实例的基类。
但是,如果您的代码需要以您尝试的方式执行而且不允许,那么您需要将foo()设为public或使Derived成为Base的朋友。
答案 2 :(得分:2)
一种解决方案是在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
是否为虚拟,或者是私有还是受保护,此方法都有效。
答案 3 :(得分:1)
它有点脆弱,但是你在这里定义的类不会起作用吗?
virtual void foo2() {
reinterpret_cast<Derived *>(this->b)->foo();
}
reinterpret_cast指向基础对象的VTABLE,并通过此成员访问器调用它。
答案 4 :(得分:0)
使用范围运算符(Base :: foo())显式调用基函数。但是在这种情况下,Base类没有定义foo(它是纯虚拟的),所以当你说this->b->foo();
时实际上没有函数可以执行,因为b是指向Base而不是Derived的指针。
答案 5 :(得分:0)
您如何访问受保护的 压倒一切的功能?
---从哪里来?
您只能通过继承访问受保护的成员(除了同一个类的方法)。比方说,您有class Derived1
继承自Derived
,Derived1
的对象可以调用foo()
。
编辑:MSDN article关于受保护的访问说明符。