Sign in to follow this  
DestX

C++ Class Linker error

Recommended Posts

Hello, I'll spare you the details around this as they would take alot of reading and aren't really all that important, and jump right into the problem. I've just now added a class into a half-made game I'm working on, the class is something like this:
Quote:
class Block { public: double destx; double desty; int destw; int desth; int setblock; int pos; bool move; //Function call to draw a sprite. void drawSprite(SDL_Surface *string, SDL_Surface *screen, int srcx, int srcy, int srcw, int srch, double destx, double desty, int destw, int desth); };
The function call is called like this:
Quote:
drawSprite(sprite, screen, 52, 74, 52, 63, destx, desty, 52, 63);
And the forward declaraction in the class leads here:
Quote:
#include "stdafx.h" #include <iostream> #include <string> #include "SDL/SDL.h" #include "SDL/SDL_image.h" void drawSprite(SDL_Surface *string, SDL_Surface *screen, int srcx, int srcy, int srcw, int srch, double destx, double desty, int destw, int desth) { SDL_Rect source; source.x = srcx; source.y = srcy; source.w = srcw; source.h = srch; SDL_Rect destination; destination.x = destx; destination.y = desty; destination.w = destw; destination.h = desth; SDL_BlitSurface(string, &source, screen, &destination); }
I think that's all the important parts... Now for the problem, when I compile I get the following error from the linker:
Quote:
1>Main.obj : error LNK2019: unresolved external symbol "public: void __thiscall Block::drawSprite(struct SDL_Surface *,struct SDL_Surface *,int,int,int,int,double,double,int,int)" (?drawSprite@Block@@QAEXPAUSDL_Surface@@0HHHHNNHH@Z) referenced in function _SDL_main 1>D:\Mor's C++\SDL launcher\Debug\SDL launcher.exe : fatal error LNK1120: 1 unresolved externals
So... yea, I've looked all over but can't find a good solution... so can anyone help me solve this, and possibly also explain for future reference?

Share this post


Link to post
Share on other sites
Is drawSprite() a member function of Block? Because it is declared as such, but not defined as such (i.e., not Block::drawSprite()).

EDIT: You edited your post while I was typing. Now I'm pretty sure it's what I said above - you're declaring drawSprite() as a member function but defining it as a global free function. The definition should be:

void Block::drawSprite(...) { ... }

Share this post


Link to post
Share on other sites
In the function implementation:

void drawSprite(SDL_Surface *string, SDL_Surface *screen,
int srcx, int srcy, int srcw, int srch,
double destx, double desty, int destw, int desth)


should infact be


void Block::drawSprite(SDL_Surface *string, SDL_Surface *screen,
int srcx, int srcy, int srcw, int srch,
double destx, double desty, int destw, int desth)


EDIT: Too slow =)

Share this post


Link to post
Share on other sites
Quote:

I'll spare you the details around this as they would take alot of reading and aren't really all that important, and jump right into the problem.

For future reference, it's worth noting that you can rarely make this judgment correctly -- that a particular piece of code isn't worth showing because it's 'not relevant' to the problem -- unless you know what the source of the problem is. And, almost by definition, if you know what the problem is, you don't generally need to ask for help.

Posting more of what you deemed unnecessary would have allowed for people to respond with a more definitive answer they could be more sure of, rather than initially just speculating until you happened along to edit and provide enough extra information.

It's much easier for us to wade through extra information than it is to work with too little information. A good guideline is that you should post exactly as much code as it takes to reproduce the bug, if at all possible -- this usually ensures we have enough context without you having to post you're entire multifile project, or whatever.

Share this post


Link to post
Share on other sites
class Block
{
public:
double destx;
double desty;
int destw;
int desth;
int setblock;
int pos;
bool move;

//Function call to draw a sprite.
void drawSprite(SDL_Surface *string, SDL_Surface *screen,
int srcx, int srcy, int srcw, int srch,
double destx, double desty, int destw, int desth);

};


I think you're misunderstanding a few things here.

First off, SDL draws to screen positions. Screen positions are integer, since they're a count of pixels. Why would you pass floating-point values (double) in?

Second, the point of member functions (i.e. the ones declared within a class body) is that they operate on an instance of the class. As you are hopefully aware, 'Block' is not simply storage for a few bits of data, but actually defines a data type. You can create variables of type Block as freely as you create variables of type int. That said, when you call drawSprite(), it will have to be called on a particular one of those variables; and that variable has data built into it - a 'destx', 'desty', 'destw', and 'desth'.

Consequently, it doesn't make any sense to pass those values into the function: you already have them - they are part of the object you are calling the function on.

Third, the block's "sprite" data is the source of the drawing. The screen should be the destination, because you are going to draw a Block onto the screen, and not the other way around. Thus, your member data should represent source x/y/w/h.

Fourth, it doesn't make any sense to expect the calling code (i.e. whereever it is that you create the Block and then .drawSprite() it) to know how big the block is. Knowing how big the block is, is the Block's responsibility. When you do the draw, the source and destination sizes ought to be the same. The caller should only have to specify where to draw the Block, and the Block takes care of the rest - by filling in its 'width' and 'height' for both source and destination width/height, where you create the SDL_Rects.

Although actually, depending on your situation, further reorganization might be necessary. What kinds of blocks do you have? Do they vary in size? In appearance?

Share this post


Link to post
Share on other sites
@jpetrie, well, currently, I have nearly 1500 lines of code, I find it highly unappropriate to post it all here having you go through it all to look for the error, and like you said, I could reproduce the problem, but I already knew exactly what was the source of it, yet not the answer, hence why I only posted this. But thanks, I'll do that next time.(Btw, I just editted for noticing I wrote in the wrong error, not adding info to the problem =P)

@Zahlman, Oh, wow, that's... alot of errors you've found there >< let's see to them then...
First, I've set destx and desty to doubles because I don't move them by whole numbers, I needed the speed and distance to be exact, and therefore made them move in greater accuracy.
second, yea, I've realized that, but when I did it was already a little too late, like I said above, I have around 1500 lines of code as of now, and I really don't feel like going through all of them and fixing it, it's not really effecting the usage of the code, so I guess there's no use in doing that now either.
third, maybe this isn't so obvious from the function, the source here references to the spritesheet(Hence the source for the sprite), and draws it into it's destination(The screen), where it will be shown, that's what I meant by it.
fourth, that does make sense, but I'm using tetris blocks for this, that are obviously varying in size and appearance, furthermore, the source for all of the sprites is on one spritesheet, so I do need these extra source coordinates, and obviously, move them around after being printed to the screen, hence why destx and desty are needed, the destw and desth, however, like I said before, aren't, also, I need quite alot of these blocks, so having them all with a set source position isn't the smartest thing to do, as I'll then need to make a few classes instead of a few variables.
Thanks for trying to help though.

Thanks Gage and Omid, that seemed to fix it, but now I get a new problem, it says:
Quote:
d:\mor's c++\sdl launcher\sdl launcher\main.cpp(63) : error C2761: 'void Block::drawSprite(SDL_Surface *,SDL_Surface *,int,int,int,int,double,double,int,int)' : member function redeclaration not allowed

And it points me to the line with destx, desty, destw and desth in the definition(void::drawSprite()).
Yet, how in that position, am I redeclaring the members? Aren't I'm just forward declaring them?

Share this post


Link to post
Share on other sites
Quote:

void Block::drawSprite(SDL_Surface *string, SDL_Surface *screen,
int srcx, int srcy, int srcw, int srch,
double destx, double desty, int destw, int desth);

And yes, yes I am, in fact, I haven't modified the code AT ALL since I posted this thread =\

Share this post


Link to post
Share on other sites
Your declaration, which goes inside the curly braces after "Class Block", doesn't need the "Block::" scope added to it. You only need this for method definitions (where you implement the code) that are outside of the class definition (the curly braces).

Also you can use the "source" or "code" tags for posting code, rather than the "quote" tags. See the forum FAQ.

Share this post


Link to post
Share on other sites
Yea, I realized that, I've only marked the declration outside of the class's definition and it gave me this error.
And thanks, I tried [ code ] before, but it didn't seem to work, I'll try
source


Edit: Cool, okay then, I'll use this from now on, thanks man.

Share this post


Link to post
Share on other sites
The problem is with this code you posted:


void Block::drawSprite(SDL_Surface *string, SDL_Surface *screen,
int srcx, int srcy, int srcw, int srch,
double destx, double desty, int destw, int desth);


This is a function declaration (since it has a semi-colon), but you've included the scope as if it were a function definition.

Share this post


Link to post
Share on other sites
Ok, you seem to be confused about some terms:

1. Class member function declaration:

this is the line that tells your compiler what your funcion expects as parameters and returns as results. In your case:

class Block
{
public:
double destx;
double desty;
int destw;
int desth;
int setblock;
int pos;
bool move;

//Function call to draw a sprite.
void drawSprite(SDL_Surface *string, SDL_Surface *screen, int srcx, int srcy, int srcw, int srch, double destx, double desty, int destw, int desth); // THE FUNCTION DECLARATION

};



This function declaration declares the function in the Block scope, since the declaration is inside the scope of the Block class declaration.

2. Class member function definition:

This part describes what the previously declared function actually does. In your case:


void Block::drawSprite(SDL_Surface *string, SDL_Surface *screen, int srcx, int srcy, int srcw, int srch, double destx, double desty, int destw, int desth)
{
// actual code goes here
}




Notice the Block:: scope specifier. Since we're outside the Block class declaration now, we aren't in the Block scope anymore. So we have to specify that the function we're trying to define is in the Block scope explicitly.

EDIT: code formatting

Share this post


Link to post
Share on other sites
Quote:
Original post by DestX
Yea, but the code for the function is actually in a seperate header file, all I'm trying to do here is forward declare to it.


-In general, function implementations (the actual function code) shouldn't go in header files. Do you mean .cpp file? Or are you talking about the function declaration?

-I'm not sure what you mean by "forward declare to it". Once a member function is declared in the class and the implementation is defined, there's no need to "forward declare" anything. You simply #include the header file containing the class definition in any .cpp files that use the class.

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