subtle C++ inheritance error with protected fields

后端 未结 6 905
無奈伤痛
無奈伤痛 2020-12-03 02:38

Below is a subtle example of accessing an instance\'s protected field x. B is a subclass of A so any variable of type B is also of type A. Why can B::foo() access b\'s x fie

相关标签:
6条回答
  • 2020-12-03 02:52

    Class B is not identical to class A. That's why members of class B cannot access non-public members of class A.

    On the other hand, class B derives publicly from class A, so class B now has a (protected) member x which any member of class B can access.

    0 讨论(0)
  • 2020-12-03 03:03

    In Public Inheritance:
    All Public members of the Base Class become Public Members of the derived class &
    All Protected members of the Base Class become Protected Members of the Derived Class.

    As per the above rule:
    protected member x from A becomes protected member of class B.

    class B can access its own protected members in its member function foo but it can only access members of A through which it was derived not all A classes.

    In this case, class B contains a A pointer a, It cannot access the protected members of this contained class.

    Why can the B::foo() access the members of the contained class B pointer b?

    The rule is:
    In C++ access control works on per-class basis, not on per-object basis.
    So an instance of class B will always have access to all the members of another instance of class B.

    An Code Sample, which demonstrates the rule:

    #include<iostream>
    
    class MyClass 
    {
        public: 
           MyClass (const std::string& data) : mData(data) 
           {
           }
    
           const std::string& getData(const MyClass &instance) const 
           {
              return instance.mData;
           }
    
        private:
          std::string mData;
    };
    
    int main() {
      MyClass a("Stack");
      MyClass b("Overflow");
    
      std::cout << "b via a = " << a.getData(b) << std::endl;
      return 0;
    }
    
    0 讨论(0)
  • 2020-12-03 03:05

    Since B is publicly inherited from A, A's protected member(s) become B's protected member(s), so B can access its protected members as usual from its member function(s). That is, the objects of B can access the protected members of B from its member functions.

    But A's protected members cannot be accessed outside the class, using object of type A.

    Here is the relevant text from the Standard (2003)

    11.5 Protected member access [class.protected]

    When a friend or a member function of a derived class references a protected nonstatic member function or protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11.102) Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5). If the access is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class).

    And the example follows from the Standard (2003) itself as:

    [Example:
    
    class B {
      protected:
      int i;
      static int j;
    };
    
    class D1 : public B {
    };
    
    class D2 : public B {
      friend void fr(B*,D1*,D2*);
      void mem(B*,D1*);
    };
    
    void fr(B* pb, D1* p1, D2* p2)
    {
      pb->i = 1; // ill-formed
      p1->i = 2; // ill-formed
      p2->i = 3; // OK (access through a D2)
      p2->B::i = 4; // OK (access through a D2, even though naming class is B)
      int B::* pmi_B = &B::i; // ill-formed
      int B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*)
      B::j = 5; // OK (because refers to static member)
      D2::j =6; // OK (because refers to static member)
    }
    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)
      int B::* pmi_B = &B::i; // ill-formed
      int B::* pmi_B2 = &D2::i; // OK
      j = 5; // OK (because j refers to static member)
      B::j = 6; // OK (because B::j refers to static member)
    }
    void g(B* pb, D1* p1, D2* p2)
    {
      pb->i = 1; // ill-formed
      p1->i = 2; // ill-formed
      p2->i = 3; // ill-formed
    }
    —end example]
    

    Note in the above example fr() is a friend function of D2, mem() is a member function of D2, and g() is neither a friend, nor a member function.

    0 讨论(0)
  • 2020-12-03 03:05

    Consider:

    class A {
    protected:
      int x;
    };
    
    class C : public A
    {
    };
    
    class B : public A {
    protected:
      unique_ptr<A> a;
    public:
      B() : a(new C) // a now points to an instance of "C"
      { }
    
      void foo() {
        int w = a->x;  // B accessing a protected member of a C? Oops.
      }
    };
    
    0 讨论(0)
  • 2020-12-03 03:12

    Why can B::foo() access b's x field, but not a's x field?

    A protected member can only be accessed by other members of the same class (or derived classes).

    b->x points to a protected member of an instance of class B (through inheritance), so B::foo() can access it.

    a->x points to a protected member of an instance of class A, so B::foo() cannot access it.

    0 讨论(0)
  • 2020-12-03 03:12

    Lets start with basic concept,

    class A {
    protected:
       int x;
    };
    
    class B : public A {
    public:
      void foo() {
        int u = x;     // OK : accessing inherited protected field
      }
    };
    

    Since child is inheriting parent, child gets x. Hence you can access x directly in foo() method of child. This is the concept of protected variables. You can access protected variables of parent in child directly. Note : Here I am saying you can access x directly but not through A's object! Whats the difference ? Since, x is protected, you cannot access A's protected objects outside A. Doesnt matter where it is - If its main or Child . That's why you are not able to access in the following way

    class B : public A {
    protected:
      A *a;
    public:
      void foo() {
        int u = x;     // OK : accessing inherited protected field x
        int w = a->x;  // ERROR : accessing a's protected field x
      }
    };
    

    Here comes an interesting concept. You can access a private variable of a class using its object with in the class!

    class dummy {
    private : 
    int x;
    public:
      void foo() {
        dummy *d;
        int y = d->x; // Even though x is private, still you can access x from object of d - But only with in this class. You cannot do the same outside the class. 
      }
    };
    

    //Same is for protected variables.Hence you are able to access the following example.

    class B : public A {
    protected:
      A *a;
      B *b;
    public:
      void foo() {
        int u = x;     // OK : accessing inherited protected field x
        int y = b->x;   // OK : accessing b's protected field x
        int w = a->x;  // ERROR : accessing a's protected field x
      }
    };
    

    Hope it explains :)

    C++ is complete Object Oriented Programming, where as Java is pure Object oriented :)

    0 讨论(0)
提交回复
热议问题