带有受保护字段的微妙 C++ 继承错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6986798/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 21:04:57  来源:igfitidea点击:

subtle C++ inheritance error with protected fields

c++inheritanceprotected

提问by wcochran

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 field, but not a's x field?

下面是一个访问实例的受保护字段 x 的微妙示例。B 是 A 的子类,所以任何类型 B 的变量也是类型 A。为什么 B::foo() 可以访问 b 的 x 字段,而不是 a 的 x 字段?

class A {
protected:
  int x;
};

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

Here is the error I get with g++

这是我用 g++ 得到的错误

$ g++ -c A.cpp
A.cpp: In member function ‘void B::foo()':
A.cpp:3: error: ‘int A::x' is protected
A.cpp:14: error: within this context

回答by Nawaz

Since Bis 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 Bcan access the protected members of Bfrom its member functions.

由于B是从 公开继承的A,A 的受保护成员成为 B 的受保护成员,因此 B 可以像往常一样从其成员函数访问其受保护成员。也就是说, 的对象B可以B从其成员函数访问受保护的成员。

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

但是 A 的受保护成员不能在类外使用类型的对象访问A

Here is the relevant text from the Standard (2003)

这是标准(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).

11.5 受保护的成员访问 [class.protected]

当派生类的友元或成员函数引用基类的受保护非静态成员函数或受保护非静态数据成员时,除了在第 11.102 节中描述的那些之外,还应用访问检查,除非形成指向成员的指针 (5.3 .1),必须通过派生类本身(或从该类派生的任何类)的指针、引用或对象进行访问(5.2.5)。如果访问要形成一个指向成员的指针,则嵌套名称说明符应命名派生类(或从该类派生的任何类)。

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

这个例子来自标准(2003)本身:

[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.

注意上例中fr()是 的友元函数D2mem()是 的成员函数D2g()既不是友元函数,也不是成员函数。

回答by Billy ONeal

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.
  }
};

回答by Alok Save

In Public Inheritance:
All Public membersof the Base Classbecome Public Membersof the derived class&
All Protected membersof the Base Classbecome Protected Membersof the Derived Class.

公有继承
所有Public members的的基类成为Public Members了的派生类
所有Protected members的的基类成为Protected MembersDerived Class

As per the above rule:
protected member xfrom Abecomes protected member of class B.

根据上述规则:
受保护的成员xfromA成为受保护的成员 class B

class Bcan access its own protected members in its member function foobut it can only access members of Athrough which it was derived not all Aclasses.

class B可以在其成员函数中访问它自己的受保护成员,foo它只能访问A派生它的成员,而不是所有A类。

In this case, class Bcontains a Apointer a, It cannot access the protected members of this contained class.

在这种情况下,class B包含一个A指针a,它不能访问这个包含类的受保护成员。

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

为什么可以B::foo()访问包含class B指针的成员b

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

规则是:
在 C++ 中,访问控制基于每个类,而不是基于每个对象。
因此, 的实例class B将始终可以访问 的另一个实例的所有成员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;
}

回答by firyice

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

为什么 B::foo() 可以访问 b 的 x 字段,而不能访问 a 的 x 字段?

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

受保护的成员只能被同一类(或派生类)的其他成员访问。

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

b->x指向类 B 实例的受保护成员(通过继承),因此B::foo()可以访问它。

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

a->x指向类 A 实例的受保护成员,因此B::foo()无法访问它。

回答by mac

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

由于孩子继承父母,孩子得到x。因此,您可以直接在 child 的 foo() 方法中访问 x。这就是受保护变量的概念。您可以直接访问 child 中 parent 的 protected 变量。注意:这里我是说您可以直接访问 x 但不能通过 A 的对象访问!有什么不同 ?由于 x 受保护,因此您无法访问 A 之外的 A 受保护对象。无论它在哪里 - 如果它的 main 或 Child 。这就是您无法通过以下方式访问的原因

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 :)

C++ 是完整的面向对象编程,而 Java 是纯面向对象的 :)

回答by Kerrek SB

Class Bis not identical to class A. That's why members of class Bcannot access non-public members of class A.

ClassB与 class 不同A。这就是为什么 class 的成员B不能访问class 的非公共成员A

On the other hand, class Bderivespublicly from class A, so class Bnow has a (protected) member xwhich any member of class Bcan access.

另一方面, class从 class 公开B派生A,因此 classB现在有一个(受保护的)成员x, class 的任何成员都B可以访问该成员。