What if I declare a class variable as extern so that it can access some global variable declared in some other file? Does such a scenario come up anytime or is it just a hypothetical case?
Lets say I have a header file global.h
extern int myglobalint;
and I have a cpp file my.cpp
Here I declare a class A
class A{
//use that variable here....is it possible
}
Yes it comes up from time to time, particularly in messy code. :D
Perhaps a more C++-like style would be to keep these kinds of variables together in a class, eg in global.h:
class Global { // You can do this with 'struct' & omit 'public'
public:
static int myglobalint;
};
And in global.cpp:
int Global::myglobalint = 0xbeef;
There's really no advantage doing it with an extern or class members - but unless it's some kind of global setting or flag, if you're resorting to storing state globally you probably need to put some thought into your design.
If you really do need global variables, for example, state or configuration that really has no other place to live, I would choose the class-static approach over a mess of extern's.
Related
I'm writing a library which is totally base on templates, so I don't have any cpp files. Now I want to declare an global variable, then I realize I have nowhere to go.
If I simply declared it in header, I will got a "multiple definition" error, if I use extern, I have to create a cpp file to really declare it.
So is there any way I can declare a global variable in header?
P.S. since a static member in a template class can (only) be declared in header, how it works?
You can use macro to for single declaration,
#ifndef __usermacro
#define __usermacro
//Declare global variable
#else
//Declare extern
#endif
As #M.M mentioned, you can use inline declaration if you're on C++17 or above.
Hovever, if that's not the case, you can declare inline function which returns a reference to static variable, just like that:
inline int& getData() {
static int data;
return data;
}
Then, in your .cpp file (as well as in any function body inside your headers) you can simply call it like int& data = getData().
As a side note, if you want to ensure that global object is created only once and is not copied by accident, it could suit you better to use a signleton instead. Global variables are more of a c-style and not really considered a good practice in c++.
For constants of a class, should I use class scope static const, or file scope const?
For example:
// .h
class C {
private:
static const int some_constant_c;
}
// .cc
const C::some_constant_c = 10;
vs.
// .h
class C {
}
// .cc
const some_constant_c = 10;
To me, the former one have better semantic meaning that the constant is of a certain class, but the latter one have the advantage not exposing constants to header file.
==============
One follow up question on this:
What if I want my constants be accessed by subclasses. Make sense to put static const in protected? Example follows:
// .h
class C {
protected:
static const int some_constant_c;
}
It's a matter of personal preference, of course. Trying not to expose class internals in the header file is a ship that has most definitely sailed in C++... between member variables and private member functions, it's just not practical to keep implementation details out of the header (unless you're using the pImpl idiom).
If all you want is to hide the value of the constant, note that you can put the initializer in the source file instead.
If you do implement the constants as globals in the source file, use an anonymous namespace to keep them from causing linker collisions.
I'd prefer 2nd variant, provided the const in the 1st case is private.
Why should one pollute the class declaration with redundant information?
Consider, you are implementing a protocol parser, with many many constants. How will the class declaration look like?
Another issue is, why should you type the name of the const twice? I try to keep definition and initialization as close as possible.
Just an opinion.
What I want is a class that contains objects and variables that can be accessed by any other class without needing to create an object of that class or get a reference to that object from the class that creates it. I know that in Java a could just create a static class that would do this but it doesn't seem like static classes exist in C++. How can I accomplish this?
Let me clarify further exactly what I'm looking for.
Say I have a class called "mob" which on update, seeks out the player and moves toward him. I could do this by putting a reference to the player in the update function of the mob, or better yet just create a pointer in the mob class that is assigned to a reference of the player on initialization. However, what I really want is to just be able to include a header like "Global.h" and put the player in there. Then when the mob, or any other object in the program wants to get some data from player, it can just use something like Global.player.GetPos()
Or maybe this is terrible practice that I should forget about right now. In which case, please tell me a better way to do this whole thing. Thanks.
You could ether use a singleton pattern (you can find those alot everywhere, like Neil Kirk mentioned in his comment above), or, if you don't need object-oriented mechanics (like inheritance or polymorphy), I personally grew accustomed to just using simple functions instead of a class.
Mob.hpp
#ifndef MOB_HPP
#define MOB_HPP
namespace Mob {
// "public" functions and variables
extern int someVariable;
extern void moveTowards(Player* player);
extern void retreat(void);
}
#endif
Mob.cpp
#include "Mob.hpp"
// "private" functions and variables
static long _lastUpdate;
static void seekOut(Player* player) {
//...
}
// "public" function implementation and variables
namespace Mob {
int someVariable = 0;
void moveTowards(Player* player) {
//...
}
void retreat(void) {
//...
}
}
Usage
#include "mob.hpp"
int var = Mob::someVariable;
Mob::moveTowards(player);
The header basically defines all the public methods you would normally have in your static class. These are marked as extern so that they have external linkage and can be used in other compilation units.
In the .cpp file there some additional things marked as static. When you declare global functions or variables as static, they have internal linkage and are only visible in the unit where they are defined. So in a sense, they are private.
Some see this approach as being kinda backwards, but to be honest, when dealing with singletons without the need to actually use them as a class somehow, or get a pointer to the singleton instance, then functions are just more simple. One drawback though: If you want the mob not to be a singleton anymore, but an instanceable object, you'd have to write a class later on.
I got a little confused of the usage of static / global / global static / extern variables.
I would like a counter variable to get increased in any creation of a class instance.
Would highly appreciate if someone can post a clarification of the appropriate usage for each.
According to OO concept, you should NEVER use global static variables.
You can instead define a static variable in your class for the instance count of your class.
Make it private, so that no one else except your constructor can increase the count.
Provide a public function to get the counter. See example below:
yourclass.h:
class YourClass {
private:
static int instanceCount_;
public:
YourClass() {++YourClass::instanceCount_;} // constructor
~YourClass() {--YourClass::instanceCount_;} // destructor
static int instanceCount() {return instanceCount_;}
};
yourclass.cpp:
int YourClass::instanceCount_ = 0;
As far as the concept of static / global / global static / extern
static:
1a) global static:
A static variable created as given: static int numberOfPersons;
This kind of variable can only be seen in a file (will not have name collision with other variable having same name in other files)
1b) class static: (already has an example in the instance count above)
A class may have static members, which are visible to that class (accessed only by Class::VarName syntax) only (instead of 'file only' as said above). It will not have name collision with variables of same name in other class. It only has one copy per class (not per instance).
1c) Both global static and class static are global(since they can be globally accessed, either with class qualifier Class:: or not.
So, 1a., 1b. and 1c. partially explain static, global, and global static
Another form of global variable, is just define a variable without static
syntax: int numberOfPersons;
Without static, this variable can be seen by other file, using extern keyword. And it will have name collision with the variables having same name in other files. So, globally, you can only define it ONCE across all your source files.
extern: Declare a variable/function which is defined in somewhere else. It is normally seen in a header file. We can have some variables defined in other file, and declare this variable as extern, like below, in another source file which uses it.
extern int numberOfPersons;
int addPersonCount()
{
numberOfPersons++;
}
Hope this helps.
If I have a class in outside.h like:
class Outside
{
public:
Outside(int count);
GetCount();
}
How can I use it in framework.cpp using the extern keyword, where I need to instantiate the class and call GetCount?
Edit:
#include is not allowed.
Everyone here is a bit too gentle.
There is ABSOLUTELY NO REASON why you would not want to include the .h file.
Go for it and include the file!
Just to clarify. It is impossible to extern the class:
class Outside
{
public:
Outside(int count);
GetCount();
}
But, once you have the class available in framework.cpp, you CAN extern an object of type Outside. You'll need a .cpp file declaring that variable:
#include "outside.h"
Outside outside(5);
And then you can refer to that object in another file via extern (as long as you link in the correct object file when you compile your project):
#include "outside.h"
extern Outside outside;
int current_count = outside.GetCount();
extern is used to say "I KNOW a variable of this type with this name will exist when this program runs, and I want to use it." It works with variables/objects, not classes, structs, unions, typedefs, etc. It's not much different from static objects.
You may be thinking about forward declaring classes to cut down on compile times, but there are restrictions on that (you only get to use the objects as opaque pointers and are not able to call methods on them).
You may also mean to hide the implementation of Outside from users. In order to do that, you're going to want to read up on the PIMPL pattern.
Update
One possibility would be to add a free function to Outside.h (I've also added a namespace):
namespace X {
class Outside {
int count_;
public:
Outside(int count) : count_(count) { }
int GetCount()
{
return count_;
}
};
int GetOutsideCount(Outside* o);
}
Implement that function in a .cpp file. While you're at it, you might as well make the global variable that you intend to extern (note, the variable itself does not need to be a pointer):
#include "outside.h"
namespace X {
int GetOutsideCount(Outside* o)
{
return o->GetCount();
}
}
X::Outside outside(5);
And then do this in your program (note that you cannot call any methods on outside because you did not include outside.h and you don't want to violate the one definition rule by adding a new definition of the class or those methods; but since the definitions are unavailable you'll need to pass pointers to outside around and not outside itself):
namespace X {
class Outside;
int GetOutsideCount(Outside* o);
}
extern X::Outside outside;
int main()
{
int current_count = GetOutsideCount(&outside);
}
I consider this an abomination, to put it mildly. Your program will find the GetOutsideCount function, call it by passing it an Outside*. Outside::GetCount is actually compiled to a normal function that takes a secret Outside object (inside Outside::GetCount that object is referred to via the this pointer), so GetOutsideCount will find that function, and tell it to dereference the Outside* that was passed to GetOutsideCount. I think that's called "going the long way 'round."
But it is what it is.
If you aren't married to using the extern keyword, you can instead go full "let's use C++ like it's C" mode by adding the following two functions in the same way (i.e., via forward declarations and implementing right next to int GetOUtsideCount():
Outside* CreateOutsidePointer(int count)
{
return new Outside(count);
}
void DestroyOutsidePointer(Outside* o)
{
return delete o;
}
I'm more willing to swallow that. It's a lot like the strategy used by the APR.
You don't make classes extern. Just include "outside.h" and create an instance of Outside.
you cant extern the class, but you can extern a function that creates an instance.. In the consumer code:
class Outside;
extern Outside* MakeAnOutside(int count);
extern int GetOutsideCount(Outside* outside);
Then in outside.h:
Outside* MakeAnOutside(int count)
{
return new Outside(count);
}
int GetOutsideCount(Outside* outside)
{
return outside->GetCount();
}
but.. this may not be a good idea..
Include files are for definitions, including class definitions. extern is for variables.
If you don't have the definition of a class in a source file, about the only thing you can do with it is declare it with class Outside; and pass instances around by pointer. You can't actually do anything with the instances, including construction, destruction, or calling member functions like GetCount(). For this, you don't need extern at all; only if you want to refer to a variable in another source file, and that won't let you do anything additional with it.
There is no valid reason not to use #include here. The only alternative is to copy-and-paste the header file into the source file, and that's considerably worse. Anybody who tells you not to use #include does not understand C++, and obviously anybody who thinks extern has any relevance here certainly doesn't.
If at all possible, you should get an experienced C++ developer to help you learn, establish good coding styles, and mentor you in how to develop C++. I suspect you're doing other things that will turn out to be Bad Ideas later on.
If you had a silly requirement that #include is not allowed then you'd have to copy and paste the class declaration into your .cpp file. Need I say that'd be a very bad idea?
What is the reason for this requirement? It pains me to advise you how to do this. If you are trying to avoid long #include paths in your source files, this is a build problem not a source code problem.
You should add directories to the include path with the gcc -I option, or whatever the equivalent is for your compiler.
If you are really, really sure about this, you'd want something like this:
framework.cpp
// FIXME: Should #include "outside.h" but not allowed.
class Outside
{
public:
Outside(int count);
GetCount();
// Omitted
// void SomeUnusedMethod();
};
<code for framework.cpp here>
void UseOutside()
{
Outside o(5);
std::cout << o.GetCount() << std::endl;
}
I would then strongly recommend you leave the declaration as is so it's just straight copy-and-pasted from the header file. But if you want to trim it you can omit any non-virtual methods you don't use. You'll need to keep all variables.
I can only think of one use case where you could 'extern' a class without either #including the header or duplicating the class definition as others have suggested.
If you need to keep pointer to the class but you never dereference it directly, only pass it around, then you can do the following in your file:
class Outside;
class MyClass
{
Outside* pOutside;
void SetOutsidePointer(Outside *p) {pOutside = p;}
Outside* GetOutsidePointer() { return pOutside;}
/* the rest of the stuff */
}
This will only work if you never call pOutside->GetCount() or new Outside in your file.
Put the include for your Outside class in the StdAfx.h or any other headerfile that framework.cpp is already including.
I think you misunderstand the storage classes and one of them is the external.
"Objects and variables declared as extern declare an object that is defined in another translation unit or in an enclosing scope as having external linkage."
So marking extern is for variables not classes defination/declaration
So if you can not include the .h, I recommend you to build the .h and .cpp to be static lib or dll and use in your code
Yikes... we put classes in header files and use #include in order to duplicate class (or other) declarations into multiple cpp files (called compilation units).
If you really can't use #include, you're left with a manual copy, as suggested above, which has the obvious problem of becoming outdated when someone changes the original. That'll completely break your test code with hard to track crashes.
If you insist on going down the path of this manual copy, you do need the entire class declaration. Technically, you could omit certain bits and pieces, but this is a bad idea -- clearly your team doesn't have deep understanding of C++ constructs, so you're likely to make a mistake. Second, the C++ object model is not standardized across compilers. Theoretically even a simple non-virtual method could change the model, breaking your test.
A "long path" is really not a great reason not to include a file directly. But if you really can't, copy the entire header file in where #include would have been -- that's exactly what the C preprocessor is going to do anyway.