【问题标题】:Why can a derived class not access a protected member of its base class through a pointer to base?为什么派生类不能通过指向基类的指针访问其基类的受保护成员?
【发布时间】:2016-12-07 15:09:48
【问题描述】:

这是code:

class TestA
{
protected:
    int test=12;

public:
    TestA() {
        cout << "test a: " << test << endl;
    }
    ~TestA() {
    }
};

class TestB : public TestA
{   
public:
    TestB(TestA *testA) {
        cout << "test b: " << testA->test;
    }
    ~TestB() {
    }
};

int main ()
{
    TestA *pTestA=new TestA();
    TestB *pTestB=new TestB(pTestA);
}

我正在尝试使用指向TestA 类型对象的指针访问protected 成员(因此,TestA 的实例)。 TestB也派生自TestA

为什么我无法访问它?它是否只能在我需要的类“内”访问?不在使用指针/直接声明之外?

【问题讨论】:

  • 我重新打开这个问题,因为这里提到的答案比旧的副本更好:accessing a protected member of a base class in another subclass。关闭另一个。
  • 简短回答:因为标准规定这是禁止的。因此,符合标准的编译器将对其抛出错误。 YMMV,但我实际上将其称为标准中的错误。
  • @cmaster (请参阅我的答案中的示例代码)如果允许,则可以通过 B* 类型的指针访问受保护的成员,该指针指向成员函数中 D1 的实例的D2。但D1 和D2 实际上是无关紧要的。这似乎违反直觉。

标签: c++ inheritance scope protected


【解决方案1】:

当public从基类继承时,它的protected成员成为派生类的protect成员,可以在派生类的成员函数中访问。但只能通过派生类本身(及其派生类)访问,不能通过基类访问。所以你不能通过TestA的指针访问成员test,但是通过TestB的指针访问就可以了。

该标准为此提供了一些说明性示例。 [class.protected]/1:

(只保留部分示例代码)

在前面的条款中描述的额外访问检查 [class.access] 应用于非静态数据成员或非静态 成员函数是其命名类的受保护成员 ([class.access.base])114 如前所述,访问受保护的 member 被授予,因为引用发生在朋友或成员中 某个类的C。如果访问是形成一个指向成员的指针 ([expr.unary.op]),嵌套名称说明符应表示 C 或类 派生自 C。所有其他访问都涉及(可能是隐式的) 对象表达式([expr.ref])。在这种情况下,对象的类 表达式应为 C 或从 C 派生的类。 [ 示例:

class B {
protected:
  int i;
};

class D1 : public B {
};

class D2 : public B {
  void mem(B*,D1*);
};

void D2::mem(B* pb, D1* p1) {
  pb->i = 1;                    // ill-formed
  p1->i = 2;                    // ill-formed
  i = 3;                        // OK (access through this)
  B::i = 4;                     // OK (access through this, qualification ignored)
}

—结束示例]

我不确定您的设计意图,让TestB 成为TestA 的朋友将是一个简单的解决方案。

【讨论】:

  • 这是(对我而言)难以证明的访问规则之一。
  • 顺便说一句,“当 public 从基类继承时,它的受保护成员成为派生类的保护成员”:受保护的继承也不是这样吗?甚至是私人的?
  • @PeterA.Schneider 对于protected inheritance 也是如此,对于private inheritance,将是“其受保护的成员成为派生类的私有成员”。
【解决方案2】:

WORLD 类成员可访问性的概念在这里适用。 WORLD 只能访问类的公共成员,无论它们是如何创建/派生的。

考虑下面的例子:

class A
{
    public:
        int public_i;
    protected:
        int protected_i;
    private:
        int private_i;

    public:
        A()
        {
            public_i = 10;
            protected_i = 20;
            private_i = 30;
        }
};

class C : protected A
{
    public:
        void Access(void)
        {
            cout << public_i << endl;
            cout << protected_i << endl;
            //cout << private_i << endl; // <- Not Allowed b'coz its private here
        }
};
class D : private A
{
    public:
        void Access(void)
        {
            cout << public_i << endl;
            cout << protected_i << endl;
            //cout << private_i << endl; // <- Not Allowed b'coz its private here
        }
};
class B : public A
{
    public:
        void Access(D *pd)
        {
            cout << public_i << endl;
            cout << protected_i << endl;
            //cout << private_i << endl; // <- Not Allowed b'coz its private here

            //pd is WORLD here
            //cout << pd->public_i << endl;    // <- Not Allowed b'coz its private here since private inheritance of A by D
            //cout << pd->protected_i << endl; // <- Not Allowed b'coz its protected here
            //cout << pd->private_i << endl; // <- Not Allowed b'coz its private here
        }
};


int main ()
{
    A objA;
    cout << objA.public_i << endl;
    //cout << objA.protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << objA.private_i << endl;   // <- Not Allowed b'coz its private here

    B objB;
    cout << objB.public_i << endl;
    //cout << objB.protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << objB.private_i << endl;   // <- Not Allowed b'coz its private here

    C objC;
    //cout << objC.public_i << endl;    // <- Not Allowed b'coz its protected here
    //cout << objC.protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << objC.private_i << endl;   // <- Not Allowed b'coz its private here

    D objD;
    //cout << objD.public_i << endl;    // <- Not Allowed b'coz its private here
    //cout << objD.protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << objD.private_i << endl;   // <- Not Allowed b'coz its private here

    //Outside class its all WORLD and WORLD can access only public members.
    //Objects and Pointers are WORLD.

    //Same thing is applicable when class members are accessed via pointers.
    B *pobjB;       //pobjB is WORLD
    cout << pobjB->public_i << endl;
    //cout << pobjB->protected_i << endl; // <- Not Allowed b'coz its protected here
    //cout << pobjB->private_i << endl;   // <- Not Allowed b'coz its private here

    objB.Access(&objD);
    objC.Access();
    objD.Access();

    return 0;
}

【讨论】:

    猜你喜欢
    • 2014-09-12
    • 2017-10-01
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 2016-07-31
    • 1970-01-01
    • 2011-01-27
    相关资源
    最近更新 更多