C++ Problems with splitting code into multiple files - c++

So, I am working on a project and decided to split the code into multiple files as it was getting too big. However, a got a compilation error. I managed to recreate the error in this simple case:
//main.cpp
#include<iostream>
#include "classa.h"
using namespace std;
int main()
{
return 0;
}
The main does nothing it just includes classa.h
//classa.h
#ifndef CLASSA_H_INCLUDED
#define CLASSA_H_INCLUDED
#include<vector>
using namespace std;
vector<int> primes= {1,2,3,5,7,11,13,17,19};
class classa
{
private:
int a;
public:
int getA();
void setA(int newA);
};
#endif //CLASSA_H_INCLUDED
The class isn't even necessary for the error to occur. However, I wanted to have something in classa.cpp
//classa.cpp
#include "classa.h"
using namespace std;
int classa::getA()
{
return a;
}
void classa::setA(int newA)
{
a=newA;
}
It gives me the following error:
obj\Debug\sources\main.o:main.cpp:(.bss+0x0): multiple definition of `primes'
obj\Debug\sources\classa.o:classa.cpp:(.bss+0x0): first defined here
The problem is that unlike here in my project I cannot use some sort of constant or a define for the global variables as they are things that can be modified by different classes.

Make primes an extern variable, and declare it in your classa.h header, but only defined it once in classa.cpp.
Currently, as your compiler told you, primes exists twice, in main.cpp and in classa.cpp. Keep in mind, #include is merely text substitution.
classa.h:
extern std::vector<int> const primes;
classa.cpp:
std::vector<int> const primes = {1,2,3,5,7,11,13,17,19};
Read more about storage class specifiers here.

If you have .cpp file in overall - then it makes sense to split into
Into .h file:
extern std::vector<int> primes;
Into .cpp file:
using namespace std;
vector<int> const primes = {1,2,3,5,7,11,13,17,19};
"using namespace std" might cause conflicts between 3rd party libraries, but this occurs very rarely - I prefer to use "using namespace std" whenever possible. But if there are conflicts - then you might want to localized "using namespace std" into your own .cpp file. (Where you control what #include's that file has).
But sometimes you might not have .cpp file at all (e.g. only local inline functions or template classes) - then you can initialize vector like this:
__declspec(selectany) std::vector<int> primes = {1,2,3,5,7,11,13,17,19};
This will instruct linker to pick up only one copy (some of them), and discard everything else. This does not play well if you want to #ifdef some of initialization, but this is not normal use case anyway.
I prefer not to use const ever, because it's always pain in neck to get const right after 2-3 level conversions. I write in function comments what is input / what is output and what should not be modified. (Because that one can change over iterations)

Related

Is it possible to add an include directive inside of a class definition?

I am currently working on a project where we have a shared set of headers. Now we want add some private fields without having to put those declarations directly in the shared headers.
Someone brought up the following:
namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#if __has_include("foo_private.hpp")
#include "foo_private.hpp"
#endif
};
}
Inside the _private.hpp headers we would then place the private fields for that class. When there are only default datatypes (int, bool, etc) this works fine(ish). But as soon as you put an include inside the _private.hpp file, for example #include everything breaks.
It is giving the following error expected unqualified-id before ‘namespace’ which as I understand is quite logical, since you're trying to define a namespace inside of a class.
Example _private.hpp file
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
Now my question is, is there any way to trick the preprocessor, or somehow get the same results with a different solution?
namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#if __has_include("foo_private.hpp")
#include "foo_private.hpp"
#endif
};
}
If that code is including a file that looks like this:
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
Then you end up with this (though in reality, the #includes themselves would resolve to the contents of <string>, etc.):
namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
};
}
Perhaps that shows your issue? You're including "string" in the middle of your class, but it needs to be included at the global namespace scope of your file.
Instead, include string at the top of the outer header, don't use include guards in the private header, and only put the body of the code you want pasted into your class into that private header. For that reason, you might not call it a ".hpp" file but something else to make it clear it's not a normal header.
Additionally, the __has_include feature seems dubious, because if your private header is missing you probably do not want it to compile to an empty class.
Worse, if you compile some translation unit that finds the header, and then compile another translation unit that does not find the private header, you will end up with two different definitions of your class, violating the One Definition Rule -- which is undefined behavior, no diagnostic required. Really nasty stuff (assuming your builds succeeds at all.)
I'm not a big fan of this kind of hiding, as it will make it hard for editors to properly show your code, to colorize and index your private header, or otherwise work with the code in a normal way. You might consider looking at the PIMPL idiom for hiding the implementation of a class in its .cpp file, so users of the header do not have to see it at all.

Why can't I just define a non-const gloabal variable in header? and if I use namespaces why do I have to declare it 'extern'?

1) I know a non-const variable is external linkage by default (it's like it's been declared as external more or less) but i don't understand why can't i define a global variable such as int glbl_a in header
//test.h
#ifndef TEST_H
#define TEST_H
int glbl_a=0; //wrong -> "multiple definition of `glbl_a`"
static int st_glbl_a=1; //ok to initialize it in header!
extern int ext_glbl_a; //ok to declare it and define it in test.cpp
#endif
//test.cpp
#include "test.h"
using namespace std;
//st_glbl_a=22; i could use st_glbl_a but it wouldn't affect st_glbl_a in main cause of 'static'
int ext_glbl_a=2; //definition of external gloabal non-const variable
//main.cpp
#include <iostream>
#include "test.h"
using namespace std;
extern int glbl_a; //declaration of glbl_a external
int main(){
cout<<glbl_a;
}
the working version for this program is the one in which I define int glbl_a=0; in test.cpp only and declare extern int glbl_a; in main before using it in output (definition in test.h is just commented, that is there's nothing about glbl_a).
2)the working version doesn't work anymore if I group all definitions/declaretions into a namespace spread onto test.cpp and test.h (MyNamespace) cause of int glbl_a in test.cpp:
//test.h
#ifndef TEST_H
#define TEST_H
namespace MyNamespace{
//extern int glbl_a;
}
#endif
//test.cpp
#include "test.h"
using namespace std;
namespace MyNamespace{
int glbl_a=0;
}
//main.cpp
#include <iostream>
#include "test.h"
using namespace std;
int main(){
cout<<MyNamespace::glbl_a; //wrong -> "'glbl_a' is not a member of 'MyNaspace'"
}
it would work only if I de-comment declaration in test.h, but why?
Problem 1
Including a header effectively pastes the included file into the including file, producing one large file that is then compiled (and, typically, promptly deleted). This means that every including file now has its very own glbl_a. The compiler is happy, but when the linker attempts to put everything together, it finds many equally valid pretenders to the name glbl_a. The linker hates this and doesn't even try to figure out what you're trying to do. It simply spits out an error message and asks that you fix the problem.
Problem 2
test.cpp and main.cpp are different translation units. They compile to produce different, completely independent objects. Neither can see what's in the other, so the fact that MyNamespace::glbl_a exists in test.cpp is lost on main.cpp. When main.cpp is compiled, the compiler builds a list of identifiers declared in the file constructed from main.cpp and all of its included headers. MyNamespace::glbl_ais never declared as of when it is first used (or after for that matter) so the compiler spits out an error message.
Uncommenting the declaration in test.h means the compiler will find MyNamespace::glbl_a in main.cpp and will allow it's use. Since MyNamespace::glbl_a is defined in test.cpp the linker can find one-and-only-one MyNamespace::glbl_a and can successfully link.
extern does not allocate storage. Instead it is a promise to the compiler that the variable being declared will be fully defined and allocated somewhere else, maybe later in the file or in another file. The variable exists, somewhere, and compilation can continue. The linker will call you out as a liar if it cannot find a definition.
More details here: How does the compilation/linking process work?
More on extern: When to use extern in C++ and Storage class specifiers
headers will be included by other files (more than one) thus if you define in header, it will be in each translation unit thus lead to "multiple definition"

C++: life-cycle of variables in namespaces

Can someone please explain to me the life cycle of a variable from a namespace? Let's say I have the following files:
file.h:
// ...
namespace variables{
int x, y;
}
file.cpp:
#include "file.h"
using namespace variables;
int main(){
...
}
What are the scopes of x and y? I ask because, in a book I was reading (C++ Primer Plus), the author recommends using namespaces inside functions, and so I thought that they are defined at the point of the using command. However, when I do this:
B.h:
class B{
// class stuff
};
namespace variables{
int x, y;
}
and then in main.cpp (main program) and B.cpp (class implementation) I add the #include "B.h" line, I get an error that I have multiple definitions of variables::x and variables::y, even though there is no using in any file. What's the deal? Am I mixing up two different concepts?
If you directly declare variables in a namespace just like you did, they will simply exist as global variables.
Thus, the rules that apply for normal global variables also apply for those ones : they will exist for as long as the program run, and you should not define them in a header file.
include.h
namespace Variables
{
extern int x;
extern int y;
}
file.cpp
namespace Variables
{
int x;
int y;
}
Writing using namespace Variables will simply allow you to access those variables by their name x and y, without having to prefix them with Variables::
Namespace has no influence on variable's lifespan, so:
namespace variables{
int x, y;
}
#include "file.h"
using namespace variables;
int main(){
...
}
What are the scopes of x and y?
These variables are global, so their life time equals to life time of the entire application.
Remember, that using namespace is simply a shortcut to writing NamespaceName:: in front of elements from this namespace.
I add the #include "B.h" line, I get an error that I have multiple definitions of variables::x and variables::y, even though there is no using in any file. What's the deal? Am I mixing up two different concepts?
Your variables are declared even if you do not explicitly import the namespace. The keyword using import namespaces or specific names within the current scope so that you don't have to prepend X:: to access a defined element.
The life span of a variable is not affected by namespaces.

using a global variable in multiple files

I have a project using cocos2d-x library that contains a lot of classes. I have a .h file contains a global vector. I want to initialize it when the program starts in an intro page class. Intro page class has a graphical surface and a loader. Then I want to use that vector in my main class. The global vector's code is like bellow:
//globals.h
#ifndef _GLOBAL_H
#define _GLOBAL_H
#include <vector>
vector<int> a;
#endif
I am using push_back in intro page class. I have used extern and static keywords. my program makes a runtime linker error and it say your vector have been declared in appDelegate class (base class of cocos2d). when I put a static keyword behind it, it don't give me that linker error but it don't work correctly.
how can I correct this error? if you have another idea instead of this one, please share it. thank you.
You should have a design like the following:
shared.cpp
vector<int> a;
shared.h
extern vector<int> a;
somewhere.cpp
#include "shared.h"
void code() {
a.push_back(10);
}
Mind that, since you are using C++, you can uses classes as namespaces to avoid cluttering the global namespace, eg:
shared.cpp
vector<int> Common::a;
shared.h
class Common {
public:
static vector<int> a;
}
somewhere.cpp
#include "shared.h"
void code() {
Common::a.push_back(10);
}
You may have multiple declarations of an object, but you should only have one definition. To accomplish this, use extern to mark the declarations and the lack of extern to mark the definition.
In your header file, do this:
extern std::vector<int> a;
In exactly one of your source code files, do this:
std::vector<int> a;

C++: Namespaces -- How to use in header and source files correctly?

Consider a pair of two source files: an interface declaration file (*.h or *.hpp) and its implementation file (*.cpp).
Let the *.h file be like the following:
namespace MyNamespace {
class MyClass {
public:
int foo();
};
}
I have seen two different practices for using namespaces in source files:
*.cpp showing practice #1:
#include "MyClass.h"
using namespace MyNamespace;
int MyClass::foo() { ... }
*.cpp showing practice #2:
#include "MyClass.h"
namespace MyNamespace {
int MyClass::foo() { ... }
}
My question: Are there any differences between these two practices and is one considered better than the other?
From a code readability standpoint, it is probably better in my opinion to use the #2 method for this reason:
You can be using multiple namespaces at a time, and any object or function written below that line can belong to any of those namespaces (barring naming conflicts). Wrapping the whole file in a namespace block is more explicit, and allows you to declare new functions and variables that belong to that namespace within the .cpp file as well
The clearest is the option you didn't show:
int MyNamespace::MyClass::foo()
{
// ...
}
It's also very verbose; too much so for most people. Since using namespace is a recipe for name conflicts, at least in my experience,
and should be avoided except in very limited scopes and places, I
generally use your #2.
Are there any differences between these two practices
Yes. #1 and #2 are examples of a using-directive and a namespace definition respectively. They are effectively the same in this case but have other consequences. For instance, if you introduce a new identifier alongside MyClass::foo, it will have a different scope:
#1:
using namespace MyNamespace;
int x; // defines ::x
#2:
namespace MyNamespace {
int x; // defines MyNamespace::x
}
is one considered better than the other?
#1 Pros: a little more terse; harder to accidentally introduce something into MyNamespace unwittingly. Cons: may pull in existing identifiers unintentionally.
#2 Pros: more clear that definitions of existing identifiers and declarations of new identifiers both belong to MyNamespace. Cons: easier to unintentionally introduce identifiers to MyNamespace.
A criticism of both #1 and #2 is that they are referring to an entire namespace when you probably only care about the definition of members of MyNamespace::MyClass. This is heavy-handed and it communicates the intent poorly.
A possible alternative to #1 is a using-declaration which includes only the identifier you're interested in:
#include "MyClass.h"
using MyNamespace::MyClass;
int MyClass::foo() { ... }
I'd like also to add that if you decide due to some reason to implement a template specialization in a cpp file and just rely on using namespace you will run into the following problem:
// .h file
namespace someNameSpace
{
template<typename T>
class Demo
{
void foo();
};
}
// .cpp file
using namespace someNameSpace;
template<typename T>
void Demo<T>::foo(){}
// this will produce
// error: specialization of 'template<class T> void someNameSpace::Demo<T>::foo()' in different namespace [-fpermissive]
template<>
void Demo<int>::foo(){}
Otherwise if you apply #2 method this will be fine.
I'd like to add one more way, using a using-declaration:
#include "MyClass.h"
using MyNamespace::MyClass;
int MyClass::foo() { ... }
This saves you from typing the namespace name many times, if a class has many functions.
I think the practice #1 is not correct C++ code at all. This code snippet defines ::MyClass::foo symbol, where the real full qualified name is ::MyNamespace::MyClass::foo.
To learn about namespaces you can read section 7.3 of the draft let's say for standard http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3690.pdf
This concept is pretty old from 1998 or so, so you can use any standard or books of B.Stroustroup to learn about it.
In C++ language the namespace is a named scope. The namespace, as opposed to the class definition, is open to adding new functions to it.
The construction "using namespace NS;" in C++ is called as using-directive, and it can be used for several goals in my practice:
You can use this directive in another namespace to combine(mix) names from a different namespace.
In the context of the compilation unit it appends synonyms to all variables in namespace NS.
To define symbol, you can use two mechanisms -
you can use the explicit qualification with all namespaces via operating in global namespace in C++ source file.
Or You can open namespace and add definitions to it (practice #2).