тонкая ошибка наследования C ++ с защищенными полями - PullRequest
40 голосов
/ 08 августа 2011

Ниже приведен тонкий пример доступа к защищенному полю экземпляра x. B является подклассом A, поэтому любая переменная типа B также имеет тип A. Почему B :: foo () может получить доступ к x-полю b, а не к 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 ]

25 голосов
/ 08 августа 2011

Поскольку B публично наследуется от A, защищенный член (ы) A становится защищенным (и) членом (ами) B, поэтому B может получить доступ к своим защищенным элементам как обычно из своих функций (функций) члена. То есть объекты B могут обращаться к защищенным элементам B из его функций-членов.

Но защищенные члены A не могут быть доступны вне класса, используя объект типа A.

Вот соответствующий текст из Стандарта (2003)

11.5 Защищенный доступ к элементу [class.protected]

Когда друг или функция-член производного класса ссылается на защищенную нестатическую функцию-член или защищенный нестатический элемент данных базового класса, проверка доступа применяется в дополнение к тем, что описаны ранее в пункте 11.102) За исключением случаев, когда формируется указатель на член (5.3.1), доступ должен осуществляться через указатель, ссылку или объект самого производного класса (или любого класса, производного от этого класса) (5.2.5). Если доступ должен формировать указатель на член, спецификатор вложенного имени должен назвать производный класс (или любой другой класс, производный от этого класса).

А пример следует из самого Стандарта (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() не является ни другом, ни функцией-членом.

12 голосов
/ 08 августа 2011

Рассмотрим:

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.
  }
};
3 голосов
/ 08 августа 2011

In Public Inheritance :
Все Public members базового класса становятся Public Members производного класса &
Все Protected members базового класса становится Protected Members 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;
}
1 голос
/ 09 августа 2011

Почему B :: foo () может получить доступ к полю x х, но не к полю х?производные классы).

b->x указывает на защищенный член экземпляра класса B (посредством наследования), поэтому B::foo() может получить к нему доступ.

a->x указывает на защищенный член экземпляра класса A, поэтому B::foo() не может получить к нему доступ.

0 голосов
/ 06 сентября 2013

Давайте начнем с базовой концепции,

class A {
protected:
   int x;
};

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

Так как child наследует родителя, child получает x.Следовательно, вы можете получить доступ к x напрямую в методе foo () child.Это концепция защищенных переменных.Вы можете получить доступ к защищенным переменным parent в child напрямую.Примечание: здесь я говорю, что вы можете получить доступ к 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 чисто объектно-ориентированный:)

0 голосов
/ 08 августа 2011

Класс B не идентичен классу A.Вот почему члены класса B не могут получить доступ к закрытым членам класса A.

С другой стороны, класс B публично получает из класса A, поэтомукласс B теперь имеет (защищенный) член x, к которому имеет доступ любой член класса B.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...