Видимость членов класса? - PullRequest
7 голосов
/ 02 января 2012

Я думаю, что я знаю о доступности, но я не уверен, что я очень четко понимаю видимость

Например:

class X
{
   int x;
};

Здесь 'x' виден только вкласс и но доступны за пределами класса.Если я прав, может ли кто-нибудь объяснить текст в этом ответе о том, как не контролируется видимость и т. Д.?

(C ++ 03 / 11.0) Это должно бытьотметил, что контролируется доступ к членам и базовым классам, а не их видимость.Имена членов по-прежнему видны, и неявные преобразования в базовые классы все еще рассматриваются, когда эти члены и базовые классы недоступны.Интерпретация данной конструкции устанавливается без учета контроля доступа.Если в установленной интерпретации используются недоступные имена членов или базовые классы, конструкция является некорректной.

Ответы [ 3 ]

7 голосов
/ 02 января 2012

C ++ имеет некоторую эзотерическую особенность относительно видимости и доступности имен членов частного класса. По определению, личное имя участника класса доступно только участникам класса и друзьям. Однако правило видимости может смутить многих. Их можно суммировать следующим образом.

  1. Имя частного участника доступно только другим пользователям и друзьям.
  2. Закрытый член виден всему коду, который видит определение класса. Это означает, что его типы параметров должны быть объявлены, даже если они никогда не понадобятся в этом модуле перевода ...
  3. Разрешение перегрузки происходит перед проверкой доступности.

В C ++ сегодня («C ++ 03» и более ранние варианты) понятия доступности и видимости независимый. Члены классов и пространств имен видны, когда они находятся в "и" нет механизма, чтобы уменьшить эту видимость с точки зрения декларации. Доступность является только параметром для членов класса и ортогональна понятию видимость. Последнее наблюдение часто удивляет начинающих программистов на C ++. Посмотреть это PDF .

Рассмотрим следующий пример.

#include < complex>

class Calc 
{ 
    public: 
        double Twice( double d ); 
    private: 
        int Twice( int i ); 
        std::complex Twice( std::complex c ); 
};

int main() 
{ 
    Calc c; 
    return c.Twice( 21 ); // error, Twice is inaccessible 
}    

Когда компилятор должен разрешить вызов функции, он выполняет три основных действия по порядку:

  • Прежде чем делать что-либо еще, компилятор ищет область, которая имеет по крайней мере один объект по имени Дважды и составляет список кандидатов. В этом случае поиск имени сначала просматривается в области Calc, чтобы увидеть, есть по крайней мере одна функция с именем Twice; если нет, база классы и окружающие пространства имен будут рассматриваться по очереди, по одному время, пока не будет найдена область, имеющая хотя бы одного кандидата. В этом В этом случае самая первая область видимости компилятора уже имеет сущность по имени Дважды - на самом деле, у нее есть три из них, и поэтому трио становится набором кандидатов. (Для получения дополнительной информации об имени поиск в C ++, с обсуждением того, как это влияет на то, как вы следует упаковать ваши классы и их интерфейсы

  • Затем компилятор выполняет разрешение перегрузки, чтобы выбрать уникальный лучший матч из списка кандидатов. В этом случае аргумент 21, что является целым числом, а доступные перегрузки принимают двойное, Int и комплекс. Понятно, что параметр int является лучшим аргумент int (это точное совпадение, и никаких преобразований требуется), и поэтому выбирается дважды (int).

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

Обратите внимание, что доступность (определяется модификаторами в C ++) и видимость независимы. Видимость основана на правилах области видимости C ++. Член класса может быть видимым и недоступным одновременно.

Статические члены в качестве примера видимы глобально во время работы вашего приложения, но доступны только в отношении примененного к ним модификатора.

7 голосов
/ 02 января 2012

Возможно, этот пример помогает:

class Bob
{
private:
    int foo(int, int);
};

class David : Bob
{
    void goo() {
        int a = foo(1, 2);  // #1
    }
};

class Dani : Bob
{
     void foo();
     void goo() {
         int a = foo(1, 2); // #2
     }   
};

В строке # 1 имя foo равно видимое , но имя, которое оно называет, не доступное (из-за принадлежности к Bob).Это ошибка компиляции, но компилятор знает, что существует потенциальная функция Bob::foo, которая будет соответствовать, но недоступна.

В строке # 2 имя foo относится только к Dani::foo, в то время как Bob::foo является невидимым (потому что оно скрыто ), и поэтому просто нет соответствующей функции для вызова foo(1, 2).Это также ошибка компиляции, но на этот раз ошибка заключается в том, что для вызова вообще не существует соответствующей функции.

1 голос
/ 02 января 2012

Как примечание: когда вы объявляете class, область действия по умолчанию является закрытой (в отличие от struct, где члены по умолчанию являются открытыми.)

Элемент переменной 'x' имеет значение толькодоступны для вашего класса и его друзей.Никто другой никогда не сможет получить доступ к 'x' напрямую (косвенно, если у вас есть функция, возвращающая ссылку на него, что является очень плохой идеей).

Текст, который вы цитировали, говорит о видимости для компилятора,так что X::x существует, несмотря ни на что. не исчезнет только потому, что это личное.Видимость используется для поиска члена, на которого вы ссылаетесь, и возвращается первое соответствующее значение.В этот момент компилятор проверяет доступность, если она доступна, у вас все хорошо.Если нет, то это плохо сформирован .

Обратите внимание, что я упомянул друзей.Это ключевое слово делает доступными все переменные элементы.Когда компилятор работает с друзьями, он полностью игнорирует все защищенные и закрытые ключевые слова.

В большинстве случаев это очень простой процесс.Это идет в порядке.Точка.

Когда это становится более сложным, когда вы начинаете использовать виртуальные функции: они могут быть общедоступными, защищенными и частными, и это может измениться в зависимости от объявления класса ... (A происходит от B и делаетзащищенная виртуальная функция public; обычно это не очень хорошая идея, но C ++ не мешает вам делать это.) Конечно, это относится только к функциям, а не к переменным элементам, так что это другая тема.

...