I was using an earlier version of Cocos2dx to write a game and compiling it with VS 2013. Note that I'm using CMake and Qt Creator with both compiler versions. When Cocos2dx v3.12 came out, I decided to upgrade the lib to that version in my game and started using VS 2015. Then I started getting this error:
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 &)" (?create@QCard@@SAPAV1@W4PLAYER@@PBUQuestion@@W4CARD_TYPE@@ABH@Z)
And I did not get that error when I was using VS 2013. After a couple of hours of debugging I found out the reason.
Here's the rough decleration of 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);
}
And I had the proper implementation of that function in QCard.cpp
file and that file was also properly added to the project.
So the problem was the class Question;
forward declaration. I included the QuestionParser.h
file in QCard.cpp
but since I used a forward declaration for QCard
in QCard.h
, QCardManager.cpp
file did not have the implementation for Question
and hence the linker error.
Here's my question: I realize that what VS 2015 does should be the expected behaviour. But why is that behaviour happening? The same code compiles with no error on VS 2013 but not on VS 2015. I read the Breaking Changes in Visual C++ 2015 guide and couldn't not see anything that was related.
EDIT 1:
Turns out the forward declaration should have been struct Question
instead of class Question
. When I try to use QCard::create
in QCardManager.cpp
I get the aforementioned linker error. But not in TimerHUD.cpp
, which is in the same directory. I'll post the summary contents of them both. Keep in mind that I'm keeping the declaration of QCard
the same with this edit.
The Question struct, which is in QuestionParser.h
:
struct Question {
Question()
: type()
, source()
, alias()
, color(0, 0, 0)
{}
};
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
raises the linker error. But TimerHUD
does not. I'm sharing the contents now.
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);
}