Функция базы друзей может получить доступ к дочерним данным - PullRequest
0 голосов
/ 09 сентября 2018
class Child;

class Base
{
    friend bool friendly(const Base&,const Child&) ;
    private:
        std::string name;
    public:
        Base() {}
};

class Child: public Base
{
    private:
        int number;

    public:
        Child() {}

};



bool friendly(const Base &base, const Child &child ) 
{

    return base.name== child.name;
}

Я не использовал другой тип. Я буквально передаю объекты Child и Base для вызова функции.

friend(Base(),Child());

Я не могу понять, почему Child может получить доступ к переменной name. При доступе к числовой переменной-члену: {child.number} с использованием дружественной функции компилятор генерирует ошибку компиляции «личные данные». Почему я не вижу эту ошибку с именем переменной. Они бывают разных типов!

П.С .: Я вижу, это довольно плохой дизайн. Я обеспокоен этим конкретным поведением C ++ 11.

Ответы [ 2 ]

0 голосов
/ 09 сентября 2018

Я думаю, что вы правы, что это поведение не особенно интуитивно, тем более что вы обычно не можете получить доступ к закрытым членам базового класса. Но это не должно быть ошибкой компиляции, так как этот случай на самом деле упоминается в стандарте ISO C ++ 14 (раздел 11.2.5, жирный шрифт, сделанный вами по-настоящему):

5) Если базовый класс доступен, можно неявно преобразовать указатель на производный класс в указатель на этот базовый класс класс (4.10, 4.11). [Примечание: из этого следует, что члены и друзья класса X могут неявно преобразовать X * в указатель на закрытый или защищенный непосредственный базовый класс X. - примечание конца] по классу, в котором член назван. Этот класс именования является классом, в котором имя члена посмотрел вверх и нашел. [Примечание: этот класс может быть явным, например, когда используется квалифицированный идентификатор, или неявным, например, когда используется оператор доступа к члену класса (5.2.5) (включая случаи, когда добавляется неявное «this->»). Если для именования члена используется оператор доступа к члену класса и квалифицированный идентификатор (как в p-> T :: m), класс, именующий члена, является классом, обозначенным спецификатором nested-name квалифицированного идентификатора (то есть T). - примечание конца] Член m доступен в точке R, если назван в классе N, если

(5.1) - m как член N является публичным, или

(5.2) - m в качестве члена N равно private, а R встречается у члена или друга класса N или

(5,3) - м поскольку член N защищен, а R встречается в члене или друге класса N или члена или друга класса P, полученного из N, где m как член P является публичным, частным или защищенным, или

(5,4) - есть существует базовый класс B из N, который доступен в R, и м доступный в R, когда назван в классе B

и следует приведенному выше blub с этим примером:

class B;
class A {
private:
    int i;
    friend void f(B*);
};
class B : public A { };
void f(B* p) {
    p->i = 1; // OK: B* can be implicitly converted to A*,
              // and f has access to i in A
}

Вы не используете указатели, но ссылки const также могут быть неявно преобразованы.

0 голосов
/ 09 сентября 2018

Я думаю, что это ожидаемо, поскольку friendly является другом класса Base, поэтому он может получить доступ к Base закрытым членам, включая name.

Здесь child.name все еще ссылается на Base приватного участника name. Но number отличается, что является частным только для child, и поэтому friendly не может получить доступ.

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