我正在使用早期版本的Cocos2dx来编写游戏并使用VS 2013进行编译.请注意,我正在使用CMake和Qt Creator两种编译器版本.当Cocos2dx v3.12问世时,我决定在我的游戏中将lib升级到该版本并开始使用VS 2015.然后我开始收到此错误:
QCardManager.cpp.obj:-1:错误:LNK2001:未解析的外部符号"public:static class QCard*__cdecl QCard :: create(enum PLAYER,struct Question const*,enum CARD_TYPE,int const&)"(?create @ QCard @@ SAPAV1 @ W4PLAYER @@ PBUQuestion @@ W4CARD_TYPE @@ ABH @ Z)
当我使用VS 2013时,我没有得到那个错误.经过几个小时的调试后我发现了原因.
这是粗略的贬值QCard:
#include "2d/CCSprite.h"
#include "CommonVariables.h"
class RandomPostureSprite;
class Question;
namespace cocos2d
{
class Label;
}
enum class CARD_TYPE {
QUESTION,
OPTION
};
class QCard : public cocos2d::Sprite
{
public:
static QCard *create(PLAYER player, const Question *question, CARD_TYPE type, const int &index);
}
Run Code Online (Sandbox Code Playgroud)
我在QCard.cpp文件中正确实现了该功能,并且该文件也正确地添加到了项目中.所以问题是class Question;前方声明.我包括在该QuestionParser.h文件QCard.cpp,但是,因为我用正向声明QCard中QCard.h,QCardManager.cpp文件没有为执行Question,因此连接错误.
这是我的问题:我意识到VS 2015所做的应该是预期的行为.但为什么会发生这种行为呢?相同的代码在VS 2013上编译没有错误,但在VS 2015上没有.我阅读了Visual C++ 2015中的重大变化指南,并且看不到任何相关内容.
编辑1:原来的声明应该是struct Question而不是class Question.当我尝试使用时QCard::create,QCardManager.cpp我得到上述链接器错误.但不在TimerHUD.cpp,它位于同一目录中.我将发布他们的摘要内容.请记住,我QCard通过此编辑保持相同的声明.
问题结构,位于QuestionParser.h:
struct Question {
Question()
: type()
, source()
, alias()
, color(0, 0, 0)
{}
};
Run Code Online (Sandbox Code Playgroud)
QCardManager.h
// Cocos2dx
#include "math/Vec2.h"
#include "math/CCGeometry.h"
// Utilities
#include "CommonVariables.h"
// Local
#include "GameDefinitions.h"
#include "QuestionParser.h"// This has the Question struct
// Forward declerations
class QCard;
namespace cocos2d
{
class Layer;
class Sprite;
}
class QCardManager
{
}
Run Code Online (Sandbox Code Playgroud)
QCardManager.cpp
#include "QCardManager.h"
// Local
#include "QCard.h"
#include "RandomPostureSprite.h"
// Utilities
#include "GameManager.h"
#include "GameSettings.h"
#include "CocosUtils.h"
// Cocos2dx
#include "cocos2d.h"
using namespace cocos2d;
QCardManager::QCardManager(PLAYER player, Layer &parent)
{
// This line gives the linker error
QCard::create(PLAYER::PLAYER_ONE, nullptr, CARD_TYPE::QUESTION, 1);
}
Run Code Online (Sandbox Code Playgroud)
QCardManager引发链接器错误.但TimerHUD事实并非如此.我现在正在分享内容.
TimerHUD.h
// Cocos2dx
#include "2d/CCNode.h"
namespace cocos2d
{
class Sprite;
class Label;
}
class TimerHUD : public cocos2d::Node
{
}
Run Code Online (Sandbox Code Playgroud)
TimerHUD.cpp
// Cocos2dx
#include "cocos2d.h"
#include "SimpleAudioEngine.h"
// Local
#include "GameDefinitions.h"
// Utilities
#include "GameManager.h"
#include "GameSettings.h"
#include "CocosUtils.h"
#include "QCard.h"
using namespace cocos2d;
TimerHUD::TimerHUD()
{
// This does not raise the linker error
QCard::create(PLAYER::PLAYER_ONE, nullptr, CARD_TYPE::QUESTION, 1);
}
Run Code Online (Sandbox Code Playgroud)
你不应该需要Question这个定义来正确链接.在U中@PBUQuestion@和链接错误似乎对谈struct Question,而不是class Question,所以你的声明和定义之间的不匹配Question.如果您要提高警告级别,您会看到:
> type a.cpp
struct A;
class A {};
> cl /Wall a.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24213.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
a.cpp
a.cpp(2): warning C4099: 'A': type name first seen using 'struct' now seen using 'class'
a.cpp(2): note: see declaration of 'A'
Run Code Online (Sandbox Code Playgroud)
但由于您的警告级别太低,您无法获得该诊断.
从标准的角度来看,您的代码似乎是有效的.来自C++ 11 9.1/2:
仅由类密钥标识符组成的声明; 是对当前作用域中名称的重新声明,或者是作为类名称的标识符的前向声明.它将类名引入当前范围.
但是,Visual C++会根据名称是a class还是a来不同地破坏函数的名称struct:
> undname ?f@@YAXPAUA@@@Z
void __cdecl f(struct A *)
> undname ?f@@YAXPAVA@@@Z
void __cdecl f(class A *)
Run Code Online (Sandbox Code Playgroud)
请注意,struct是错位的U和class作为V.这是绝对在Visual C++中的错误,不应该对待class和struct区别.
一旦理解了这一点,您的错误就很容易重现:
> type a.cpp
class A; // declares A as a class
void f(A* a); // declares f(class A*)
int main()
{
f(nullptr); // calls f(class A*)
}
> type b.cpp
struct A {}; // defines A as a struct, mismatch!
void f(A* a) {} // defines f(struct A*)!
> cl /nologo a.cpp b.cpp
a.cpp
b.cpp
Generating Code...
a.obj : error LNK2019: unresolved external symbol
"void __cdecl f(class A *)" (?f@@YAXPAVA@@@Z) referenced
in function _main
a.exe : fatal error LNK1120: 1 unresolved externals
Run Code Online (Sandbox Code Playgroud)
因此,您遇到这些奇怪问题的原因是因为行为取决于特定翻译单元(基本上是a .cpp)是Question视为a class还是a struct.这又取决于包含哪些标题.
请注意,您需要将不匹配项置于不同的翻译单元中.在同一个单元中,Visual C++将使用定义中的类键,即使之前有不同的声明:
编译器警告(级别2)C4099
'identifier':首先使用'objecttype1'看到的类型名称现在看到使用'objecttype2'
声明为结构的对象定义为类,或声明为类的对象定义为结构.编译器使用定义中给出的类型.
至于这在Visual C++ 2013中不是问题的原因,我怀疑最近的修改方案有所改变.听起来这个bug已经存在至少6.0.您可能无意中更改了包含的顺序.
| 归档时间: |
|
| 查看次数: |
202 次 |
| 最近记录: |