Ошибка «отсутствует спецификатор типа» при объявлении конструктора - PullRequest
5 голосов
/ 27 сентября 2010

У меня есть 2 класса в 2 разных файлах:

RegMatrix.h:

#ifndef _RM_H
#define _RM_H
#include "SparseMatrix.h"
...
class RegMatrix{
    ...
    RegMatrix(const SparseMatrix &s){...}   //ctor
    ...
};
#endif

SparseMatrix.h:

#ifndef _SM_H
#define _SM_H
#include "RegMatrix.h"
...
class SparseMatrix{
    ...
    SparseMatrix(const RegMatrix &r){...}   //ctor
    ...
};
#endif

На строках строки я получаю ошибки:

ошибка C4430: отсутствует указатель типа - предполагается int.

ошибка C2143: синтаксическая ошибка: отсутствует ',' before '&'

Но когда я добавляю объявления классов

class SparseMatrix;

в файле RegMatrix.h и

class RegMatrix;

в файле SparseMatrix.h работает нормально. Мой вопрос: зачем это нужно, если у меня есть включения? 10x.

Ответы [ 4 ]

10 голосов
/ 27 сентября 2010

Вы не можете иметь циклический #include (один файл #include другой, который #include первый файл). Объявление вперед одного из классов вместо #include разорвет цепочку и позволит ей работать. Объявление имени класса позволяет использовать имя без необходимости знать о внутренних битах класса.

Кстати, стремление к круглому #include - это дизайнерский запах. Возможно, вы могли бы создать интерфейс, от которого могут зависеть два класса? Тогда им не придется взаимно зависеть друг от друга.

5 голосов
/ 27 сентября 2010

Включение вашего заголовка не будет работать, посмотрите, что произойдет, если я включу SparseMatrix.h после разрешения включает:


#ifndef _SM_H
#define _SM_H
/// start of #include "RegMatrix.h"
#ifndef _RM_H
#define _RM_H
/// start of #include "SparseMatrix.h" inside "RegMatrix.h"
#ifndef _SM_H
// skipping, because _SM_H is defined and the condition is false
#endif
/// end of #include "SparseMatrix.h" inside "RegMatrix.h"

class RegMatrix{
    ...
    RegMatrix(const SparseMatrix &s){...}   //ctor
    ...
};
#endif


/// end of #include "RegMatrix.h"
...
class SparseMatrix{
    ...
    SparseMatrix(const RegMatrix &r){...}   //ctor
    ...
};
#endif

Так что в основном SparseMatrix не определен. Вы ничего не можете с этим поделать. Просто объявите форвардную декларацию вашего класса.

3 голосов
/ 27 сентября 2010

Заявления типа

class SparseMatrix;

называются предварительными декларациями.Он сообщает компилятору, что «где-то» существует класс с таким именем.Это делает компилятор счастливым и прекрасно работает до тех пор, пока файл прямого объявления использует либо указатель, либо ссылку на класс прямой ссылки.Это потому, что, с точки зрения компилятора, указатели или ссылки занимают всего 4 байта независимо от содержимого класса.

В коде OP обе SparseMatrix и RegMatrix используются только как (const) ссылки, поэтомупредварительного объявления достаточно, чтобы оно заработало.

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

void foo( SparseMatrix );  // note pass by value

, то компилятор будет жаловаться:)

В конкретной ситуации, создаваемой OP, я предпочитаю отказаться от общего #include в целом и спроектировать интерфейс только на основе предварительных объявлений.Реализация (т.е. файлы .cpp) может включать оба заголовочных файла, но это не проблема.

3 голосов
/ 27 сентября 2010

Если вы включите сначала RegMatrix.h, оно будет включать SparseMatrix.h.Затем вернемся к включению RegMatrix.h и пропустим, потому что защита заголовка определена.Затем SparseMatrix продолжает определяться, за исключением того, что RegMatrix даже не был объявлен.Тогда вы получите ошибку.

У вас не может быть циклических включений.Вы должны заранее объявить одного или обоих из них, как вы сделали.

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