C++ global pointer shared by different files - c++

So I am trying to make a C++ / OpenGL program (using Visual Studio 2010) that deals with Keyboard Input using a class called Operation. The point is to learn a few things since I'm new to both C++ and OpenGL.
I'm using an array 'bool keysDown[256]' to store which keys are pressed. Likewise I want to make an array of operations 'Operation *keyOps[256]', to operate those keys.
And here comes my problem, most of those keys will have no operation so I want an Operation class that will do absolutely nothing, but I only need one global instance/pointer that different files can use.
Now what I wanted to do, was to somehow create a single instance of this 'no operation' class and make it usable in any files that include this header without needing to declare it in each file. (Something like NULL, only in the shape of an Operation class)
So far my 'solution' was to use a namespace like this,
(operation.h)
#ifndef _OPERATION_H
#define _OPERATION_H
#include <iostream>
#include <GL\glut.h>
namespace operations{
class Operation{
protected:
std::string _name;
public:
Operation(std::string name) : _name(name){}
virtual void operate()=0;
std::string getName(){return _name;}
};
(...)
class OPnop: public Operation{
public:
OPnop(): Operation("No operation"){}
void operate(){}
};
static OPnop OPNOP;
Operation* nop(); //implemented in .cpp > {return &OPNOP;}
(...)
};
#endif
Other files can get a pointer to the OPNOP instance by using the operations::nop() function. I've tested and it works, but I'm not sure this works as intended in the background.
I have been searching for extern and static usage on global variables, but I probably didn't understand it all and I didn't find an answer I could relate to my problem. If I'm not mistaken extern variables have to be declared in other files too while static creates a different variable for each file including it.
So my question is, is there a way to declare/instantiate this 'no operation' so that all the files including this header will have access to the same unique instance directly without having to use a function?

Indeed the static keyword has a different meaning in the namespace context than the class context. I believe what you want to do is declare it as extern in your header, and in the implementation (.cpp) file initialize it once. Take a look at this question.

I did something similar here.
I'm using a Gesture class with a single global instance as gGesture to handle all the user interactions.
// .h file
struct Gesture_{
int fingers;
int taps;
eGestureAction action;
bool continious;
};
typedef struct Gesture_ Gesture;
extern Gesture gGesture;
To answer your question on static vs extern, the extern avoids linker problems by not adding same symbol to all translation units.
Notes:
The code was originally intended to work in a C based project, but I think you'll get the idea.
The Gesture object is intended for Touch based devices.

Related

Scope of a static variable to several files C++ [duplicate]

Well, I'm learning C++ and never really learned how to do stuff that is not OO.
I'm trying to get a bit more experience coding in C style.
GobalInformation.h
#pragma once
#ifndef GLOBALINFORMATION_H
#define GLOBALINFORMATION_H
#include "MapInformation.h"
namespace gi {
MapInformation mapInf;
};
#endif
I would like to be able to access gi::mapInf from every header and cpp in my project. Right now I'm including globalinformation.h in every header, so I'm getting linker errors with multiple definitions.
How can I work around the problem?
In header file only do
namespace gi {
extern MapInformation mapInf;
};
In CPP file provide the actual definition.
namespace gi {
MapInformation mapInf;
};
It will work as you intend.
If you are using the MapInformation across dynamic link library boundaries you might have to link against the library that includes the definition cpp file. Also on Window you might have to use dllimport/dllexport
Be aware that having globals in multiple compilation units can easily lead to order-of-initialization problems. You may wish to consider replacing each global with a function that returns a reference. In your case, put this in one cpp file and declare it in the header:
namespace gi {
MapInformation& getMapInf()
{
static MapInformation result;
return result;
}
}
Global variables are C, but namespaces are C++. There is a good discussion on using global variables and how they can be replaced by Singleton pattern: Globals and Singletons
And here is a simple sample: CPP/Classes/Singleton
Perhaps a better solution is to create a global object that contains all your global data. Then pass a smart pointer to the classes that actually need to access this shared global data.
Example:
class GlobalData
{
public:
int ticks_;
};
//Other file
class ThatNeedsGlobalData
{
public:
ThatNeedsGlobalData(std::shared_ptr<GlobalData> globalData);
};
This will save you some trouble.
Good luck!
Here are a few things that you need to take care of while trying to use global variables the way you have used.
Ensure that all the header files that the header files that GobalInformation.h includes are also enclosed insides #ifndefs. (I could not see mapinformation.h so I assume you have done it)
Just like CPP, C compiler also does not ensure order of the initialization of variables in different translation units(different C/CPP files).
Hence declare the header file as
//GlobalInformation.h
namespace gi {
extern MapInformation mapInf;
};
In a function that you know would be called first initialize the variable. This way lazy-initialization can also be acheived in C.

How to use public static variables in C++

There doesn't seem to be a clear, concise example of real word use of a public static variable in C++ from multiple files on StackOverflow.
There are many examples showing how to use static variables in a single C++ translation unit, and many questions about the precise nature of the various uses of the static keyword, but as a programmer more experienced with C# I found it hard to scrape together what I needed to simply "have a static variable on a class and use it elsewhere" like you would in C# or Java.
Here I will try to demonstrate what I discovered in the most straightforward way. I hope that others will then improve on the answer and give more technical details for those that are interested.
SomeClass.h
In the header file for the class where we want to have a static variable, we just declare it static like we would in C# or Java. Don't try to initialise the variable here; C++ doesn't like that.
class SomeClass
{
public:
static bool some_flag;
};
SomeClass.cpp
In the cpp file for the class, we create the storage for the static variable, just like we would provide the implementation for a member function. Here we can initialise the variable. So far, this is going swimmingly!
#include "SomeClass.h"
bool SomeClass::some_flag = true;
SomeOtherClass.cpp
Here is where I ran into problems. If we try to just access SomeClass::some_flag from elsewhere (which, let's face it, is probably the reason you wanted a public static variable in the first place), the linker will complain that it doesn't know where it lives. We've told the compiler that the static variable exists, so the compiler is happy. The problem is that in this other translation unit we've never specified where that static variable is stored. You may be tempted to try redeclaring the storage, and hoping the linker resolves them both as "the some_flag I declared in SomeClass.h", but it won't. It will complain that you've given the variable two homes, which of course is not what you meant.
What we need to do is to tell the linker that the storage for some_flag lives elsewhere, and that it will be found once we try to put all the translation units together at link time. We use the extern keyword for this.
#include "SomeOtherClass.h"
#include "SomeClass.h"
extern bool SomeClass::some_flag;
void SomeOtherClass::SomeOtherFunction()
{
SomeClass::some_flag = true;
};
Voila! The compiler is happy, the linker is happy, and hopefully the programmer is also happy.
I now leave this open for a discussion on how I should not have used a public variable, could have just passed an instance of SomeClass through the 87 layers of code that's between it and the usage, should have used some feature coming in C++23, should have used boost::obscurething etc. etc.
I do however welcome any alternative approaches to this fundamental problem that are true to the usage I've demonstrated here.
Here is where I ran into problems. If we try to just access SomeClass::some_flag from elsewhere [...], the linker will complain that it doesn't know where it lives.
The linker won't complain, as long as you link with the translation unit that defines the variable (SomeClass.cpp).
extern bool SomeClass::some_flag;
This declaration is neither allowed, nor is it necessary. The class definition that contains the variable declaration is sufficient for the compiler, and the variable definition in SomeClass.cpp is sufficient for the linker. Demo
Don't try to initialise the variable here; C++ doesn't like that.
I do however welcome any alternative approaches to this fundamental problem
You could simply use an inline variable (since C++17):
class SomeClass
{
public:
inline static bool some_flag = true;
The answer, in summary form, for people who just want the code so they can get back to work:
SomeClass.h
#pragma once
class SomeClass
{
public:
static bool some_flag;
};
SomeClass.cpp
#include "SomeClass.h"
bool SomeClass::some_flag = true;
SomeOtherClass.cpp
#include "SomeOtherClass.h"
#include "SomeClass.h"
extern bool SomeClass::some_flag;
void SomeOtherClass::SomeOtherFunction()
{
SomeClass::some_flag = true;
}

C++ header cannot be included without LNK2005 error

I have a large project which is designed to control and test hardware.
There are 4 device control classes (for interferometers, a piezo-motor, a PXI system, and a nano-positioning controller).
I created a "master" class called MainIO which stores an instance of each of the above classes, in order to perform operations across the range of IO (i.e. move motor and check interferometers). The MainIO header file includes the 4 control classes headers.
I then have a separate "global" hpp/cpp which contains global variables, conversions, ini file operations and so on. This is laid out with namespaces for the types of operation rather than creating a class, i.e. GCONV::someFunction(); and GMAIN::controllerModel;
I need all 4 control classes to have access to conversion and other global operations. I had them all including global.hpp at one point, but I've changed something (I can't think what it could be!) and now it seems that I cannot include global.hpp in ANY of my control class hpp's or cpp's without getting a linker error -
global.obj:-1: error: LNK2005: "class QString GMAIN::controllerModel" (?controllerModel#GMAIN##3VQString##A) already defined in controllers.obj
I'm absolutely certain that I've done something stupid and the solution is staring me in the face, but it's got to the stage where I'm getting so frustrated with it that I cannot see the wood for the trees.
I have discovered what I was doing wrong, and although it is frustratingly simple, it took me a while to find the relevant documentation to discover my error, and so I will answer my own question in the hope of giving someone else an easier time.
It turns out that in global.hpp I was declaring variables within a namespace like this:
namespace GMAIN {
QString controllerModel;
}
Essentially this means that every file that includes global.hpp will include its own definition of QString controllerModel thereby throwing the linker error. Each control class would have its own definition of the same named variable, violating the one definition rule.
To fix this, QString controllerModel needs to be extern'ed. The extern keyword allows a variable to be declared in multiple locations while only having a single definition (and hence not breaking the rule).
So the working code is now:
//in global.hpp
namespace GMAIN {
extern QString controllerModel; //declaration - this is called for each `#include global.hpp`
}
//in global.cpp
namespace GMAIN {
QString controllerModel; //definition - only called once as .cpp is never included
}
Are you defining controllerModel where you should only be declaring it?
http://www.cprogramming.com/declare_vs_define.html
You should export your dll.
Use __declspec(dllexport). You can include __declspec(dllexport) as a macro in your header file and put the macro in the beginning of each and every member function.
For example:
In your Header.h file include
#define MYMACRO __declspec(dllexport);
and in your class
class classname
{
public:
MYMACRO void MYFUNCTION();
MYMACRO void MYFUNCTION2();
};

C++ What might cause unresolved external errors in he link process when using static members of a class?

I made a program that has a class with static-only members in it in its own dedicated cpp/h file combo. The probably is that when I try to use these static members in my code, I'm getting "unresolved external" errors at the linker stage. I am remembering to include the h file in my cpp file that is getting the errors. I don't understand. Is this the wrong design approach to take?
Basically i want some global objects that are part of a third party API to be available to my whole program, so I organized everything into one class and made everything a static member. I also made an empty private constructor to keep the class from being instantiated. Is this a sensible approach? The static members are all pointers and I tried to start out by allocating new objects and attaching each to the static poonters. Is here a problem with this approach?
Thanks!
Are you remembering to actually define the variable somewhere, instead of just declaring it in the header?
Foo.hpp:
#ifndef FOO_HPP
#define FOO_HPP
class Foo {
public:
static int bar;
};
#endif
Foo.cpp:
#include "Foo.hpp"
int Foo::bar; // <-- This being the critical line.
If you are accessing global objects in a third-party library, you need to make sure you are linking with that library. Just compiling against the headers for the library won't do it.

Class Definition Instance Instantiation Question

I have a class imgmanager that allows me to load all my images exactly once, it's quite nice, and while prototyping I had all of my files in one place, so I didn't have to worry about cyclical definitions. However after separating all of my classes I have a problem.
My Header File
#ifndef IMAGEMANAGER_H
#define IMAGEMANAGER_H
#include "Img.h"
#include <vector>
#include <map>
#include <string>
class imgmanager{
protected:
std::vector<sf::Image*> images;
std::map<std::string,int> positions;
public:
sf::Image* addimg(std::string path); //relative to resources
sf::Image* getimg(std::string path);
int size();
virtual ~imgmanager();
sf::Image* operator[](int);
}imagemgr;
#endif
With the instance created after the } and before the ; my compiler complains at me:
So I ask: What should I do to have a global instance of my imagemgr class? Should I just make a global header file and create an instance? (in this particular case I can just make a global variable in my main.cpp, none of the headers require the instance)
Don't create object instances in headers.
Create your object instance in one source file.
If you need to access it across multiple Translation Units, put this in your header:
extern imgmanager imagemgr; // declaration
This will inform all code that can "see" the header that there exists a so-named object; but it will still only actually be defined in the one source file where you wrote:
imgmanager imagemgr; // definition
(This is analogous to the way in which you declare functions in a header, but define them in precisely one source file:
void f(); // declaration
void f() { ... } // definition
)
The above general advice dutifully imparted, I would now question the rationale of having a class at all if you're only going to use one, single, global instance of it. Either make it a "singleton" class, or use free functions in a namespace instead.
If you require a single global instance, i suggest you make the ImageManager a "Singleton".
I'm unsure what to do for complex types, but for a global declaration of a simple data-type you should declare the variable "extern" in the header, and instantiate it in exactly one module (.cpp file).