我不明白为什么以下代码会产生未解析的符号
main.cpp中:
#include <Windows.h>
#include "rendermanager.h"
#include "gamestatemanager.h"
using namespace GameplayLib;
using namespace RenderLib;
//Window Procedure Methods
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT paint_struct;
HDC hDC;
switch (message)
{
case WM_PAINT:
hDC = BeginPaint(hwnd, &paint_struct);
EndPaint(hwnd, &paint_struct);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
int WINAPI wWinMain(HINSTANCE h_instance, HINSTANCE prev_instance, LPWSTR cmd_line, int cmd_show)
{
//Suppress unused warning for these parameters
UNREFERENCED_PARAMETER(prev_instance);
UNREFERENCED_PARAMETER(cmd_line);
//Initialize a window
WNDCLASSEX wnd_class = { 0 };
wnd_class.cbSize = sizeof(WNDCLASSEX);
wnd_class.style = CS_HREDRAW | CS_VREDRAW;
wnd_class.lpfnWndProc = WndProc; //Callback function that's called whenever an event notification comes form OS.
wnd_class.hInstance = h_instance;
wnd_class.hCursor = LoadCursor(NULL, IDC_ARROW);
wnd_class.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wnd_class.lpszMenuName = NULL;
wnd_class.lpszClassName = "ProjectX";
if (RegisterClassEx(&wnd_class) == false)
{
return -1;
}
RECT window_rect = { 0, 0, 800, 600 };
AdjustWindowRect(&window_rect, WS_OVERLAPPEDWINDOW, FALSE);
HWND hwnd = CreateWindowA("ProjectX", "ProjectX 0.01", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, NULL, NULL, h_instance, NULL);
if (hwnd == NULL)
{
return -1;
}
ShowWindow(hwnd, cmd_show);
//Initialize sub-systems
cGameStateManager::Create();
cRenderManager::Create(h_instance, hwnd);
//Enter Main loop
MSG msg = { 0 };
while (true)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
//translate keystroke msgs into the right format
TranslateMessage(&msg);
//Send the msg to WndProc
DispatchMessage(&msg);
}
if (msg.message == WM_QUIT)
{
//Shutdown
cRenderManager::Destroy();
cGameStateManager::Destroy();
break;
}
else
{
//Update
cGameStateManager::Instance().Update();
//Render
cRenderManager::Instance().Render();
}
}
return static_cast<int>(msg.wParam);
}
gamestatemanager.h:
#pragma once
namespace GameplayLib
{
class cGameStateManager
{
public:
static void Create();
static void Destroy();
static cGameStateManager& Instance();
void Update();
private:
explicit cGameStateManager();
~cGameStateManager();
static cGameStateManager* sGameStateManagerInstance;
};
}
gamestatemanager.cpp:
#include "gamestatemanager.h"
using namespace GameplayLib;
cGameStateManager* cGameStateManager::sGameStateManagerInstance = nullptr;
//static
void cGameStateManager::Create()
{
sGameStateManagerInstance = new cGameStateManager();
}
//static
void cGameStateManager::Destroy()
{
delete sGameStateManagerInstance;
}
//static
cGameStateManager& cGameStateManager::Instance()
{
return *sGameStateManagerInstance;
}
void cGameStateManager::Update()
{
}
//Private
cGameStateManager::cGameStateManager()
{
}
cGameStateManager::~cGameStateManager()
{
}
奇怪的是,cRenderManager遵循完全相同的单例模式但没有未解析的符号。它在main.cpp中没有cGameStateManager代码编译得很好。这是源代码。
rendermanager.h:
#pragma once
#include "directxincludes.h"
namespace RenderLib
{
class cRenderManager
{
public:
static void Create(HINSTANCE h_instance, HWND hwnd);
static void Destroy();
static cRenderManager& Instance();
void Render();
private:
explicit cRenderManager();
~cRenderManager();
static cRenderManager* sRenderManagerInstance; //Static instance
HINSTANCE mHInstance; //Handle to instance
HWND mHWND; //Handle to window
D3D_DRIVER_TYPE mD3DDriverType; //Device type
D3D_FEATURE_LEVEL mD3DFeatureLevel; //Feature level
ID3D11Device* mD3DDevice; //Device
ID3D11DeviceContext* mD3DDeviceContext; //Device context
IDXGISwapChain* mDXGISwapChain; //Swap chain
ID3D11RenderTargetView* mRenderTargetView; //Back buffer
};
}
rendermanager.cpp:
#include "rendermanager.h"
using namespace RenderLib;
cRenderManager* cRenderManager::sRenderManagerInstance = nullptr;
//static
void cRenderManager::Create(HINSTANCE h_instance, HWND hwnd)
{
sRenderManagerInstance = new cRenderManager();
sRenderManagerInstance->mHInstance = h_instance;
sRenderManagerInstance->mHWND = hwnd;
//Get the dimensions
RECT dimensions;
GetClientRect(hwnd, &dimensions);
unsigned int width = dimensions.right - dimensions.left;
unsigned int height = dimensions.bottom - dimensions.top;
//D3D driver types
D3D_DRIVER_TYPE driver_types[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_SOFTWARE
};
unsigned int total_driver_types = ARRAYSIZE(driver_types);
//D3D feature levels in the order we support
D3D_FEATURE_LEVEL feature_levels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
unsigned int total_feature_levels = ARRAYSIZE(feature_levels);
//Create swap chain
DXGI_SWAP_CHAIN_DESC swap_chain_desc;
ZeroMemory(&swap_chain_desc, sizeof(swap_chain_desc));
swap_chain_desc.BufferCount = 1;
swap_chain_desc.BufferDesc.Width = width;
swap_chain_desc.BufferDesc.Height = height;
swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60;
swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1;
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swap_chain_desc.OutputWindow = hwnd;
swap_chain_desc.Windowed = true;
swap_chain_desc.SampleDesc.Count = 1;
swap_chain_desc.SampleDesc.Quality = 0;
unsigned int creation_flags = 0;
#ifdef _DEBUG
creation_flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
//Create driver
HRESULT result;
unsigned int driver = 0;
for (driver = 0; driver < total_driver_types; ++driver)
{
result = D3D11CreateDeviceAndSwapChain(0, driver_types[driver], 0, creation_flags, feature_levels, total_feature_levels, D3D11_SDK_VERSION,
&swap_chain_desc, &sRenderManagerInstance->mDXGISwapChain, &sRenderManagerInstance->mD3DDevice,
&sRenderManagerInstance->mD3DFeatureLevel, &sRenderManagerInstance->mD3DDeviceContext);
if (SUCCEEDED(result))
{
sRenderManagerInstance->mD3DDriverType = driver_types[driver];
break;
}
}
if (FAILED(result))
{
DXTRACE_MSG("Failed to create the Direct3D Device!");
//TODO handle this?
return;
}
//Create back buffer texture
ID3D11Texture2D* backbuffer_texture = nullptr;
result = sRenderManagerInstance->mDXGISwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backbuffer_texture);
if (FAILED(result))
{
DXTRACE_MSG("Failed to get the swap chain back buffer!");
//TODO handle this?
return;
}
//Create the render target view
result = sRenderManagerInstance->mD3DDevice->CreateRenderTargetView(backbuffer_texture, 0, &sRenderManagerInstance->mRenderTargetView);
if (backbuffer_texture != nullptr)
{
backbuffer_texture->Release();
}
if (FAILED(result))
{
DXTRACE_MSG("Failed to create the render target view!");
//TODO handle this?
return;
}
//Setup render target
sRenderManagerInstance->mD3DDeviceContext->OMSetRenderTargets(1, &sRenderManagerInstance->mRenderTargetView, 0);
//Setup viewport
D3D11_VIEWPORT viewport;
viewport.Width = static_cast<float>(width);
viewport.Height = static_cast<float>(height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
sRenderManagerInstance->mD3DDeviceContext->RSSetViewports(1, &viewport);
}
//static
void cRenderManager::Destroy()
{
if (sRenderManagerInstance->mRenderTargetView != nullptr)
{
sRenderManagerInstance->mRenderTargetView->Release();
}
if (sRenderManagerInstance->mDXGISwapChain != nullptr)
{
sRenderManagerInstance->mDXGISwapChain->Release();
}
if (sRenderManagerInstance->mD3DDeviceContext != nullptr)
{
sRenderManagerInstance->mD3DDeviceContext->Release();
}
if (sRenderManagerInstance->mD3DDevice != nullptr)
{
sRenderManagerInstance->mD3DDevice->Release();
}
sRenderManagerInstance->mD3DDevice = nullptr;
sRenderManagerInstance->mD3DDeviceContext = nullptr;
sRenderManagerInstance->mDXGISwapChain = nullptr;
sRenderManagerInstance->mRenderTargetView = nullptr;
delete sRenderManagerInstance;
}
//static
cRenderManager& cRenderManager::Instance()
{
return *sRenderManagerInstance;
}
void cRenderManager::Render()
{
//Render all your stuff!
}
//Private
cRenderManager::cRenderManager()
: mD3DDriverType( D3D_DRIVER_TYPE_NULL )
, mD3DFeatureLevel( D3D_FEATURE_LEVEL_11_0 )
, mD3DDevice( nullptr )
, mD3DDeviceContext( nullptr )
, mDXGISwapChain( nullptr )
, mRenderTargetView( nullptr )
{
}
cRenderManager::~cRenderManager()
{
//Private destructor. Do nothing
}
最后,我收到以下编译错误:
1> gamestatemanager.h
1> gamestatemanager.cpp
1> Generating Code...
1>x64\Debug\//gamestatemanager.obj : warning LNK4042: object specified more than once; extras ignored
1>main.obj : error LNK2019: unresolved external symbol "public: static void __cdecl GameplayLib::cGameStateManager::Create(void)" (?Create@cGameStateManager@GameplayLib@@SAXXZ) referenced in function wWinMain
1>main.obj : error LNK2019: unresolved external symbol "public: static void __cdecl GameplayLib::cGameStateManager::Destroy(void)" (?Destroy@cGameStateManager@GameplayLib@@SAXXZ) referenced in function wWinMain
1>main.obj : error LNK2019: unresolved external symbol "public: static class GameplayLib::cGameStateManager & __cdecl GameplayLib::cGameStateManager::Instance(void)" (?Instance@cGameStateManager@GameplayLib@@SAAEAV12@XZ) referenced in function wWinMain
1>main.obj : error LNK2019: unresolved external symbol "public: void __cdecl GameplayLib::cGameStateManager::Update(void)" (?Update@cGameStateManager@GameplayLib@@QEAAXXZ) referenced in function wWinMain
1>G:\Programming\C++\Projects\ProjectX\x64\Debug\ProjectX.exe : fatal error LNK1120: 4 unresolved externals