Подтвердить что ты не робот

Область перечисления в C vs С++

Почему значения enum доступны вне блока, в котором перечисление определено в C, но не в С++?

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

#include <stdio.h>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

/* Why is INT accessible here? */
int main()
{
    tu.type = INT;
    tu.integer = 100;
    return 0;
}

Он компилируется и отлично работает в C.

Но в С++ это не скомпилировано.

#include <iostream>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

/* Why is INT accessible here? */
int main()
{
    tu.type = INT;
    tu.integer = 100;
    return 0;
}

[Ошибка] 'INT' не был объявлен в этой области

Существуют ли правила перераспределения и области видимости в C и С++?

4b9b3361

Ответ 1

В C просто нет правила для области перечислений и структуры. Место, где вы определяете свое перечисление, не имеет никакого значения.

В С++ определите что-то внутри другого (например, enum в классе), сделайте это что-то другим.

Если вы хотите сделать свой enum global на С++, вам придется определить его вне вашего класса или получить доступ к вашему пути к структуре:

#include <iostream>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

int main()
{
    tu.type = mystruct::INT; // INT is not in global scope, I have to precise it.
    tu.integer = 100;
    return 0;
}

Примечание.. Это работает в этом примере, потому что вы используете struct, где по умолчанию все public. Быть осторожен; вы можете получить доступ к типу и значениям перечисления вне вашей структуры или вашего класса, только если перечисление находится в области public, как любое поле или функция.

Ответ 2

Основное отличие состоит в том, что напротив C, С++ имеет класс.

В C (6.2.1 Области идентификаторов)

4 Каждый другой идентификатор имеет область, определяемую размещением ее (в указателе или спецификаторе типа). Если декларатор или спецификатор типа, который объявляет идентификатор, появляется за пределами любого блок или список параметров, идентификатор имеет область действия, что завершается в конце единицы перевода.

Таким образом, в этой программе

#include <stdio.h>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

/* Why is INT accessible here? */
int main()
{
    tu.type = INT;
    tu.integer = 100;
    return 0;
}

Перечислители INT, FLOAT, STRING объявляются вне любой области блока и, следовательно, имеют область действия файла.

В С++ определена отдельная область видимости класса:

3.3.7 Область видимости класса

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

и

2 Имя члена класса должно использоваться только следующим образом:

- в рамках своего класса (как описано выше) или полученного класса (Раздел 10) из своего класса,

- после. оператор, применяемый к выражению типа его класс (5.2.5) или класс, полученный из его класса,

- после того, как оператор → , примененный к указателю на объект своего класса (5.2.5) или класс, полученный из его класса,

- после того, как оператор разрешения области видимости (5.1) применяется к имени его класс или класс, полученные из его класса.

Учтите, что (9.2 членов класса)

1... Члены класса являются членами данных, функциями-членами (9.3), вложенные типы и перечисления.

Таким образом, в этой программе

#include <iostream>
struct mystruct
{
    enum {INT, FLOAT, STRING} type;
    int integer;
    float floating_point;
} tu;

/* Why is INT accessible here? */
int main()
{
    tu.type = INT;  // Invalid access of class member
    tu.integer = 100;
    return 0;
}

Вы должны получить доступ к члену класса INT одним из следующих способов.

    tu.type = mystruct::INT;

или

    tu.type = tu.INT;

или даже как

    tu.type = ( &tu )->INT;

Ответ 3

Ответы Влада и Арахтера хороши, насколько они идут, но есть вопрос, на который они не обращаются: почему С++ делает это по-другому. Если кто-то знаком с книгой Страуступа, они могут улучшить это, но я полагаю:

  • C был разработан давно, его довольно легко скомпилировать, в то время как С++ нацелен на то, чтобы сделать программирование более надежным, используя OO, основным идеалом которого является "в одном месте", сказать пользователю о конструкции, которую они должны знать, чтобы использовать ее и не более "; это имеет часто невысказанное преимущество объединения того, что принадлежит вместе.
  • Это приводит к решениям использовать определения типов для ограничения объема некоторых определений и размещения конструкций в иерархии пространств имен.
  • Ограничивая область вложенного перечисления, можно использовать короткие имена без риска двусмысленности или столкновений.