2010-02-04 25 views
7

я могу сделать этоПочему я не могу мульти-объявить класс

extern int i; 
extern int i; 

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

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

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

+0

Должны ли они быть двумя классами разностей? или частичный класс? – Naveen

+0

@all На самом деле я понимаю, что дифференцирующий факт между определением и декларацией - в памяти не выделяется память. Вот почему я считал класс А {..} скорее декларацией, чем определением. – deeJ

ответ

25

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

extern int i; 
class A; 

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

int i; 
class A { ... } 

Правила являются:

  • определение также является декларация ,
  • вы должны «увидеть» объявление элемента, прежде чем сможете его использовать.
  • повторное декларирование в порядке (должно быть идентичным).
  • re-definition - ошибка (правило определения).
+0

Ты сказал это лучше. Я снимаю свой ответ –

+3

Для чего это стоит, это называется Правилом одного определения. – GManNickG

+6

Вы можете добавить, что "class A;" Действительно, объявление класса A. – Klaim

2

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

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

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

0

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

extern int i; 
extern double i; 

также не будет работать. Итак, если вы создадите класс A во времена, было бы невозможно решить, кто такой A.

3

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

class A; 

class A; 

class A; 

class A{}; 

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

1

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

class A; 

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

class A { ... } 

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

class A; 
class B { A *a; } 

классA.ч:

class B; 
class A { B *b; } 
+0

Это не сработает: компилятору необходимо определить определение «B», чтобы определить размер «A». Однако указатели или ссылки будут работать нормально. –

+0

@roger: спасибо, исправлено. Знание C++ немного ржавое – dbemerlin

1

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

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

extern int a; 

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

+0

Точнее, extern - это ссылка. Может быть определение с extern, как extern int a = 7; –

+0

Да, но в этом случае более важным эффектом «extern» является тот факт, что он изменяет объявление, чтобы оно не было определением. –

0

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

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

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

extern int i; 
extern float i; 

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

декларации Дублирование класса приводит к возможности того, что объявления различны, еще раз, как компилятор узнает, какой из них использовать, когда он встречает «A foo»? Я думаю, что компилятор мог сравнить объявления классов и убедиться, что они инфакт идентичны, но это было бы очень много усилий, чтобы пойти, когда альтернативные решения (пространства имен, включая охранники, переименование) намного проще (и, вероятно, менее запутывают для тех, кто заканчивает чтение кода).

0

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

extern int i; 

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

class A { 
.. 
}; 

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

0

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

Так

extern int i; 
extern int i; 

междунар является типом данных. Поэтому мы повторно объявляем переменную, а не тип данных.

Но в

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

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

Смежные вопросы