Подтвердить что ты не робот

С++ не позволит мне заводить друзей

У меня есть два класса: 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)

  • ошибка C2143: синтаксическая ошибка: отсутствует ';' до '*'
  • ошибка C4430: отсутствует спецификатор типа - int. Примечание: С++ не поддержка default-int
  • ошибка C4430: отсутствует спецификатор типа - int. Примечание: С++ не поддержка default-int

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

  • meshlist.cpp(5): ошибка C2248: "Mesh:: vboHandle_": невозможно получить доступ закрытый член объявлен в классе "Mesh"
  • mesh.h(10): см. объявление "Mesh:: vboHandle _"
  • mesh.h(8): см. объявление "Mesh"
  • meshlist.cpp(5): ошибка C2100: незаконное косвенное обозначение
4b9b3361

Ответ 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 в классе. Клиенты класса относятся только к общему интерфейсу, не нужно, чтобы они пробирались через все детали грязной реализации, прежде чем они смогут добраться до него.