С++ не позволит мне заводить друзей
У меня есть два класса: Mesh и MeshList. Я хочу, чтобы у MeshList была функция, которая может изменять частные члены Mesh. Но он не будет компилироваться, и я не знаю, почему. Вот мой код.
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)
Ответы
Ответ 1
Циклические зависимости объясняются в других ответах...
Вот решение:
В MeshList.h
:
- заменить
#include "Mesh.h"
на объявление вперед class Mesh;
(здесь вам не нужно включать сюда, потому что вы объявляете только указатель на Mesh)
В MeshList.cpp
:
- добавить
#include "Mesh.h"
к вашим включенным (вам нужно объявление, потому что вы используете Mesh)
Последняя ошибка компиляции, о которой вы говорили, является другой проблемой:
*mesh->vboHandle_ = 4;
mesh
является указателем. Ваш код выбирает элемент vboHandle_
и пытается разыменовать его (что не получается). Полагаю, вы имеете в виду:
mesh->vboHandle_ = 4; // <-- no leading asterisk
Ответ 2
Когда вы компилируете Mesh.cpp
, он включает Mesh.h
, который включает MeshList.h
, который начинает включать Mesh.h
, но останавливается раньше, потому что _MESH_H
теперь определен. Затем (обратно в MeshList.h
) есть ссылка на Mesh
- но это еще не объявлено. Следовательно, например, ваша ошибка C2143.
Ответ 3
Это потому, что вы #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
Некоторые (субъективные) рекомендации:
-
Включите материал в обратном порядке вашей способности изменить его, если он сломается, то есть: STL сначала, сторонние заголовки во-вторых, ваш собственный стек промежуточного программного обеспечения третий, текущий проект включает четвертый, а текущая библиотека - пятая. Таким образом, если есть конфликт, мы надеемся, что ошибка укажет на ваш заголовок.
-
Поместите материал public
перед тегом private
в классе. Клиенты класса относятся только к общему интерфейсу, не нужно, чтобы они пробирались через все детали грязной реализации, прежде чем они смогут добраться до него.