Наследование C++: обзор и видимость участников

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

#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 в class B.


отредактированный теперь!

5
задан Donal Fellows 13 June 2010 в 19:54
поделиться

4 ответа

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

Нет, это неправда.

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

b.a = 10; // Error. You can't access a private member.
b.A::a = 10; // OK.
15
ответ дан 18 December 2019 в 09:05
поделиться

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

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

0
ответ дан 18 December 2019 в 09:05
поделиться

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

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

3
ответ дан 18 December 2019 в 09:05
поделиться

Первое недопустимо, поскольку приводит к неоднозначным определениям. Во втором случае, хотя у вас есть как общедоступная, так и частная 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)

}

}
0
ответ дан 18 December 2019 в 09:05
поделиться
Другие вопросы по тегам:

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