• Advertisement
Sign in to follow this  

problem with 'static' in class

This topic is 3576 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

This may sound like a n00bish question but i get "LNK2001: unresolved external symbol" errors in MSVC when i use static variables in classes. Here is some of my code:
class Button : public Component {
public:
    // Images used for all objects of this component.
    static Image *upImg, *downImg, *hoverImg;
    static int divLeft, divRight;
    static void loadImages();

    GLuint dlUp, dlHover, dlDown;  // OpenGL display lists

	Button() {}
    Button(String text, int x, int y, int w = 150, int h = 50);

    void draw();
	void update();
};

and i get these erros:
ComboBox.obj : error LNK2001: unresolved external symbol "public: static int gui::ComboBox::divBoxTop" (?divBoxTop@ComboBox@gui@@2HA)
ComboBox.obj : error LNK2001: unresolved external symbol "public: static int gui::ComboBox::divSelRight" (...)
ComboBox.obj : error LNK2001: unresolved external symbol "public: static class allegx::Image * gui::ComboBox::upImg" (...)
ComboBox.obj : error LNK2001: unresolved external symbol "public: static class allegx::Image * gui::ComboBox::downImg"
... etc.
any help? thanks

Share this post


Link to post
Share on other sites
Advertisement
When you declare a static variable in a class, you still need to allocate storage for it. In your case you'd need to put:

int Button::divLeft;
int Button::divRight;
// etc.

in one source file at namespace scope (not inside another class or a function).

Share this post


Link to post
Share on other sites
Ok, thanks. What about static functions? My graphics functions such as drawImage are not static (and not in a class) but i get link errors. If i make them static (declaration not definition) i get:

C:\...\VC\include\xlocnum(235) : error C2129: static function 'void allegx::drawImage(allegx::Image *,int,int,int,int,int,int,int,int)' declared but not defined
c:\...\allegx\Graphics.h(30) : see declaration of 'allegx::drawImage'

Share this post


Link to post
Share on other sites
You need to be linking to whichever lib has the drawImage function in it. If you can post the code that produces that error maybe we can get a better feel for the problem.

Share this post


Link to post
Share on other sites
Using my super psychic powers assisted by a magic eight ball I've determined that the link error you were getting was LNK1285: Redundant cheese error. This is commonly caused by ordering a cheese lover's pizza with double extra cheese and leaving a slice overnight on the plate on the computer case. I suggest washing the case gently with soapy water and drying with a soft cloth. Also consider not using your case as a convenient flat surface.

If this isn't the problem you might want to post the actual error and maybe the code you were having problems with.

Share this post


Link to post
Share on other sites
Alright, Alright, there's no need for sarcasm :) I assumed the problem was similar to my first, i'm used to programming in Java where static (or any) declarations and definitions are not separate i.e. Java doesn't have header files.
My graphics functions are not in a different lib, they are just in another source file. I create a display list for each GUI component:

// in Button class
createComponentDL(dlUp, upImg, x, y, width, height);
...
// in gui.h which is included with .cpp files
inline void createComponentDL(GLuint &id, Image* img, int x, int y,
int width, int height, int divLeft, int divRight) {
beginList(id);
drawImage(img, x, y, ...);
endList();
}


And my graphics code:

// Graphics.h
void drawImage(Image* img, int x, int y);
etc.

// Graphics.cpp
void drawImage(Image* img, int x, int y) {
...
}
etc.


refer to my previous post for my question. please ask if you have any more questions about my code.

Share this post


Link to post
Share on other sites
And the actual linker error? Unless, of course, it was actually a redundant cheese error, in which case follow the above suggestion.

Share this post


Link to post
Share on other sites
like i said above, see my previous post. The error was:
C:\...\VC\include\xlocnum(235) : error C2129: static function 'void allegx::drawImage(allegx::Image *,...)' declared but not defined

Ok, well that's what i got when i made 'drawImage' static. If i don't have it static i get unresolved symbol error.

Share this post


Link to post
Share on other sites
You aren't showing us something... the error you pasted clearly shows it defined as allegx::drawImage. The snippet you posted for the declaration and definition only show drawImage. It would appear--again, without enough information--that your declaration in the header has the function in the allegx namespace, but the definition doesn't.

Share this post


Link to post
Share on other sites
Ok, well i omitted some stuff to avoid explaining the entire structure of all my classes and stuff. My graphics stuff is in namespace 'allegx' (my wrapper around Alegro) and my GUI stuff is in namespace 'gui'. I don't think i have made any errors using the namespaces and unless a namespace error can cause a link error then i don't think that's the problem.
If i have some functions in a cpp file and not in a class (i.e. my graphics functions) do i have to make them static. I noticed that i had to make other functions static so i didn't get multiple symbols during linking but that didn't happen in this case.

Share this post


Link to post
Share on other sites
Quote:
Original post by XTAL256
like i said above, see my previous post. The error was:


Let's see here. You say that there was a linker error when you didn't have the static keyword, but only mention the compiler error that occurs when you add the static keyword. MSVC error codes starting with a C are compiler errors, not linker errors. Therefore you hadn't actually posted the original linker error.

In any case, are you sure that you defined the original function in the same namespace that you declared it in?

Share this post


Link to post
Share on other sites
Quote:
Original post by XTAL256
don't think i have made any errors using the namespaces and unless a namespace error can cause a link error then i don't think that's the problem.


I don't know what you mean by a "namespace error", but if you declare a function allegx::drawImage and then only implement a function called drawImage, the linker will correctly complain that allegx::drawImage isn't defined. It's called a namespace because it becomes part of the typename... it absolutely can cause linker programs.

No offense, but you might want to be a bit less dismissive of or impatient with our questions and advice. We're trying to help you here with basically zero information to work from.

Also, your error message is referring to a function 'void allegx::drawImage(allegx::Image *,int,int,int,int,int,int,int,int)', but your code snippets only show 'void drawImage(Image*, int, int)', so the dclaration and definition snippet you posted is completely unrelated to the problem.

Quote:
If i have some functions in a cpp file and not in a class (i.e. my graphics functions) do i have to make them static. I noticed that i had to make other functions static so i didn't get multiple symbols during linking but that didn't happen in this case.

'static' makes no sense in reference to a function that isn't a class method, so no. You should just have to have a declaration that is visible to your source code, and an implementation that is linked.

Share this post


Link to post
Share on other sites
@SiCrane: sorry, you're right. I posted the same error twice! I'm getting a bit confused here.
I try to omit irrelevant details like the number of function arguments (because i know i got that right) by saying something like allegx::drawImage(allegx::Image *,...) where ... is the rest of the arguments. But, yes, i did forget to do that once smitty.
I think i have probably done something wrong somewhere, i always manage to do something wrong. It's not that i'm a n00b, i'm just used to programming in Java where you don't have to worry about header files. I guess i'll figure it out eventually.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
In any case, are you sure that you defined the original function in the same namespace that you declared it in?


Share this post


Link to post
Share on other sites
Quote:
Original post by XTAL256
I try to omit irrelevant details like the number of function arguments (because i know i got that right) by saying something like allegx::drawImage(allegx::Image *,...) where ... is the rest of the arguments.


But those aren't irrelevant details. Those are exactly the sort of details that are probably causing your problem.

As I said before--as as SiCrane seems to be hinting rather conspicuously [grin]--your problem is most likely that you declared the function inside of the namespace, but defined it without the namespace.

Why don't you just post your code?

Share this post


Link to post
Share on other sites
Quote:
Original post by XTAL256
like i said above, see my previous post. The error was:
C:\...\VC\include\xlocnum(235) : error C2129: static function 'void allegx::drawImage(allegx::Image *,...)' declared but not defined

Ok, well that's what i got when i made 'drawImage' static. If i don't have it static i get unresolved symbol error.


Well according to this error drawImage has definately been declared in the allegx namespace, but have you made sure that its definition counterpart is also in the allegx namespace?

Share this post


Link to post
Share on other sites
Quote:
Original post by smitty1276
Why don't you just post your code?

Alright, if you are willing to look through it all. I will, however, only include the code for which i get the errors. i.e. there is no need for me to include all the graphics initialisation code that is in the function. :)

// ballistic/Ballistic.h
#ifndef _BALLISTIC_H_
#define _BALLISTIC_H_

#include <windows.h> // Use <winalleg.h> if <allegro.h> is included
#include <sstream>
#include "utils/utils.h"
#include "resource.h"

#define ALLEGRO_STATICLINK
#include "allegro/timer.h"
#include "allegro/sound.h"
//#include <allegro.h> // This is how it's done for Windows but i
//#include <winalleg.h> // only need timer and sound

#include "graphics/graphics.h"
#include "sound/sound.h"
#include "thread/Thread.h"
#include "thread/Timer.h"
#include "gui/gui.h"

static bool fullscreen;

void initWindow(bool fullscreen=true, int width=800, int height=600);
void destroyWindow();
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR cmdLine, int wndState);

#endif // _BALLISTIC_H_

// graphics/graphics.h
#ifndef _GRAPHICS_H_
#define _GRAPHICS_H_

#include <gl/gl.h>
#include "Image.h"
#include "Animation.h"
#include "Colour.h"
#include "Font.h"

namespace allegx {

void initGraphics();
void shutdownGraphics();

// Wrapper functions around OpenGL's display list functions
inline void beginList(GLuint &id) { id = glGenLists(1); glNewList(id, GL_COMPILE); }
inline void endList() { glEndList(); }
inline void callList(GLuint id) { glCallList(id); }

// Drawing functions
void drawLine(int x1, int y1, int x2, int y2);
void drawRect(int x, int y, int w, int h);
void drawImage(Image* img, int x, int y);
void drawImage(Image* img, int x, int y, int w, int h,
int wrapX = IMG_STRETCH, int wrapY = IMG_STRETCH, float angle = 0.0f);
void drawImage(Image* img, int x, int y, int w, int h,
int imgX, int imgY, int imgW, int imgH);
} // namespace allegx

#endif // _GRAPHICS_H_

// graphics/Graphics.cpp
#include "ballistic/Ballistic.h"
using namespace allegx ;


/* Intialise the graphics routines internally */
void initGraphics() {
}

/* Shutdown the graphics routines internally */
void shutdownGraphics() {
}

void drawImage(Image* img, int x, int y) {
}

void drawImage(Image* img, int x, int y, int w, int h,
int wrapX, int wrapY, float angle) {
}

void drawImage(Image* img, int x, int y, int w, int h,
int imgX, int imgY, int imgW, int imgH) {
}

// drawAnim, etc

// gui/Button.h
namespace gui {

class Button : public Component {
public:
// Images used for all objects of this component.
static Image *upImg, *downImg, *hoverImg;
static int divLeft, divRight;
static void loadImages();

GLuint dlUp, dlHover, dlDown;

Button() {}
Button(String text, int x, int y, int w = 150, int h = 50);

void draw();
void update();
};

} // namespace gui

#endif // _GUI_BUTTON_H_

// gui/Button.cpp
#include "ballistic/Ballistic.h"
using namespace gui;


Image* Button::upImg = NULL;
Image* Button::downImg = NULL;
Image* Button::hoverImg = NULL;
int Button::divLeft = 0;
int Button::divRight = 0;

Button::Button(String text, int x, int y, int w, int h) {
this->text = text;
this->x = x; this->y = y;
this->width = w; this->height = h;
this->state = BUTTON_UP;
update();

}

/* Updates the component's image when one of it's properties changes */
void Button::update() {
drawImage(upImg, x, y);
}

void Button::draw() {
// Not done yet
}

void Button::loadImages() {
// Not done yet
}




I think that's all. I haven't implemented anything else (except WinMain) so the functions have nothing in them

Share this post


Link to post
Share on other sites
Yeah, it's exactly what we've been telling you... you are declaring it inside of the namespace, but defining it without the namespace. You can't simply put a "using namespace blah" statement in front of it like you are doing. If that were possible, your Button.cpp file would just have a "using namespace Button;" at the top and would omit the "Button::" in front of method names. The problem with that, of course, is that you would then be unable to define those function names in the global namespace... you would be implicitly tainting a different namespace (which defeats the purpose of namespaces) so that is why its illegal.

Examples...


namespace allegx
{
void initGraphics();
}

using namespace allegx;

// **** This defines ::initGraphics, not allegx::initGraphics ***
void initGraphics() {
}






Fix it by including the namespace, just like you do in the class definitions..

namespace allegx
{
void initGraphics();
}



// **** This defines allegx::initGraphics ***
void allegx::initGraphics() {
}






EDIT: Here is some info from the MSDN page for the using declaration:
Quote:
When a using declaration is made, the synonym created by the declaration refers only to definitions that are valid at the point of the using declaration. Definitions added to a namespace after the using declaration are not valid synonyms.
You are employing the using directive, but the rules and the logic behind them still hold.

[Edited by - smitty1276 on April 2, 2008 3:47:03 AM]

Share this post


Link to post
Share on other sites
Oh ok, well like i said, i'm used to Java. I didn't know there was a problem with namespaces. I say "using namespace gui" at the top of Button.cpp but i thought that "Button::" was refering to the class Button. See that's what i'm confused about, you use "blah::blah" to resolve namespaces as well as classes. So since i don't do "gui::Button::draw()" (and i don't have to do i?) so since my graphics functions aren't in a class called Graphics then i assumed that i didn't have to put "graphics::" before it.
I have read the info on MSDN before but i still don't really understand. I will read up more on namespaces.
yay, it compiles! thanks

Share this post


Link to post
Share on other sites
Yes but why can i say

using namespace gui;

void Button::draw() {
}

instead of

using namespace gui;

void gui::Button::draw() {
}

but i have to say

using namespace graphics;

void graphics::drawImage(...) {
}

I understand that drawImage needs to be defined within the 'graphics' scope but what about my gui example, i specify Button scope but it doesn't seem to need gui scope.

Share this post


Link to post
Share on other sites
Because the only valid way that
void Button::draw() {

}


can make sense is if it refers to an existing function named draw.

If you have:

namespace Button {
void draw();
};
namespace gui {
namespace Button {
void draw();
}
}
using namespace gui;
void Button::draw() {}

what happens? :)

Using namespace tells the code to look there after looking locally. namespace foo { ... } does what you are describing.

Share this post


Link to post
Share on other sites
I have another problem. Everything compiles ok but my static objects (static Image *upImg, *downImg, *hoverImg;) don't seem to be created.
I read them from an XML file:

void Button::loadImages() { // Defined in Button as 'static void loadImages()'
XMLNode* node = readXML(UI_XML);
node = node->getChild("button"); // Get <button> element

XMLNode* child;
for (int i = 0; child = node->getChild(i); i++) {
if (!strcmp(child->getType(), "img")) {
getImageFromXML(child, Button::upImg, "up");
getImageFromXML(child, Button::hoverImg, "hover");
getImageFromXML(child, Button::downImg, "down");
}
if (!strcmp(child->getType(), "div")) {
getDivFromXML(child, Button::divLeft, "left");
getDivFromXML(child, Button::divRight, "right");
}
}
}

// In gui.h
inline void getImageFromXML(XMLNode* node, Image* img, char* id) {
if (!strcmp(node->getAttribute("id"), id))
img = new Image(node->getAttribute("file"));
}




Then create an OpenGL display list from the images:

void Button::update() { // 'void update()', virtual in Component
// Create display lists to draw each image
createComponentDL(dlUp, Button::upImg, x, y,
width, height, Button::divLeft, Button::divRight);
createComponentDL(dlHover, Button::hoverImg, x, y,
width, height, Button::divLeft, Button::divRight);
createComponentDL(dlDown, Button::downImg, x, y,
width, height, Button::divLeft, Button::divRight);
}

// In gui.h
inline void createComponentDL(GLuint &id, Image* img, int x, int y,
int width, int height, int divLeft, int divRight) {
float ratio = height/img->height;// Ratio of img to component size
int posL = divLeft*ratio; // Position of divLeft on component
int posR = divRight*ratio; // Position of divRight on component
createList(id);
// Draw left edge of image
drawImage(img, x, y, posL, height, 0, 0, divLeft, img->height);
// Draw middle section of image
drawImage(img, x + posL, y, width - posL - posR, height,
divLeft, 0, img->width - divLeft - divRight, img->height);
// Draw right edge of image
drawImage(img, x + width - posR, y, posR, height,
img->width - divRight, 0, divRight, img->height);
endList();
}




The problem is that it crashes on the line "float ratio = height/img->height" saying that 'img' is not defined. When i click 'Add Watch' it says that the variable is out of scope. I reference it as Button::upImg and i get no compile errors so i don't get it. And the images are being created in getImageFromXML because they are not NULL.

EDIT: i just found out that if i directly substitute the code in getImageFromXML to where it is used, it works! But why? Am i not passing the Image pointer right?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement