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

时间:2011-08-08 18:29:58

标签: c++ inheritance protected

以下是访问实例的受保护字段x的一个微妙示例。 B是A的子类,因此类型B的任何变量也是A类。 为什么B :: foo()可以访问b的x字段,但不能访问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
  }
};

这是我用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

6 个答案:

答案 0 :(得分:25)

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

但是,使用A类型的对象,无法在课堂外访问受保护的成员。

以下是标准(2003)

的相关文字
  

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

     

当派生类的朋友或成员函数引用受保护的非静态成员函数或受保护的基类的非静态数据成员时,除了前面第11.102节中描述的那些之外,还应用访问检查。除非形成指向member(5.3.1),访问必须通过指向,引用或派生类本身的对象(或从该类派生的任何类)(5.2.5)。如果访问要形成指向成员的指针,则nested-name-specifier应命名派生类(或任何名称)   从该类派生的类)。

这个例子来自标准(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]

在上面的例子中注意fr()D2的朋友函数,mem()D2的成员函数,g()不是朋友,也不是会员职能。

答案 1 :(得分:12)

考虑一下:

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

答案 2 :(得分:3)

公共继承中:
基类的所有Public members成为派生类Public Members&amp;
基类的所有Protected members都成为Protected Members的{​​{1}}。

按照上述规则:
来自Derived Class的受保护成员x成为班级A的受保护成员。

B可以在其成员函数class B中访问自己的受保护成员,但它只能访问foo的成员,而A所有成员A课程。

在这种情况下,class B包含A指针a,它无法访问此包含类的受保护成员。

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

规则是:
在C ++中,访问控制基于每个类,而不是基于每个对象。
因此,class B的实例始终可以访问class B的另一个实例的所有成员。

代码示例,演示规则:

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

答案 3 :(得分:1)

  

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

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

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

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

答案 4 :(得分:0)

班级B与班级A不同。这就是为什么班级B的成员无法访问班级A的非公开成员。

另一方面,课程B 从课程A公开,因此课程B现在有一个(受保护的)成员x班级B的任何成员都可以访问。

答案 5 :(得分:0)

让我们从基本概念开始,

class A {
protected:
   int x;
};

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

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

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

这是一个有趣的概念。您可以在类中使用其对象访问类的私有变量!

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

//同样适用于受保护的变量。您可以访问以下示例。

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

希望它解释:)

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