2012-04-27 49 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++不支持default-int
  • 错误C4430:缺少类型说明符 - 假定为int。注意:C++不 支持默认int

  • mesh.h(11):错误C2653: 'MeshList':不是类或命名空间 名称

  • meshlist.cpp(5):错误C2248 : '网:: vboHandle_':无法访问 私有成员在课堂上 '网'
  • mesh.h声明(10):看的 '网:: vboHandle_'
  • mesh.h声明(8):看到声明'Mesh'
  • meshlist.cpp(5):错误C2100:非法间接寻址
+38

你需要多出来。 – 2012-04-27 01:19:16

+32

仅适用于标题。 – 2012-04-27 01:19:17

+5

尝试'class Meshlist;'而不是'#include“MeshList.h”' – chris 2012-04-27 01:19:18

回答

6

循环依赖在其他的答案解释...

这里谈到的解决方案:

MeshList.h

  • 与向前声明class Mesh;更换#include "Mesh.h"(你不这里不需要include,因为你只声明一个指向Mesh的指针)

MeshList.cpp

  • 添加#include "Mesh.h"到您的包括(你需要的声明,因为您使用网)

最后的编译错误,你提到的是另一个问题:

*mesh->vboHandle_ = 4; 

mesh是一个指针。您的代码选择会员vboHandle_并尝试解除引用(失败)。我想你的意思是:

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

根据David的评论修正了答案。 – Stephan 2012-05-02 15:43:56

9

当你编译Mesh.cpp,它包括Mesh.h,其中包括MeshList.h,其开始包括Mesh.h但早期停止,因为_MESH_H现在定义。然后(返回MeshList.h)参考Mesh - 但尚未宣布。因此,例如,您的C2143错误。

+0

@ildjarn,这很有趣,因为我从来没有发现任何地方。请问为什么? – chris 2012-04-27 01:25:41

+0

@chris:你得问问设计C++的人! – ildjarn 2012-04-27 01:26:24

+0

@ildjarn:你确定吗?其实我相当肯定,事实恰恰相反。我甚至想到要记住,标准表明,结交一个班级相当于结交所有的职能......我将不得不寻找我猜的报价。 – 2012-04-27 01:32:56

6

这是因为您在文件Mesh.h中有#include "MeshList.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之前。这个类的客户端只关心公共接口,不需要让他们在所有脏的实现细节中都能够接触到它。

+0

据我所知,如果你的朋友声明高于第一次使用,你就不需要前向声明。 (我测试过类似的例子,没有'class MeshList;'在VS中,它工作。) – anxieux 2012-04-28 07:25:36

+0

@anxieux:我从来没有真正完全理解'friend class'后面的名字在哪个范围内被注入,如果找不到;所以我养成了只是向前宣布类型的习惯。也许稍微冗长些,但是嘿:它可以100%的工作! – 2012-04-28 10:21:23