C ++ наследование: область видимости и видимость членов - PullRequest
5 голосов
/ 13 июня 2010

Можете ли вы объяснить, почему это не разрешено,

#include <stdio.h>

class B {
private:
    int a;
public:
    int a;
};

int main() {
    return 0;
}

, хотя это так?

#include <stdio.h>

class A {
public:
    int a;
};

class B : public A{
private:
    int a;
};

int main() {
    return 0;
}

В обоих случаях у нас есть одна открытая и одна закрытая переменная с именем a in class B.


отредактировано сейчас!

Ответы [ 4 ]

15 голосов
/ 13 июня 2010

В обоих случаях у нас есть одна открытая и одна закрытая переменная с именем a в классе B.

Нет, это не так.

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

b.a = 10; // Error. You can't access a private member.
b.A::a = 10; // OK.
3 голосов
/ 13 июня 2010

Потому что B::a скрывает A::a во втором примере. Вы по-прежнему можете получить к нему доступ, но для компилятора ему нужна явная квалификация, чтобы понять, что вы запрашиваете член родительского класса с тем же именем.

В первом примере оба a находятся в одной и той же области видимости, а во втором примере области видимости разные.

0 голосов
/ 13 июня 2010

Класс B в первом примере недопустим, поскольку C ++ не может различать членов по их спецификаторам доступа (общедоступный / частный / защищенный) Тем не менее, пространства имен позволяют C ++ различать членов. В классе B во втором коде у вас нет «public a» и «private a», у вас есть B::a и A::a.

Даже если было разрешено объявлять членов с одним и тем же именем / подписью с разными спецификаторами доступа, невозможно было бы обратиться к правильному члену.

0 голосов
/ 13 июня 2010

Первое не разрешено, потому что оно приводит к неоднозначным определениям. Во втором случае, хотя у вас есть и открытая, и приватная целочисленная переменная a, вы скрыли A :: a внутри своего класса B. Компилятор неявно знает, что вы хотите, потому что есть способ явного доступа к скрытым переменным.

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

Самый простой способ проиллюстрировать, почему одно разрешено, а другое - нет, это посмотреть, как компилятор скомпилирует функцию-член, использующую каждую переменную.

Внутри вашего класса b:

class b {

int a;
public:
int a;

void myMethod()
{
 a = 10; //what a should the compiler use? Ambiguous, so the compiler sez BZZT.
}

}

Для 2-го примера:

class A
{
public: 
int a;
}

class B: public A
{
private:
int a;

void someMethod()
{
 a = 10; //implied that you are using B::a (which may be a programmer error)

}

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