Почему к защищенному участнику суперкласса нельзя получить доступ в функции подкласса при передаче как аргумент?

Я получаю ошибку компиляции, которой я немного смущен. Это находится на VS2003.

ошибка C2248: 'A:: y': не может получить доступ к защищенному участнику, объявленному в классе

class A
{
public:
  A() : x(0), y(0) {}
protected:
  int x;
  int y;
};

class B : public A
{
public:
  B() : A(), z(0) {}
  B(const A& item) : A(), z(1) { x = item.y;}
private:
  int z;
};

Проблема с x = item.y;

Доступ указан, как защищено. Почему не делает конструктора класса B, имеют доступ к A:: y?

13
задан Chris Bednarski 1 April 2010 в 03:18
поделиться

3 ответа

Это из-за этого:

class base_class
{
protected:
    virtual void foo() { std::cout << "base::foo()" << std::endl; }
};

class A : public base_class
{
protected:
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
};

class B : public base_class
{
protected:
    virtual void foo() { std::cout << "B::foo()" << std::endl; }

public:
    void bar(base_class *b) { b->foo(); }
};

Если бы это было законно, вы могли бы сделать это:

A a;
B b;
b.bar(&a);

И вы бы назвали защищенным членом A из B, что не разрешено.

5
ответ дан 2 December 2019 в 01:31
поделиться

Документация IBM лучше всего описывает это:

Член защищенного нестатического базового класса может быть доступен членам и друзьям любых классов, производных от этого базового класса, с помощью одно из следующих :

  • Указатель на прямо или косвенно производный класс
  • Ссылка на прямо или косвенно производный класс
  • Объект прямо или косвенно производного класса

Таким образом , используя приведенный выше пример в качестве основы:

B::B(const A& item) : A(), z(1) {
  // NOT OK because `item` is not a reference to the derived class B
  //int i = item.y; 

  // OK because `item` reinterpreted as a reference to the derived class B
  // Do not do this (bad!) -- for illustrative purposes only
  int i = reinterpret_cast< const B& >(item).y;

  // OK because it is equivalent to `this->x = i`,
  //  where `this` is a pointer to the derived class B
  x = i;
}
1
ответ дан 2 December 2019 в 01:31
поделиться

Другие ответы объясняют причину, по которой ваш объект B не может получить доступ к защищенным частям A в вашем Например, даже если B 'is-a' A . Конечно, самый простой способ решить эту проблему - сделать части A, к которым вы хотите получить доступ, общедоступными` или иметь общедоступные методы доступа.

Однако вы можете решить, что это неуместно (или вы не можете контролировать определение A ). Вот несколько советов, которые помогут вам обойти проблему в возрастающем порядке подрыва контроля доступа A . Обратите внимание, что все эти обходные пути предполагают, что класс A является копируемым.

В первом случае вы просто используете конструктор копирования для A , чтобы установить начальное состояние для этой части объекта B , а затем исправить его позже:

class B1 : public A
{
public:
  B1() : A(), z(0) {}
  B1(const A& item) : A(item), z(1) {
    // fix up the A sub-object that was copy constructed 
    //  not quite the way we wanted
    x = y;
    y = 0;
  }
private:
  int z;
};

Я нахожу это невероятно запутанным и, вероятно, очень подверженным ошибкам (при условии, что мы хотим, чтобы подобъект A в объекте B отличался от объекта A передается в конструктор - необычная ситуация, но это то, что было задано в задаче). Однако тот факт, что это можно сделать, дает некоторое оправдание для более разрушительных примеров, которые следуют ...

В следующем примере создается временный объект B , который имеет точную копию A объект, к которому мы хотим получить доступ. Затем мы можем использовать временный объект B , чтобы добраться до элементов, которые были защищены:

class B2 : public A
{
public:
  B2() : A(), z(0) {}
  B2(const A& item) : A(), z(1) {
    // create a special-use B2  object that can get to the 
    //  parts of the A object we want access to
    B2 tmp( item, internal_use_only);

    x = tmp.y;  // OK since tmp is of type B
  }

private:
  int z;

  // create a type that only B2 can use as a 
  //    'marker' to call a special constructor 
  //    whose only purpose in life is to create
  //    a B object with an exact copy of another
  //    A sub-object in it
  enum internal_use {
    internal_use_only
  };
  B2( const A& item, internal_use marker) : A(item), z(0) {};
};

Я считаю, что это решение немного менее запутанно, чем первое, но оно все еще сбивает с толку (на мой взгляд). Странно иметь ублюдочную версию объекта B только для того, чтобы добраться до тех частей объекта A, которые нам нужны.

Мы можем что-то сделать с этим, создав специальный прокси для объектов A , который дает нам нужный доступ. Обратите внимание, что это «самый разрушительный» обходной путь, потому что это то, что может сделать любой класс, чтобы добраться до защищенных частей A , даже если они сами не являются подклассами A . .В случае класса B существует некоторая правомерность доступа к защищенным частям объектов A , поскольку B - это A ], и, как мы уже видели, существуют обходные пути, которые позволяют нам получить доступ, использующий только права, которые уже есть у класса B , поэтому я считаю это более чистой версией этих обходных путей в class B .

class B3 : public A
{
public:
  B3() : A(), z(0) {}
  B3(const A& item) : A(), z(1) { 
    // a special proxy for A objects that lets us
    //  get to the parts of A we're interested in
    A_proxy tmp( item);
    x = tmp.get_y();
  }

private:
  int z;

    class A_proxy : public A
    {
    public:
        A_proxy( const A& other) : A(other) {};
        int get_x() {return x;};
        int get_y() {return y;};
    };

};
3
ответ дан 2 December 2019 в 01:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: