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