派生类无法访问基类的受保护成员。

10

考虑以下例子

class base
{
protected :
    int x = 5;
    int(base::*g);
};
class derived :public base
{
    void declare_value();
    derived();
};
void derived:: declare_value()
{
    g = &base::x;
}
derived::derived()
    :base()
{}
据我所知,只有基类的友元和派生类能够访问基类的受保护成员,但在上述示例中,我收到以下错误消息:“Error C2248 'base::x': cannot access protected member declared in class",但当我添加以下行时:

根据我的了解,只有基类的朋友和派生类可以访问基类的受保护成员,但在上面的例子中,我得到了以下错误:"Error C2248 'base::x': cannot access protected member declared in class " 但是当我添加以下行:

friend class derived;

将它声明为友元后,我可以访问基类的成员,那我在声明派生类时有做错什么吗?


https://dev59.com/NUbRa4cB1Zd3GeqPzVeD?rq=1 这个问题解答了您的疑问吗?这非常相似。 - Sebastian Redl
3
为什么不直接使用 g = &x;? - Simion
@SebastianRedl,你链接的问题涉及在另一个实例上调用受保护的方法,这与此处情况并不完全相同。 - 463035818_is_not_a_number
@user463035818 虽然情况不同,但原因是一样的。你试图通过一个非本类访问路径来访问受保护的成员。这就是为什么songyuanyao的答案可行的原因。 - Sebastian Redl
显示剩余3条评论
2个回答

12

派生类只能通过派生类的上下文来访问基类的protected成员。换句话说,派生类不能通过基类访问protected成员。

当形成指向protected成员的指针时,必须在其声明中使用派生类:

struct Base {
 protected:
    int i;
};

struct Derived : Base {
    void f()
    {
//      int Base::* ptr = &Base::i;    // error: must name using Derived
        int Base::* ptr = &Derived::i; // okay
    }
};
你可以改变。
g = &base::x;

g = &derived::x;

@g463035818 g = &x;?不行。&x 的类型是 int*,无法被赋值给成员指针。实时演示 - songyuanyao
1
这是因为派生类只允许访问其自身类型的基类受保护成员。想象一个具有受保护成员的形状基类。如果正方形从它继承,我们不希望正方形访问圆形的受保护成员。(重点是,仅因为X继承自Base并不意味着X应该访问所有Base受保护成员,而仅限于实际由X类型对象使用的那些。)base::qualification不再处于派生类的上下文中,因此受保护的访问会阻止它。 - Chris Uzdavinis
似乎存在&(foo::x)&foo::x之间的差异,我之前并不知道(前者是int*,后者是指向int成员的指针)。 - 463035818_is_not_a_number
@user463035818 是的。对于这种情况,&(derived::x)&(x)&x是相同的。 - songyuanyao
@ChrisUzdavinis 我已经思考了一段时间,关于为什么派生类成员或友元只能通过派生对象访问基类的受保护成员。我不同意你的例子。我认为重点是,在类中设置protected意味着用户无法从类本身之外的任何地方访问它,即使是从派生类。请查看此答案。 (https://softwareengineering.stackexchange.com/questions/345312/why-is-accessing-virtual-protected-functions-of-a-base-class-not-allowed-through) - Rick
1
@Rick Protected 允许访问声明它的类及其派生类的成员(和友元)。不允许的是,如果 X 是一个带有受保护成员的基类,并且两个类 A 和 B 都从 X 派生。当查看类型为 A 的类时(因为它是自己的数据),A 只能看到 X 的受保护成员,而不能在类 B 中看到 X 的受保护成员,反之亦然。给定一个指向基类的指针,您不知道它实际上指向 A 还是 B,因此不允许 A 查看 B 的受保护数据(反之亦然)。 - Chris Uzdavinis

0

我的编译器告诉我需要为 base 添加非默认构造函数,因为该字段未初始化。

添加后:

base() : g(&base::x) {}

编译时没有出现问题。


2
这是有效的,因为你正在从base内部访问base::x,显然会有访问权限。 - Chris Uzdavinis
@ChrisUzdavinis 我没有删除任何行,问题中出现错误的那一行仍然存在,并且在没有错误的情况下编译。我只是通过添加构造函数来修复了其他错误。 - nvoigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接