如何从派生类访问基类中的受保护方法?
这是令我烦恼的代码示例:
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' */
}
};
How do you access to protected overrided function?
感谢您的帮助。 :o)
Here is a sample of code that annoys me:
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' */
}
};
How do you access to the protected overrided function?
Thanks for your help. :o)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
一种解决方案是在
Base
中声明一个静态受保护函数,将调用重定向到私有/受保护函数(示例中的foo
)。可以这么说:
这样,我们就不会破坏封装,因为
Base
的设计者可以做出显式选择,允许所有派生类相互调用foo
,同时避免将foo
放入公共接口或显式地将Base
的所有可能子类转换为友元。此外,无论 foo 是否是虚拟的,或者是私有的还是受保护的,此方法都有效。
这里是上面代码的运行版本的链接,这里是同一想法的另一个版本,但有更多的业务逻辑。
One solution would be to declare a static protected function in
Base
that redirects the call to the private / protected function (foo
in the example).Lets say:
This way, we don't break encapsulation because the designer of
Base
can make an explicit choice to allow all derived classes to callfoo
on each other, while avoiding to putfoo
into the public interface or explicitly turning all possible subclasses ofBase
into friends.Also, this method works regardless of whether
foo
is virtual or not, or whether it is private or protected.Here is a link to a running version of the code above and here another version of the same idea with a little more business logic.
它有点脆弱,但是使用您在这里定义的类,这行不通吗?
reinterpret_cast 指向基础对象的 VTABLE,并通过此成员访问器调用它。
It's a bit fragile, but with the classes you defined here, won't this work?
The reinterpret_cast points at the VTABLE for the base object, and calls it through this members accessor.
您可以使用作用域运算符 (Base::foo()) 显式调用基函数。但在本例中,基类没有定义 foo (它是纯虚拟的),因此当您说
this->b->foo();
因为 b 时,实际上没有要执行的函数是指向 Base 而不是 Derived 的指针。You call base functions explicitly with the scope operator (Base::foo()). But in this case, the Base class doesn't define foo (it's pure virtual), so there's actually no function to execute when you say
this->b->foo();
since b is a pointer to Base and not Derived.- - 从哪里?
您只能通过继承来访问受保护的成员(同一类的方法除外)。举例来说,您有一个继承自
Derived1
的class Derived1
,那么Derived1
的对象可以调用foo()
。编辑:关于受保护访问说明符的 MSDN 文章。
--- from where?
You can access a protected member only via inheritance (apart from the methods of the same class). Say for example you have a
class Derived1
which inherits fromDerived
, then objects ofDerived1
can callfoo()
.EDIT: MSDN article on protected access specifier.
基类中的受保护成员只能由当前对象访问。
因此,您可以调用
this->foo()
,但不允许调用this->b->foo()
。这与Derived
是否提供foo
的实现无关。此限制背后的原因是否则很容易绕过受保护的访问。您只需创建一个像
Derived
这样的类,突然间您就可以访问其他类(例如OtherDerived
)的部分内容,而这些部分本来是外人无法访问的。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 callthis->b->foo()
. This is independent of whetherDerived
provides an implementation forfoo
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 (likeOtherDerived
) that were supposed to be inaccessible to outsiders.通常,您可以使用 Base::foo() 来完成此操作,它引用当前实例的基类。
但是,如果您的代码需要按照您尝试的方式执行此操作并且不允许这样做,那么您需要将 foo() 公开或将 Derived 设为 Base 的友元。
Normally, you would do it using
Base::foo()
, which refers to the base class of the current instance.However, if your code needs to do it the way you're trying to and it's not allowed, then you'll need to either make foo() public or make Derived a friend of Base.