2016-08-17 44 views
3

我使用Cocos2dx的早期版本編寫遊戲並使用VS 2013進行編譯。請注意,我使用CMake和Qt Creator兩個編譯器版本。當Cocos2dx V3.12出來了,我決定升級的lib在我的遊戲版本,並使用VS 2015年開始然後,我開始收到此錯誤:LNK2001在VS 2013(MSVC 18)但不是VS 2015(MSVC 19)

QCardManager.cpp.obj:-1: error: LNK2001: unresolved external symbol "public: static class QCard * __cdecl QCard::create(enum PLAYER,struct Question const *,enum CARD_TYPE,int const &)" ([email protected]@@[email protected]@@[email protected]@[email protected]@[email protected])

當我是我沒有得到這樣的錯誤使用VS 2013.經過幾個小時的調試,我發現原因。

這裏是QCard粗糙decleration:

#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); 
} 

我有這樣的功能的正確實施QCard.cpp文件,該文件也被正確地添加到項目中。 所以問題是class Question;轉發聲明。我在QCard.cpp中包含了QuestionParser.h文件,但由於我在QCard.h中使用了QCard的正向聲明,因此QCardManager.cpp文件沒有執行Question,因此鏈接器錯誤。

以下是我的問題:我意識到2015年的應該是預期的行爲。但爲什麼會發生這種行爲?相同的代碼在VS 2013上編譯時沒有錯誤,但在VS 2015上沒有錯誤。我閱讀了Breaking Changes in Visual C++ 2015指南,並且看不到任何相關的內容。

編輯1: 原來向前聲明應該已經struct Question而不是class Question。當我嘗試在QCardManager.cpp中使用QCard::create時,我收到前面提到的鏈接器錯誤。但不在TimerHUD.cpp,這是在同一目錄中。我會發布他們的總結內容。請記住,我保留QCard的聲明與此編輯相同。

問題結構,這是在QuestionParser.h

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 
{ 
} 

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); 
} 

QCardManager引發鏈接器錯誤。但TimerHUD不。我現在分享內容。

TimerHUD.h

// Cocos2dx 
#include "2d/CCNode.h" 

namespace cocos2d 
{ 
class Sprite; 
class Label; 
} 

class TimerHUD : public cocos2d::Node 
{ 
} 

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); 
} 
+0

你說得對,'問題'是'struct'。將前面的聲明從'class Question'改爲'struct Question'後,問題就消失了。但是這對我提出了另一個問題,在進行更改之前,提出錯誤的相同代碼在另一個類中沒有引起錯誤。我在編輯中爲我的問題添加了更多解釋。謝謝。 – Furkanzmc

回答

6

你不應該需要這個Question的定義正確鏈接。 U@[email protected]和鏈接器錯誤似乎談論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' 

但是因爲你的警告級別太低,你沒有得到診斷。

您的代碼似乎從standard's point of view有效。從C++ 11 9.1/2:

A declaration consisting solely of class-key identifier; is either a redeclaration of the name in the current scope or a forward declaration of the identifier as a class name. It introduces the class name into the current scope.

但是,Visual C++軋液機的功能不同,這取決於一個名稱是否是一個class的名稱或struct

> undname [email protected]@[email protected]@@Z 
void __cdecl f(struct A *) 

> undname [email protected]@[email protected]@@Z 
void __cdecl f(class A *) 

注意struct是損壞爲UclassV。這是definitely a bug in Visual C++,不應該將classstruct區別對待。

一旦這樣理解,你的錯誤很容易重現:

> 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 *)" ([email protected]@[email protected]@@Z) referenced 
     in function _main 
a.exe : fatal error LNK1120: 1 unresolved externals 

所以,你有這些奇怪的問題,其原因是因爲行爲取決於特定translation unit(基本上,一個.cpp)看到Question作爲classstruct。這反過來取決於包括哪些標題。

請注意,您需要以不同的翻譯單位進行不匹配。在同一個單位,Visual C++ will use the the class-key from the definition,即使有前有不同的聲明:

Compiler Warning (level 2) C4099

'identifier' : type name first seen using 'objecttype1' now seen using 'objecttype2'

An object declared as a structure is defined as a class, or an object declared as a class is defined as a structure. The compiler uses the type given in the definition.

至於原因爲何,這不是在Visual C++ 2013的問題,我懷疑的是,重整方案最近改變。這聽起來像這個bug已經出現since at least 6.0。您可能無意中更改了包含的順序。