# 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.

## 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;

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 on other sites
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 on other sites
.cpp file

Image* Button::upImg = 0;
Image* Button::downImg = 0;
Image* Button::hoverImg = 0;

int Button::divLeft = 0;
int Button::divRight = 0;

##### 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 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 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 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 filesinline 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.hvoid drawImage(Image* img, int x, int y);etc.// Graphics.cppvoid 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 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 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 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 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 on other sites
Quote:
 Original post by XTAL256like 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 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 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 on other sites
Quote:
 Original post by SiCraneIn any case, are you sure that you defined the original function in the same namespace that you declared it in?

##### Share on other sites
Quote:
 Original post by XTAL256I 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 on other sites
Quote:
 Original post by XTAL256like 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 definedOk, 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 on other sites
Quote:
 Original post by smitty1276Why 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 functionsinline void beginList(GLuint &id) { id = glGenLists(1); glNewList(id, GL_COMPILE); }inline void endList() { glEndList(); }inline void callList(GLuint id) { glCallList(id); }// Drawing functionsvoid 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.hnamespace 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 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 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 on other sites
The '::' isn't for resolving namespaces it is for resolving scope issues, of which namespaces are one possible application. Classes are another. Scope Resolution Operator.

##### Share on other sites
Yes but why can i say
using namespace gui;void Button::draw() {}

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 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 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.hinline 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.hinline 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?