2013-02-25 5 views
1

Я получаю сумасшедшие критические ошибки компилятора при попытке построить мое решение на VS2010. Мне очень трудно понять, как они работают.Заголовки C++ и файлы cpp - как я их справляюсь?

Game.cpp 
Game.h 
Deck.cpp 
Deck.h 
Card.h 

// Game.cpp 
#include "Game.h" 

Все в порядке. Теперь мне нужно, чтобы создать новую колоду:

// Game.h 
private: 
    static Deck _deck; 

Ну тогда мне нужно включить deck.h поэтому он знает, что это такое:

// Game.h 
#include "Deck.h" 
class Game { 
private: 
    Deck _deck; 
} 

Хорошо, то отлично. Но теперь мне нужно использовать _deck в Game.cpp

// Game.cpp 
#include "Game.h" 
Deck Game::_deck; 
void Shuffle(void) 
{ 
    _deck = Deck(); 
    _deck.Shuffle(); 
} 

Но я получаю сообщение об ошибке, что «Колода не определено». Но поскольку Game.cpp включает Game.h, если Game.h включает Deck.h?

Если добавить к deck.h Game.cpp я получаю:

"Uses undefinied class Deck Game.cpp" 

и

"Deck class redeclaration Deck.h" 

Я не понимаю, это вообще ...

+0

'# include' просто копирует и вставляет содержимое файла в текущий файл перед отправкой его в компилятор. –

+0

Будьте внимательны, чтобы не устанавливать взаимное включение между вашими заголовками. Разрыв зависимости с форвардными объявлениями. Возможно, [* this Q & A *] (http://stackoverflow.com/questions/14909997/why-arent-my-include-guards-preventing-recursive-inclusion-and-multiple-symbol/14909999#14909999) может помочь. –

ответ

1

У вас есть круглый круг. К счастью для вас, static член не требует полного определения при объявлении, так что вы можете включить в вашем Game.h с упреждающим объявлением:

// Game.h 
class Deck; 

//.... 
private: 
    static Deck _deck; 
1

#include является частью фазы препроцессора, который работает до вашего компилятор и в основном выполняет замену текста.

Опишите проблему, которую вы описываете в статье translation units. В основном вы можете думать, что исходный файл (.c, .cpp, .inl и т. Д.) Отличается от файла заголовка (.h, .hpp) тем фактом, что каждый исходный файл определяет блок перевода, который может компилировать действуют на. Исходный файл по существу состоит из всей логики в файле, плюс все из них включает в себя либо прямое, либо косвенное отношение.

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

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

Многие современные языки смешивают две концепции интерфейса и реализации и с мощью новых IDE, это не большая проблема.Тем не менее, я все еще оглядываюсь назад и ценю разделение на C++, поскольку этот подход гораздо более ясен. Клиент хорошо написанного класса должен иметь возможность игнорировать детали реализации, и, следовательно, заголовок - все, что им нужно, чтобы видеть, чтобы использовать класс. Когда вы имеете дело с библиотеками на C++, это часто бывает так, как вы можете иметь доступ только к файлам заголовков.

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

  • Нет связанных вопросов^_^