Sign in to follow this  
lonewolff

Troubles using .h and .cpp files

Recommended Posts

lonewolff    1182
Hi there, I am currently working on a project where the code is starting to build up in a class. In the past I have always crammed the functions into the header file. I know this is bad practice and this is why I am trying to do it the right way. At the moment I have a function prototype in the .h file after the 'public:' statement. I have put the actual function in a separate .cpp file like so. engine.h
#pragma once

class Engine
{
public:
	void function();

engine.cpp
#include engine.h

void function()
{
	// implementation here
}

The problem is when I compile I get a linker error as a result
Quote:
1>framework.obj : error LNK2005: "long __stdcall WinProc(struct HWND__ *,unsigned int,unsigned int,long)" (?WinProc@@YGJPAUHWND__@@IIJ@Z) already defined in main.obj 1>framework.obj : error LNK2005: "private: static int Engine::init" (?init@Engine@@0HA) already defined in main.obj
I cant figure out what is happening here. Any help would be greatly appreciated.

Share this post


Link to post
Share on other sites
mattd    1078
The linker is complaining because it is seeing definitions for the same things in different files, namely WinProc and Engine::init in both main.cpp and framework.cpp.

Are these functions/static member definitions in a header file main.cpp and framework.cpp are both including?

Also, you might already be aware of this, and just forgot it when typing out your example case code here without compiling, but your engine.cpp would look like:
#include "engine.h"

void Engine::function()
{
// implementation here
}

I.e., you need to explicitly include the class name in the method definition.

Share this post


Link to post
Share on other sites
lonewolff    1182
You are right about the example I did leave off Engine:: at the front. My actual code has it in there though.

The function is only defined in the .h file.

If I inline the code it works fine. So, I cant see where the re-definition is happening.

Share this post


Link to post
Share on other sites
mattd    1078
Quote:
Original post by lonewolff
The function is only defined in the .h file.

If I inline the code it works fine. So, I cant see where the re-definition is happening.

Which function?

Post the source for the header you're talking about.

Share this post


Link to post
Share on other sites
lonewolff    1182
Here is the full source. The function in question is Engine::startRender() - as that is where I started to put the stuff in the cpp file.

main.cpp

#include"framework.h"

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nShowCmd)
{
Engine *mEngine=new Engine;
mEngine->makeWindow();
mEngine->terraForm(10,10);

MSG msg;
ZeroMemory(&msg,sizeof(msg));
while(msg.message!=WM_QUIT)
{
if(PeekMessage(&msg,NULL,0U,0U,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
mEngine->startRender();

// ***** Put scene here *****
mEngine->cameraPosition(0,10.0,-15.0);
mEngine->renderTerrain();

mEngine->endRender();

if(mEngine->handle()==GetActiveWindow())
{
if(GetAsyncKeyState(VK_ESCAPE))
{
PostQuitMessage(0);
}
}
}
}

delete mEngine;

return 0;
}



framework.h

#pragma once

#include <d3dx9.h>
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")

#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
struct CUSTOMVERTEX{FLOAT X,Y,Z;DWORD COLOR;};

LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
}

return DefWindowProc(hWnd,msg,wParam,lParam);
}

class Engine
{
public:
Engine()
{
if(init==0)
{
hWnd=NULL;
d3dInterface=NULL;
d3dDevice=NULL;
v_buffer=NULL;
i_buffer=NULL;
}
++(this->init);
}
~Engine()
{
--(this->init);
if(init==0)
{
if(d3dDevice)
d3dDevice->Release();
if(d3dInterface)
d3dInterface->Release();
}
}

int makeWindow()
{
WNDCLASSEX wClass;
ZeroMemory(&wClass,sizeof(WNDCLASSEX));
wClass.cbClsExtra=NULL;
wClass.cbSize=sizeof(WNDCLASSEX);
wClass.cbWndExtra=NULL;
wClass.hbrBackground=(HBRUSH)COLOR_WINDOW;
wClass.hCursor=LoadCursor(NULL,IDC_ARROW);
wClass.hIcon=NULL;
wClass.hIconSm=NULL;
wClass.hInstance=(HINSTANCE)GetModuleHandle(NULL);
wClass.lpfnWndProc=(WNDPROC)WinProc;
wClass.lpszClassName="Window Class";
wClass.lpszMenuName=NULL;
wClass.style=CS_HREDRAW|CS_VREDRAW;

if(!RegisterClassEx(&wClass))
{
int nResult=GetLastError();
MessageBox(NULL,
"Window class creation failed",
"Window Class Failed",
MB_ICONERROR);
return nResult;
}

hWnd=CreateWindowEx(NULL,
"Window Class",
"Window Title",
WS_OVERLAPPEDWINDOW,
(GetSystemMetrics(SM_CXSCREEN)/3)*2-(GetSystemMetrics(SM_CXSCREEN)/2),
(GetSystemMetrics(SM_CYSCREEN)/3)*2-(GetSystemMetrics(SM_CYSCREEN)/2),
(GetSystemMetrics(SM_CXSCREEN)/3)*2,
(GetSystemMetrics(SM_CYSCREEN)/3)*2,
NULL,
NULL,
(HINSTANCE)GetModuleHandle(NULL),
NULL);

if(!hWnd)
{
int nResult=GetLastError();

MessageBox(NULL,
"Window creation failed",
"Window Creation Failed",
MB_ICONERROR);
return nResult;
}

// Setup D3D Interface
d3dInterface=Direct3DCreate9(D3D_SDK_VERSION);
if(!d3dInterface)
{
MessageBox(NULL,"Could not create D3D interface","Initialization problem!",NULL);
return 1;
}

// Setup D3D adapter
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.AutoDepthStencilFormat=D3DFMT_D24S8;
d3dpp.BackBufferCount=1;
d3dpp.BackBufferFormat=D3DFMT_X8R8G8B8;
d3dpp.BackBufferHeight=(GetSystemMetrics(SM_CYSCREEN)/3)*2;
d3dpp.BackBufferWidth=(GetSystemMetrics(SM_CXSCREEN)/3)*2;
d3dpp.EnableAutoDepthStencil=true;
d3dpp.Flags=0;
d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
d3dpp.hDeviceWindow=hWnd;
d3dpp.MultiSampleQuality=0;
d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed=true;

// Create D3D Device
d3dInterface->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_PUREDEVICE,
&d3dpp,
&d3dDevice);

if(!d3dDevice)
{
MessageBox(NULL,"Unable to create D3D device.\r\nYour graphics adapter may not support 'Hardware Vertex Processing'","Initialization problem!",NULL);
return 1;
}

d3dDevice->SetRenderState(D3DRS_LIGHTING,FALSE);

// Show the window after all of the DX initialization for a faster cleaner looking start-up
ShowWindow(hWnd,1);

return 0;
}

void startRender(void);
/*
void startRender()
{
d3dDevice->Clear(0,0,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);
d3dDevice->BeginScene();
}
*/

void endRender()
{
d3dDevice->EndScene();
d3dDevice->Present(0,0,0,0);
}

HWND handle()
{
return hWnd;
}

void createTerrain()
{
return;
}

void cameraPosition(float x,float y,float z)
{
D3DXMATRIX mCamera;
D3DXVECTOR3 mCameraPosition(x,y,z);
D3DXVECTOR3 mCameraUp(0.0f,1.0f,0.0f);
D3DXVECTOR3 mCameraTarget(0.0f,0.0f,0.0f);
D3DXMatrixLookAtLH(&mCamera,&mCameraPosition,&mCameraTarget,&mCameraUp);
d3dDevice->SetTransform(D3DTS_VIEW,&mCamera);

D3DXMATRIX mFrustum;
RECT rRect;
GetClientRect(hWnd,&rRect);
float width=(float)rRect.right;
float height=(float)rRect.bottom;
D3DXMatrixPerspectiveFovLH(&mFrustum,D3DXToRadian(60),((FLOAT)(GetSystemMetrics(SM_CXSCREEN)/3)*2)/((FLOAT)(GetSystemMetrics(SM_CYSCREEN)/3)*2),1.0f,5000.0f);
d3dDevice->SetTransform(D3DTS_PROJECTION,&mFrustum);

return;
}

void terraForm(int width,int height)
{
CUSTOMVERTEX vertices[100];

int k=0;
for(float i=0;i<height;++i)
{
for(float j=0;j<width;++j)
{
vertices[k].X=j;
vertices[k].Y=0.0f;
vertices[k].Z=-i;
vertices[k].COLOR=0xffffffff;
++k;
}
}

d3dDevice->CreateVertexBuffer(100*sizeof(CUSTOMVERTEX),0,CUSTOMFVF,D3DPOOL_MANAGED,&v_buffer,NULL);
VOID* pVoid; // a void pointer
v_buffer->Lock(0,0,(void**)&pVoid,0); // lock v_buffer and load the vertices into it
memcpy(pVoid,vertices,sizeof(vertices));
v_buffer->Unlock();

short indices[3*100];

k=0;
for(int i=0;i<height-1;++i)
{
for(int j=0;j<width-1;++j)
{
// Triange 1
indices[k]=i*height+j;
indices[k+1]=i*height+j+1;
indices[k+2]=(i+1)*height+j;
// Trangle 2
indices[k+3]=(i+1)*height+j;
indices[k+4]=i*height+j+1;
indices[k+5]=(i+1)*height+j+1;
k+=6;
}
}

// create an index buffer interface called i_buffer
d3dDevice->CreateIndexBuffer(((width-1)*(height-1)*2*3)*sizeof(short),0,D3DFMT_INDEX16,D3DPOOL_MANAGED,&i_buffer,NULL); // 6 is the number of indices Quads = tri's * 2
i_buffer->Lock(0,0,(void**)&pVoid,0); // lock i_buffer and load the indices into it
memcpy(pVoid,indices,sizeof(indices));
i_buffer->Unlock();

return;
}

void renderTerrain()
{
// Prepare to render the terrain
d3dDevice->SetFVF(CUSTOMFVF);
// select the vertex buffer to display
d3dDevice->SetStreamSource(0,v_buffer,0,sizeof(CUSTOMVERTEX));
d3dDevice->SetIndices(i_buffer);
// Draw the terrain
//g_d3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,10,0,6);

d3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,100,0,(10-1)*(10-1)*2);
}

private:
static int init;
HWND hWnd;
IDirect3D9 *d3dInterface; // Remember anything starting with 'I' is COM
IDirect3DDevice9 *d3dDevice; // object and requires releasing at end of app.

LPDIRECT3DVERTEXBUFFER9 v_buffer; // Pointer to the vertex buffer
LPDIRECT3DINDEXBUFFER9 i_buffer; // Pointer to the index buffer
};

int Engine::init=0;



famework.cpp

#include"framework.h"

void Engine::startRender()
{
d3dDevice->Clear(0,0,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(0,0,0),1.0f,0);
d3dDevice->BeginScene();
}



Once again, thanks in adavnce!

Share this post


Link to post
Share on other sites
Brother Bob    10344
Since WinProc is defined in framework.h, which is included in both main.cpp and framework.cpp, the function will be defined in both main.cpp and framework.cpp also. This is what the linker error says, that the function is defined in multiple places. Same for the Engine::init definition.

Move the definition to one source file only, and only use declarations in header files.

Share this post


Link to post
Share on other sites
pto    194
Quote:
Original post by lonewolff
BTW, isnt this what #pragma once is for?


No. That ensures that its only included once per .cpp file, NOT across all files. So if you used #pragmaonec WinProc is included once in main.cpp, and then once in framework.cpp which doesn't help you at all.


What you want is to have something like:

// framework.h
// this is just a declaration saying "hey guys, this function exists"
// and can be included as many times as you like error free
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);



// then in framework.cpp you have the full thing
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
......
}
}





Remember the compiler builds ever single .cpp file into an object file. Then the linker takes those object files and mash's them together, but it gets confused if it has 2 functions of the same name in different object files. When you call winproc which one did you mean? The one from framework or the one from main? The linker can't tell so you get an error. A easy rule is - never have a function implementation in a .h, only have declarations then put the implementations in the corresponding cpp file.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this