C++ 循环依赖性头痛
最初的问题是 我有三个类A、B和C。A有一个链接并调用B,B有一个链接并调用C。但C有一个静态方法调用。而我就是无法让这个静态呼叫工作 但是伙计们向我抱怨截短代码的错误,所以类的真实名称是GameRenderer、GameView和FieldView。GameRenderer具有指向GameView的链接和调用,GameView具有指向FieldView的链接和调用。但是FieldView调用了GameRenderer静态方法createGlTextureFromResource。而我就是无法让这个静态呼叫工作 这是完整的和真实的标题 游戏渲染器C++ 循环依赖性头痛,c++,header,linker,circular-dependency,C++,Header,Linker,Circular Dependency,最初的问题是 我有三个类A、B和C。A有一个链接并调用B,B有一个链接并调用C。但C有一个静态方法调用。而我就是无法让这个静态呼叫工作 但是伙计们向我抱怨截短代码的错误,所以类的真实名称是GameRenderer、GameView和FieldView。GameRenderer具有指向GameView的链接和调用,GameView具有指向FieldView的链接和调用。但是FieldView调用了GameRenderer静态方法createGlTextureFromResource。而我就是无法让
// GameRenderer.h
#ifndef GAME_RENDERER
#define GAME_RENDERER
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
namespace game{
class GameModel;
class GameView;
class GameRenderer {
jobject* context;
jobject* gameOverHandler;
static JNIEnv* env;
static jobject* jparent;
GameModel* gameModel;
GameView* gameView;
glm::mat4 mProjMatrix;
glm::mat4 mVMatrix;
public:
GameRenderer(jobject* context, jobject* gameOverHandler, JNIEnv* env, jobject* jparent);
void onSurfaceCreated();
void onDrawFrame();
void onSurfaceChanged(int width, int height);
void setMotionDirection();
static int* getImagePixels (int imageId, int width, int height);
static void createGlTextureFromResource (int resourceId, int textureId);
};
}
#endif
GameView.h
// GameView.h
#ifndef GAME_VIEW
#define GAME_VIEW
#include <glm/glm.hpp>
namespace game{
class GameModel;
class FieldView;
class GameView {
GameModel* gameModel;
FieldView* fieldView;
public:
GameView(GameModel* gameModel);
void draw(glm::mat4 mProjMatrix, glm::mat4 mVMatrix);
};
}
#endif
FieldView.h
// FieldView.h
#ifndef FIELD_VIEW
#define FIELD_VIEW
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include "GLESUtils.h"
namespace game{
class GameRenderer;
class FieldView {
static const int FLOAT_SIZE_BYTES = 4;
static const int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
static const int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
static const int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
glm::mat4 mMMatrix;
glm::mat4 mMVPMatrix;
int mProgram;
int mTextureID;
int muMVPMatrixHandle;
int maPositionHandle;
int maTextureHandle;
public:
FieldView();
void draw(glm::mat4 mProjMatrix, glm::mat4 mVMatrix);
};
}
#endif
这是FieldView.cpp的剪切版本
// FieldView.cpp
#include <jni.h>
#include <string.h>
#include <android/log.h>
#include "FieldView.h"
#include "GameRenderer.h"
#define LOG_TAG "NDK_FieldView"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
namespace game{
static GLfloat mTriangleVerticesData[] = {...};
static const char mVertexShader[] = "...\n";
static const char mFragmentShader[] = "...\n";
FieldView::FieldView() {
mProgram = -1;
mTextureID = -1;
muMVPMatrixHandle = -1;
maPositionHandle = -1;
maTextureHandle = -1;
mProgram = GLESUtils::createProgram(mVertexShader, mFragmentShader);
GLESUtils::checkGlError("createProgram mProgram");
if (mProgram == 0) {
LOGI("program not created exiting");
return;
}
maPositionHandle = glGetAttribLocation(mProgram, "aPosition");
GLESUtils::checkGlError("glGetAttribLocation aPosition");
if (maPositionHandle == -1) {
return;
}
maTextureHandle = glGetAttribLocation(mProgram, "aTextureCoord");
GLESUtils::checkGlError("glGetAttribLocation aTextureCoord");
if (maTextureHandle == -1) {
return;
}
muMVPMatrixHandle = glGetUniformLocation(mProgram, "uMVPMatrix");
GLESUtils::checkGlError("glGetUniformLocation uMVPMatrix");
if (muMVPMatrixHandle == -1) {
return;
}
/*
* Create our texture. This has to be done each time the
* surface is created.
*/
GLuint textures[] = {0};
glGenTextures(1, &textures[0]);
mTextureID = textures[0];
glBindTexture(GL_TEXTURE_2D, mTextureID);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// here is the actual problem, I get the following error on this line
// FieldView.cpp: In constructor 'game::FieldView::FieldView()':
// FieldView.cpp:89:9: error: incomplete type 'game::GameRenderer' used in nested name specifier
GameRenderer::createGlTextureFromResource(0x7f040004, mTextureID);
}
void FieldView::draw(glm::mat4 mProjMatrix, glm::mat4 mVMatrix) {
//... doesn't matter
}
}
如果我理解正确,我必须使用前向声明,并且至少在一个地方不使用头的includes来阻止循环,但我不能这样做,因为我在对象之间有调用,并且没有头编译器拒绝调用方法。编译器错误在FieldView.cpp中,请参阅GameRenderer::createGlTextureFromResource0x7f040004,mTextureID附近代码中的注释;打电话
在所有这些编辑之后,问题实际上保持不变:
我做错了什么?我想我在某处使用了非常糟糕的设计实践
请原谅我最初的错误。至少在你发布的代码中,没有理由在A.h的底部包含B.h等等。您应该将这些包括在实现文件中
// A.cpp
#include "A.h"
#include "B.h"
namespace game
{
....
}
我认为这应该奏效: 停止包含来自其他标头的标头。您不需要它们,这一点很明显,因为它只包含在最后一行中。作为一般规则,在头中包含尽可能少的内容,并尝试使用简单的声明,如类B;只要可能 包括C.cpp中的A.h和C.h。这两个类都是直接从C.cpp使用的,因此您需要同时包含这两个头
从我可以看出,include A.h在C.h头文件中什么都不买。你的C.cpp头应该包括A.h和C.h。同样,B.h也包括尾部的C.h,就像以前一样,什么都买不到
A.h - include no other headers, forward decl class C;
B.h - include no other headers, forward decl class C;
C.h - include no other headers, forward decl class A
A.cpp - include A.h, C.h
B.cpp - include A.h, B.h, C.h
C.cpp - include A.h, C.h
似乎你有一个咒语,就是一个.cpp文件只包含一个自定义头。对于多类/多头层次结构,这种情况几乎从未出现过。您的代码可以为我编译。尽管将C中的构造函数更改为默认构造函数,因此C.cpp中的代码有一个声明。我不太明白这个问题。为什么不包括其他标题呢?另一方面,我错过了文件末尾的包含:-我在头文件中包含了头文件,所以我得到了C a.k.a字段视图中名称的不明显重叠这没有改变任何东西,我仍然在构造函数“game::C::C”中获取FieldView.cpp C.cpp::C.cpp:89:9:错误:嵌套名称中使用的类型“game::A”不完整specifier@AntonBoritskiy这没有多大帮助,因为您的示例没有任何称为FieldView的内容。你能举个有代表性的例子吗?@AntonBoritskiy我很困惑。如我的回答所述,如果更改Cjobject*上下文;到C;因为C.cpp中的默认构造函数需要声明,所以它为我编译。您是在测试您在这里给出的代码,还是这只是为了表示您实际使用的代码?@AntonBoritskiy-错误消息说问题出在C.cpp的第89行,上面提供的C.cpp只有11行。编译发布的代码时会发生什么情况?是的,抱歉,我在翻译名称时不准确,请参阅完整源代码的更新问题shmm,我尝试了此操作,但没有效果,编译器说相同的错误。。。从逻辑上讲,我看不出有什么不同。在其他模块中包含警卫是一个错误。。。守卫的名字和游戏玩家的名字一致。。。当我开始改变头文件的模型时,我发现了它,包括一个文件一个文件,谢谢你的回答!