Я получаю ошибку компиляции, которой я немного смущен. Это находится на 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?
Это из-за этого:
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, что не разрешено.
Документация 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;
}
Другие ответы объясняют причину, по которой ваш объект 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;};
};
};