Почему я не могу объявить несколько классов - PullRequest
7 голосов
/ 04 февраля 2010

Я могу сделать это

extern int i;
extern int i;

Но я не могу сделать то же самое с классом

class A {
..
}
class A {
..
}

Хотя в обоих случаях память не выделяется.

Ответы [ 9 ]

24 голосов
/ 04 февраля 2010

Ниже приведены декларации :

extern int i;
class A;

И следующие два: определения :

int i;
class A { ... }

Правила таковы:

  • определение также является декларацией.
  • Вы должны «увидеть» декларацию предмета, прежде чем сможете его использовать.
  • повторное объявление в порядке (должно быть идентично).
  • Переопределение является ошибкой (Правило единого определения).
3 голосов
/ 04 февраля 2010

Ближайшим эквивалентом extern int i с классом является предварительное объявление, которое вы можете делать столько раз, сколько захотите:

class A;

class A;

class A;

class A{};

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

2 голосов
/ 04 февраля 2010

Первый (внешний) указывает на существующую переменную. Таким образом, вы просто указываете переменную дважды.

Объявление класса придает значение типу (ваш класс: A). Вы пытаетесь дать два значения A. Это не имеет никакого смысла для вас и может только сбить с толку, поэтому компилятор защищает вас от этого.

Кстати, если вы поместите оба класса в разные пространства имен, вы можете дать им одно и то же имя.

1 голос
/ 04 февраля 2010

Вы можете объявлять класс и объект несколько раз, чего вы не можете сделать, это определить это более одного раза.

extern делает этообъявление, а не определение (потому что инициализатор отсутствует):

extern int a;

Тело делает ваше class определением, а не просто объявлением.Вы можете определить класс один раз.

1 голос
/ 04 февраля 2010

вы можете делать

class A;

так часто, как хотите, а затем в одном файле определить его с помощью

class A { ... }

Пример для этого:
classB.h:

class A;
class B { A *a; }

classA.h:

class B;
class A { B *b; }
0 голосов
/ 19 февраля 2010

Я немного подумал. Я понял, что класс не в типе данных, это средство для определения типа данных.

Так что в

extern int i;
extern int i;

int - это тип данных. Таким образом, мы повторно объявляем переменную, а не тип данных.

Но в

class A {...};
class A {...};

A - это тип данных. И мы переопределяем тип данных, что, конечно, недопустимо.

0 голосов
/ 05 февраля 2010

Это не имеет ничего общего с объявлениями против определений.Проблема заключается в типах и объектах.

extern int i;

сообщает программе, что объект типа int существует и имеет имя i.Поскольку это extern, для него не выделено хранилище здесь , но где-то еще, вероятно, в другой единице перевода, оно определено и для него выделено хранилище.

class A {
..
};

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

0 голосов
/ 04 февраля 2010

Полагаю, реальный вопрос в том, «почему вы хотите?». Иногда возникает ситуация, когда вы включаете заголовочный файл несколько раз в одну и ту же единицу перевода (файл .cpp). Если это так, вы должны использовать include guard , чтобы компилятор был доволен.

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

В обоих случаях 'extern int i;' ссылается на один и тот же объект (объявленный в другом месте), поэтому множественные объявления однозначны. Если вы написали:

extern int i;
extern float i;

Компилятор будет жаловаться на неоднозначность (потому что он не будет знать, какой переменной вы собираетесь манипулировать, если вы написали 'i = 0;'.

Повторяющиеся объявления классов дают возможность того, что объявления отличаются; Опять же, как компилятор узнает, какой из них использовать, когда он встречает 'Foo;'? Я предполагаю, что компилятор мог бы сравнить объявления классов и убедиться, что они на самом деле идентичны, но это будет очень много усилий, когда альтернативные решения (пространства имен, включают в себя охранники, переименование) намного проще (и, вероятно, меньше). сбивает с толку тех, кто в конечном итоге читает код).

0 голосов
/ 04 февраля 2010

Но в первом случае нет противоречия.

extern int i;
extern double i;

тоже не сработает. Поэтому, если вы создадите класс А для времен, было бы невозможно решить, кто такой А.

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