2012-04-27 3 views
29

У меня есть два класса, Mesh и MeshList. Я хочу, чтобы у MeshList была функция, которая может изменять частные члены Mesh. Но он не будет компилироваться, и я не знаю, почему. Вот мой код.C++ не позволит мне подружиться

Mesh.h

#ifndef _MESH_H 
#define _MESH_H 

#include "MeshList.h" 
#include <iostream> 

class Mesh 
{ 
private: 
    unsigned int vboHandle_; 
    friend void MeshList::UpdateVBOHandle(); 
public: 
    inline void Out() {std::cout << vboHandle_;} 
}; 
#endif 

Mesh.cpp

#include "Mesh.h" 

MeshList.h

#ifndef _MESH_LIST_H 
#define _MESH_LIST_H 

#include "Mesh.h" 


class MeshList 
{ 

public: 
    Mesh *mesh; //Line 11 Error 
    void UpdateVBOHandle(); 
}; 
#endif 

MeshList.cpp

#include "MeshList.h" 

void MeshList::UpdateVBOHandle() 
{ 
    *mesh->vboHandle_ = 4; 
} 

я получаю эти ошибки:

MeshList.h (линия 11)

  • ошибка C2143: синтаксическая ошибка: отсутствует ';' перед '*'
  • ошибка C4430: отсутствует спецификатор типа - int. Примечание: C++ не support default-int
  • ошибка C4430: спецификатор отсутствующего типа - предполагается int. Примечание: C++ не поддержка по умолчанию-ИНТ

  • mesh.h (11): ошибка C2653: 'MeshList': это не класс или пространство имен имя

  • meshlist.cpp (5): ошибка C2248 : 'Mesh :: vboHandle_': не может получить доступ к закрытый член объявлен в классе 'Mesh'
  • mesh.h (10): см декларирование 'Mesh :: vboHandle_'
  • mesh.h (8): см декларацию of 'Mesh'
  • meshlist.cpp (5): ошибка C2100: незаконное направление
+38

Вам нужно больше выйти. –

+32

+1 для названия в одиночку. –

+5

Попробуйте 'class Meshlist;' вместо '#include 'MeshList.h" ' – chris

ответ

6

Циклических зависимости объясняются в других ответах ...

Здесь приходит решение:

В MeshList.h:

  • заменить #include "Mesh.h" с упреждающим объявлением class Mesh; (Вы надеваете здесь не нужно включать сюда, потому что вы объявляете только указатель на сетку)

В MeshList.cpp:

  • добавить #include "Mesh.h" к вашему включает в себя (вам нужно заявление, потому что вы используете Mesh)

Последняя ошибка компиляции, вы упомянули еще одна проблема:

*mesh->vboHandle_ = 4; 

mesh - указатель. Ваш код выбирает член vboHandle_ и пытается разыменовать его (что не удается). Полагаю, вы имеете в виду:

mesh->vboHandle_ = 4; // <-- no leading asterisk 
+0

Исправлен ответ в соответствии с комментарием Дэвида. – Stephan

9

При компиляции Mesh.cpp, она включает в себя Mesh.h, который включает в себя MeshList.h, который начинает включать Mesh.h, но останавливается рано, потому что _MESH_H теперь определена. Затем (обратно в MeshList.h) есть ссылка на Mesh - но это еще не объявлено. Следовательно, например, ваша ошибка C2143.

+0

@ildjarn, это интересно, поскольку я никогда нигде не обнаружил. Могу я спросить, почему? – chris

+0

@chris: Вы должны спросить людей, которые разработали C++! – ildjarn

+0

@ildjarn: Вы уверены?На самом деле я совершенно уверен, что все наоборот. Я даже думаю, что помню, что стандарт утверждал, что подружиться с классом было равносильно поддержке всех его функций ... Мне нужно искать цитату, я думаю. –

6

Это потому, что вы #include "MeshList.h" в файле Mesh.h, поэтому файл MeshList.h будет составлен первым, а класс Mesh пока не объявлен. Для этого компилятор будет считать, что Mesh в строке ошибки - это имя переменной, у которой до этого нет типа, следовательно, ошибка.

Это пример создания функции в friend члена:

#include <iostream> 


class foo; 

class bar 
{ 
public: 
    void barfunc(foo &f); 
}; 

class foo 
{ 
private: 
    friend void bar::barfunc(foo &f); 
    int i; 
public: 
    foo() 
    { 
     i = 0; 
    } 
    void printi() 
    { 
     std::cout << i << '\n'; 
    } 
}; 

void bar::barfunc(foo &f) 
{ 
    f.i = 5; 
} 


int main() 
{ 
    foo f; 
    bar b; 
    b.barfunc(f); 
    f.printi(); 
    return 0; 
} 
4

Проблема: Циклические зависимости в включает. К сожалению, сообщение об ошибке является менее идеальным.


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

// Mesh.h 
#ifndef _MESH_H 
#define _MESH_H 

#include <iostream> 

class MeshList; 

class Mesh 
{ 
private: 
    unsigned int vboHandle_; 
    friend class MeshList; 
public: 
    inline void Out() {std::cout << vboHandle_;} 
}; 
#endif 

Некоторая (субъективная) рекомендация:

  • Включайте вещи в порядке, обратном порядке вашей способности изменить его, если он сломается, то есть: СТЛ первый, 3-й заголовков партии второй, ваш собственный промежуточный стек третьего, текущий проект включает четвертый, а текущая библиотека - пятая. Таким образом, если есть конфликт, мы надеемся, что ошибка укажет на ваш заголовок.

  • Поместите public материалам до private материала в классе. Клиенты класса относятся только к общему интерфейсу, не нужно, чтобы они пробирались через все детали грязной реализации, прежде чем они смогут добраться до него.

+0

Как я понимаю, вам не нужно форвардное объявление, если объявление вашего друга выше первого использования. (Я тестировал аналогичный пример w/o 'class MeshList;' в VS, и он работает.) – anxieux

+0

@anxieux: Я никогда не понимал полностью, в какой области было введено имя после 'friend class', если его не удалось найти; поэтому я привык к простому объявлению типа. Немного более подробный, возможно, но эй: он работает в 100% случаев! –

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