Consider the following:
// defs.h
extern "C" {
typedef struct t_state
{
bool b;
} t_state;
static t_state _state;
void t_state_allocate();
}
// defs.cpp
#include "defs.h"
void t_state_allocate()
{
_state.b = true;
printf("G state at %p is %d\n", &_state, _state.b);
}
// App.hpp
#include "defs.h"
class App
{
App();
};
// App.cpp
#include "App.hpp"
App::App()
{
printf("1 state at %p is %d\n", &_state, _state.b)
t_state_allocate();
printf("2 state at %p is %d\n", &_state, _state.b)
}
Output under G++ is something like:
1 state at 0x736e20 is 0
G state at 0x9cb140 is 1
2 state at 0x736e20 is 0
Here the expected behaviour is to access the same structure.. Where's the mistake ?
EDIT 1
t_state must be a pure C struct because it is used in other .c source code (and thus the extern keyword). However I can grant that nobody modifies its content.
In your code, you have two different global variables: one at App.cpp including defs.h, and the other one at defs.cpp including defs.h.
You have to use extern as you can see here:
How do I use extern to share variables between source files?
defs.h is included twice in two different .cpp files. so there are two instances of _state getting created. This is because #include essentially pastes the contents of the header into the file that includes it. So how do you get around this problem? Use extern:
typedef struct t_state
{
bool b;
} t_state;
extern t_state _state; //Tells the compiler to share the variable between files.
Now you can use the variable in each source file:
#include "defs.h"
void t_state_allocate()
{
_state.b = true;
printf("G state at %p is %d\n", &_state, _state.b);
}
Related
I am getting an error of redefinition while using extern, but I was also told, that extern variable should be used like this, why I am getting this error and how should I use extern in this case so it will work? (I can use this variable even if I don't specify it in Tab.cpp, but I am getting error of finding one or more symbols, which was defined 2 times.)
Files:
Tab.h:
#pragma once
#include "wx/wx.h"
class Tab : public wxFrame {
wxDECLARE_EVENT_TABLE();
void close(wxCommandEvent& evt);
void init();
public:
Tab();
};
Tab.cpp:
#include "Tab.h"
#include "ids.h"
#include "wx/wx.h"
int maxid;
wxBEGIN_EVENT_TABLE(Tab, wxFrame)
EVT_BUTTON(2, Tab::close)
wxEND_EVENT_TABLE()
Tab::Tab() : wxFrame(nullptr, maxid++, "ERIS 2") {
init();
}
void Tab::close(wxCommandEvent &evt) { this->Close(); evt.Skip(); }
void Tab::init() {
wxGridSizer* sizer = new wxGridSizer(10, 10, 0, 0);
for(int x = 0; x < 10; ++x)
for(int y = 0; y < 10; ++y) {
sizer->Add(new wxButton(this, maxid, _(std::to_string(maxid))), wxEXPAND | wxALL);
++maxid;
}
this->SetSizer(sizer);
sizer->Layout();
}
ids.cpp:
#include "ids.h"
std::vector<Object> ids;
Object& search(const char* name) {
for(std::vector<Object>::iterator it = ids.begin(); it != ids.end(); *++it)
if((*it).name == name)
return *it;
}
Object& search(int id) {
for(std::vector<Object>::iterator it = ids.begin(); it != ids.end(); *++it)
if((*it).id == id)
return *it;
}
void add(Object& obj) {
ids.emplace_back(obj);
}
ids.h:
#pragma once
#include <vector>
#include "wx/wx.h"
struct Object {
wxObject* obj;
const char* name;
int id;
};
Object& search(const char*);
Object& search(int);
void add(Object&);
extern std::vector<Object> ids;
extern int maxid = 0;
The line
extern int maxid = 0;
in the file ids.h is a definition, because it also initializes the variable. Instead, it should only contain a declaration:
extern int maxid;
The definition should be in a source file (.cpp), not a header file (.h). Header files should only contain declarations of variables, not definitions. Otherwise, you will violate the one definition rule if you include the header file more than once, or if you already have a definition in a source file.
In your case, you already have a definition of the variable in the file Tab.cpp. The line int maxid; is a definition, because it is not using the extern keyword. If you want to initialize the variable, you should do it in that file.
There are definitions and declarations. A declaration tells the compiler that something exists. A definition is a declaration that has all the information needed to describe that thing.
For global variables like maxid, The extern says that it will have external linkage; that is, be known to the linker and be seen between different source files (translation units).
Many different translation units can say extern int maxid; and they all just say "OK, I know about this symbol, I'll find it somewhere eventually.". So, that's fine to put in a header which becomes part of more than one translation unit.
However, when you give it an initializer, in this case the =0 (one of several possible ways describe initialization), then it becomes a definition. It causes storage to be allocated and a definite location set up for that variable. You should not do that in a header, because each file that includes it will define the same variable. Thus, at link time you get more than one, which is an error.
The legacy way of doing this is to put extern int x; in the header so that everyone knows x exists, and then put int x = 0; in one CPP file so that this variable lives somewhere. Writing extern int x = 0; would mean the same thing but is un-idiomatic.
The modern way to handle this is to use a feature created for this express purpose. Put inline int x = 0; in the header file. This will define it in every translation unit that includes it, but they will be marked such that the linker understands that they are all the same and it should just pick one and ignore the others.
extern int maxid = 0; When you assign something, this is a definition and extern becomes meanless and ignored. Remove the assignment:
extern int maxid;
You have the definition in Tab.cpp and it's assigned to zero by default as a global variable.
(Not sure whether this is exclusively a C/C++ issue)
I’m currently fragmenting elements of a large Arduino project into reusable libraries - so far soo good.
However, a number of methods in the libraries return special structs which are declared in a data-types.h file contained in each library. The problem I have now is I'm unable to import/utilise these structs in my main sketch. I've tried declaring a variable of the DataTypes class in the main library header file and accessing the structs through it, but I get error error: invalid use of 'struct DataTypes::_theStructNameHere_t'
How would I go about accessing these structs from the library in my main sketch to declare as a variable type? I don't want to have to copy the header file which contains the structs from the library into my sketch, and I also don't want to have to create a separate library just for this single header file of structs!
Here's a quick example of what I mean:
Main.cpp:
#include <Arduino.h>
#include <MyLibrary.h>
MyLibrary myLib;
void setup() {
(This is declared in the library) myLib.dataTypes._theStructNameHere_t response = myLib.getASpecialValueWhichIsOfType_theStructNameHere_t()// Gives "error: invalid use of 'struct DataTypes::_theStructNameHere_t'""
// Example usage of the struct:
Serial.print("\n Loop Card Status: ");Serial.print(response.loop_status, HEX);
if (response.number_allocated > 0) {
Serial.print("\n Devices Allocated: ");Serial.print(response.number_allocated, HEX);
} else {
if (response.loop_status != 0x123) {
// Some condition
} else {
// Something else
}
}
}
void loop() {
...
}
Library Structure:
src/
- /data-types/
- - data-types.h
- MyLibrary.cpp
- MyLibrary.h
Library Header MyLibrary.h:
#ifndef _MYLIBRARY_H_
#define _MYLIBRARY_H_
#include <Arduino.h>
#include "./helpers/helpers.h"
...
#include "./data-types/data-types.h"
class MyLibrary {
public:
Uart *_commPort;
Helpers helpers;
...
DataTypes dataTypes;
DataTypes::_theStructNameHere_t getASpecialValueWhichIsOfType_theStructNameHere_t();
...
protected:
private:
};
#endif // _MYLIBRARY_H_
DataTypes Class data-types.h:
#ifndef _RESPONSE_TYPES_H
#define _RESPONSE_TYPES_H
class DataTypes
{
public:
struct _theStructNameHere_t
{
bool successful;
uint8_t loop_status;
uint8_t number_allocated;
uint8_t highest_address;
uint8_t number_inputs;
uint8_t number_outputs;
}
..even more..
private:
}
#endif // _RESPONSE_TYPES_H
I was able to obtain a MCVE from your example:
class DataTypes
{
public:
struct _theStructNameHere_t
{
};
};
class Library
{
public:
DataTypes dataTypes;
DataTypes::_theStructNameHere_t getMyDataType();
};
int main(int argc, char *argv[])
{
Library myLib;
myLib.dataTypes._theStructNameHere_t response;
}
which gives a similar error as your code:
~$ g++ test.cpp
test.cpp: In function 'int main(int, char**)':
test.cpp:20:21: error: invalid use of 'struct DataTypes::_theStructNameHere_t'
myLib.dataTypes._theStructNameHere_t response;
The problem is that you use an instance to access the struct type/name. To fix it, replace
myLib.dataTypes._theStructNameHere_t response = ...;
with
DataTypes::_theStructNameHere_t response = ...;
Notes:
Instead of using classes to create separate namespaces, please consider using namespaces directly. This is a feature of C++ which is available under Arduino.
namespace Library {
namespace DataTypes {
struct _theStructNameHere_t
{
...
};
...
} /*** namespace Library::DataTypes ***/
} /*** namespace Library ***/
Please read StackOverflow guidelines concerning how to ask a good question, in particular the section about Mininimal, Complete and Verifiable Example.
Sooner or later someone will tell you that there is no such thing as C/C++; C is C and C++ is C++; Arduino lives in its own world, even if is based on C++. Thus, you might want to remove C and C++ tags from your question.
This question has derived from this one.
I have a working program which must be split into multiple parts. In this program is needed to use a variable (now it's a GTK+ one :P) many times in parts of the program that will end up in separated .cpp files.
So, I made a simple example to understand how to make variables available to the program parts. A modified version of the previous code would be:
#include <iostream>
using namespace std;
int entero = 10;
void function()
{
cout<<entero<<endl;
//action1...;
}
void separated_function()
{
cout<<entero<<endl;
//action2...;
}
int main( int argc, char *argv[] )
{
function();
separated_function();
cout<<entero<<endl;
//something else with the mentioned variables...;
return 0;
}
It is needed to split the code correctly, to have function(), another_function() and main() in separated .cpp files,and make entero avaliable to all of them... BUT:
In the previous question #NeilKirk commented:Do not use global variables. Put the required state into a struct or class, and pass it to functions as necessary as a parameter (And I also have found many web pages pointing that is not recommended to use global variables).
And, as far I can understand, in the answer provided by #PaulH., he is describing how to make variables avaliable by making them global.
This answer was very useful, it worked fine not only with char arrays, but also with ints, strings and GTK+ variables (or pointers to variables :P).
But since this method is not recommended, I would thank anyone who could show what would be the correct way to split the code passing the variables as a function parameter or some other method more recommended than the - working - global variables one.
I researched about parameters and classes, but I'm a newbie, and I messed the code up with no good result.
You need to give the parameter as a reference if you want the same comportement as a global variable
#include <iostream>
using namespace std;
// renamed the parameter to avoid confusion ('entero' is valid though)
void function(int &ent)
{
cout<<ent<<endl;
++ent; // modify its value
//action1...;
}
void separated_function(int &ent)
{
cout<<ent<<endl;
++ent; // modify its value again
//action2...;
}
int main( int argc, char *argv[] )
{
int entero = 10; // initializing the variable
// give the parameter by reference => the functions will be able to modify its value
function(entero);
separated_function(entero);
cout<<entero<<endl;
//something else with the mentioned variables...;
return 0;
}
output:
10
11
12
Defining a class or struct in a header file is the way to go, then include the header file in all source files that needs the classes or structures. You can also place function prototypes or preprocessor macros in header files if they are needed by multiple source files, as well as variable declarations (e.g. extern int some_int_var;) and namespace declarations.
You will not get multiple definition errors from defining the classes, because classes is a concept for the compiler to handle, classes themselves are never passed on for the linker where multiple definition errors occurs.
Lets take a simple example, with one header file and two source files.
First the header file, e.g. myheader.h:
#ifndef MYHEADER_H
#define MYHEADER_H
// The above is called include guards (https://en.wikipedia.org/wiki/Include_guard)
// and are used to protect the header file from being included
// by the same source file twice
// Define a namespace
namespace foo
{
// Define a class
class my_class
{
public:
my_class(int val)
: value_(val)
{}
int get_value() const
{
return value_;
}
void set_value(const int val)
{
value_ = val;
}
private:
int value_;
};
// Declare a function prototype
void bar(my_class& v);
}
#endif // MYHEADER_H
The above header file defines a namespace foo and in the namespace a class my_class and a function bar.
(The namespace is strictly not necessary for a simple program like this, but for larger projects it becomes more needed.)
Then the first source file, e.g. main.cpp:
#include <iostream>
#include "myheader.h" // Include our own header file
int main()
{
using namespace foo;
my_class my_object(123); // Create an instance of the class
bar(my_object); // Call the function
std::cout << "In main(), value is " << my_object.get_value() << '\n';
// All done
}
And finally the second source file, e.g. bar.cpp:
#include <iostream>
#include "myheader.h"
void foo::bar(foo::my_class& val)
{
std::cout << "In foo::bar(), value is " << val.get_value() << '\n';
val.set_value(456);
}
Put all three files in the same project, and build. You should now get an executable program that outputs
In foo::bar(), value is 123
In main(), value is 456
I prefer to provide a functional interface to global data.
.h file:
extern int get_entero();
extern void set_entero(int v);
.cpp file:
static int entero = 10;
int get_entero()
{
return entero;
}
void set_entero(int v)
{
entero = v;
}
Then, everywhere else, use those functions.
#include "the_h_file"
void function()
{
cout << get_entero() << endl;
//action1...;
}
void separated_function()
{
cout << get_entero() << endl;
//action2...;
}
int main( int argc, char *argv[] )
{
function();
separated_function();
cout<< get_entero() <<endl;
//something else with the mentioned variables...;
return 0;
}
If you do not plan to modify the variable, it is generally ok to make it global. However, it is best to declare it with the const keyword to signal the compiler that it should not be modified, like so:
const int ENTERO = 10;
If you are using multiple cpp files, also consider using a header file for your structures and function declarations.
If you are planning on modifying the variable, just pass it around in function parameters.
I am having a problem with a large project on visual studio 2005 on which I have run out of ideas.
I can't even put a working code snippet because I don't know what's related, but I will try:
I needed to make each .cpp file in my project have its own ID number, and create an instance of an object (which is globally accessible) that knows that ID.
I followed the help on the accepted answer on this thread How to manage file unique IDs in c++
and made it work in a sandbox environment.
Adding files, giving them a unique #define FILEID (FileId::ID_FileName)
and then accessing their instance works fine on the sandbox.
Now comes the trouble -
I pasted the code that makes files know their IDS to the main project, and compiled.
So far so good.
Now, I added to one of the existing .cpp files in the project:
#include "ids.h"
#define FILEID File1 // The FileId corresponding to this file
#include "global.h"
Still compiles, links, all good.
Adding these lines to a (any) second .cpp file in the project
now gives link error:
in which:
name1: 1st file I added the lines to (alphabeticcaly)
name2: other unrelated filename (which can also be the 2nd file I added the lines to, but may as well be just some other file)
The error
in name2.obj : error LNK2005: "public static class Instance & __cdecl Manager<3>::getInstance(void)" (?getInstance#$Manager#$02##SAAAVInstance##XZ) already defined in name1.obj
Some times the error is only in the second file, and sometimes (between consecutive builds without changes) the error appears on every .cpp file in the folder.
Looking in the intermediate file (the preprocessor output) on the files to which I added the lines shows exactly one appearance of the
template <>
Instance &Manager<FILEID>::getInstance()
{
static Instance theInstance = getTheFactory().getInstance(FILEID);
return theInstance;
};
with the correct FileId::ID_FileName, which is a different name than that of the other file.
Still, the linker thinks the same FileId is used in more than one file.
On unrelated files (which also give the exact same error), there is no appearance of getInstance() at all. Apparently, there shouldn't be a reason for the linker to shout there.
I checked, and no .cpp files include each other somewhere in the project.
I am completely out of ideas as to what could cause this
and would appreciate any help.
EDIT 1
ids.h
enum FileId{
ID_file1ID=3,//just to see a non zero number in the debugger, which I do
ID_file2ID,
//and so on
FileIdSize
}
EDIT 2
When these errors start, the compiler starts to behave extremely unexpectedly.
Adding the line sdfsdfgasaedfahjk to any file STILL COMPILES AND PASSES.
it clearly states the file name to which the line has been added to compiles.
It clearly states it links to it.
It passes.
I now can't trust the compiler.
No idea what's going on.
You have 2 cpp files defining the FILEID to the same value 3.
As for a MCVE:
ids.h:
#pragma once
#define File1 3
#define File2 3 //<--same value on purpose
global.h
struct Instance
{
};
struct Factory
{
Instance getInstance(int FileID) { return Instance(); }
};
template <int ID>
struct Manager
{
Factory factory;
Instance& getInstance();
Factory& getTheFactory() { return factory; }
};
template <>
Instance& Manager<FILEID>::getInstance()
{
static Instance theInstance = getTheFactory().getInstance(FILEID);
return theInstance;
};
name1.cpp
#include "ids.h"
#define FILEID File1 // The FileId corresponding to this file
#include "global.h"
name2.cpp
#include "ids.h"
#define FILEID File2 // The FileId corresponding to this file
#include "global.h"
As this compiles there is a special implementation for Manager<3>::getInstance(void) created for both name1.cpp and name2.cpp.
You can't use the same value for FILEID in 2 different compilation units.
EDIT: Check values while compiling
Requires the preprocessor definition __BASE_FILE__="%(Filename)%(Extension)"
(Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions)
template <>
Instance& Manager<FILEID>::getInstance()
{
#define _STR(x) #x
#define STR(x) _STR(x)
#define CHECK_ID() __pragma(message("Initializing \"Instance& Manager<FILEID>::getInstance()\" with FILEID="STR(FILEID)" in "STR(__BASE_FILE__)))
CHECK_ID()
static Instance theInstance = getTheFactory().getInstance(FILEID);
return theInstance;
};
Example-Output:
1>------Build started : Project : Test_Call, Configuration : Debug Win32------
1> name1.cpp
1> Initializing "Instance& Manager<FILEID>::getInstance()" with FILEID = FileId::ID_file1ID in "name1.cpp"
1> name2.cpp
1> Initializing "Instance& Manager<FILEID>::getInstance()" with FILEID = FileId::ID_file2ID in "name2.cpp"
1> Test_Call.vcxproj-><Project>\Debug\Test_Call.exe
== == == == == Build: 1 succeeded, 0 failed, 0 up - to - date, 0 skipped == == == == ==
EDIT: Using FileId values as template parameter (MSVE)
id.h
#pragma once
enum FileId {
ID_file1ID = 3,//just to see a non zero number in the debugger, which I do
ID_file2ID,
//and so on
FileIdSize
};
global.h
#pragma once
#include "ids.h"
struct Instance
{
};
struct Factory
{
Instance getInstance(int FileID) { return Instance(); }
};
template <FileId ID>
struct Manager
{
static const FileId manager_id = ID;
static Factory& getTheFactory() { return m_factory; }
static Instance& getInstance()
{
static Instance theInstance = getTheFactory().getInstance(manager_id);
return theInstance;
}
private:
static Factory m_factory;
};
global.cpp
#include "global.h"
Factory Manager<FileId::ID_file1ID>::m_factory;
Factory Manager<FileId::ID_file2ID>::m_factory;
name1.cpp
#include "global.h"
void test1()
{
Instance& a = Manager<FileId::ID_file1ID>::getInstance();
}
name2.cpp
#include "global.h"
void test2()
{
Instance& a = Manager<FileId::ID_file2ID>::getInstance();
}
test.cpp
#include <iostream>
#include "global.h"
using namespace std;
int main(int argc, char** argv)
{
Instance& a = Manager<FileId::ID_file1ID>::getInstance();
Instance& b = Manager<FileId::ID_file2ID>::getInstance();
Instance& c = Manager<FileId::ID_file1ID>::getInstance();
Instance* aptr = &a;
Instance* bptr = &b;
Instance* cptr = &c;
printf("aptr==bptr -> %s\n", (aptr == bptr) ? "true" : "false"); //->false
printf("aptr==cptr -> %s\n", (aptr == cptr) ? "true" : "false"); //->true (both use the instance from ID_file1ID
printf("bptr==cptr -> %s\n", (bptr == cptr) ? "true" : "false"); //->false
}
This is not an answer, but may prove useful in finding out what is wrong.
The following code is essentially the same as the original answer, but with all complexity stripped away at the expensive of needing boilerplate code in various places.
idmanager.h
struct Instance {/*...*/};
Instance &getFile1Instance();
Instance &getFile2Instance();
// etc...
idmanager.cpp
Instance &getFile1Instance()
{
static Instance file1instance;
return file1instance;
}
Instance &getFile2Instance()
{
static Instance file2instance;
return file2instance;
}
// etc...
In each file, place at the start
#include "idmanager.h"
and you can get the static Instance of any file in the obvious way.
This is as simple as it can possibly get, so copying it into your project simply can't cause a problem.
If the above example worked, then try making it slightly closer to the original answer: move the definitions of the getFileXInstance functions into the files themselves, and delete idmanager.cpp.
idmanager.h
struct Instance {/*...*/};
Instance &getFile1Instance();
Instance &getFile2Instance();
// etc...
file1.cpp
#include "idmanager.h"
Instance &getFile1Instance()
{
static Instance file1instance;
return file1instance;
}
file2.cpp
// etc...
Clearly this just moves the code around between different .obj files, so should still work.
Now replace each getFileXInstance function with a struct with a single static member function, getInstance, as follows:
idmanager.h
struct Instance {/*...*/};
struct Manager1
{
static Instance &getInstance(); // defined in file1.cpp
};
struct Manager2
{
static Instance &getInstance(); // defined in file2.cpp
};
// etc...
file1.cpp
#include "idmanager.h"
Instance &Manager1::getInstance()
{
static Instance file1instance;
return file1instance;
}
file2.cpp
// etc...
The previous step allows us to reduce the amount of boilerplate code using templates:
idmanager.h
struct Instance {/*...*/};
template <int id>
struct Manager
{
static Instance &getInstance(); // each instantiation has its definition in a different cpp file
};
file1.cpp
#include "idmanager.h"
template <>
Instance &Manager<1>::getInstance()
{
static Instance file1instance;
return file1instance;
}
This is where linker errors are most likely to start appearing again, if they do at all.
More repetition can also be removed by putting the common code in a shared header globals.h, and communicating the preprocessor constant FILEID to it.
idmanager.h
struct Instance {/*...*/};
template <int id>
struct Manager
{
static Instance &getInstance(); // each instantiation has its definition in a different cpp file
};
file1.cpp
#include "idmanager.h"
#define FILEID 1
#include "globals.h"
globals.h
template <>
Instance &Manager<FILEID>::getInstance()
{
static Instance theInstance;
return theInstance;
}
This last example is now the same as the original answer, with a few differences (no factories, no enums, no getThisFileInstance()) which are irrelevant to the linker errors. Therefore (assuming the first example worked) you can identify which change broke the program, and that should help to diagnose the real problem.
(note: although your error is exactly that which would appear if multiple files shared the same id, from the comments I assume this is not the case.)
Is there a way to avoid the Graph:: repetition in the implementation file, yet still split the class into header + implementation? Such as in:
Header File:
#ifndef Graph_H
#define Graph_H
class Graph {
public:
Graph(int n);
void printGraph();
void addEdge();
void removeEdge();
};
#endif
Implementation File:
Graph::Graph(int n){}
void Graph::printGraph(){}
void Graph::addEdge(){}
void Graph::removeEdge(){}
I'm guessing this is to avoid lots of "unnecessary typing". Sadly there's no way to get rid of the scope (as many other answers have told you) however what I do personally is get the class defined with all my function prototypes in nice rows, then copy/paste into the implementation file then ctrl-c your ClassName:: on the clip board and run up the line with ctrl-v.
If you want to avoid typing the "Graph::" in front of the printGraph, addEdge etc., then the answer is "no", unfortunately. The "partial class" feature similar to C# is not accessible in C++ and the name of any class (like "Graph") is not a namespace, it's a scope.
No there's not. Not directly at least. You could go for preprocessor tricks, but don't do it.
#define IMPL Graph::
IMPL Graph(int n){}
void IMPL printGraph(){}
void IMPL addEdge(){}
void IMPL removeEdge(){}
Also, you shouldn't even want to do it. What's the point. Besides it being a C++ rule, it lets you know you're actually implementing a member function.
One option is using. If you have method definitions which are in a cpp file that never gets #included, then using is safe (doesn't affect other files):
foo.h:
class FooLongNameSpecialisationsParamaters
{
int x_;
public:
int Get () const;
void Set (int);
};
foo.cpp:
#include "foo.h"
using Foo = FooLongNameSpecialisationsParamaters;
int Foo::Get () const
{
return x_;
}
void Foo::Set (int x)
{
x_ = x;
}
main.cpp:
#include "foo.h"
int main ()
{
//Foo foo; <-- error
FooLongNameSpecialisationsParamaters foo;
return 0;
}
No, there is no way to avoid it. Otherwise, how would you know if a given function definition is for a class function or for a static function?
If you are asking if you can define a member function such as Graph::printGraph without specifying the class name qualification, then the answer is no, not the way that you want. This is not possible in C++:
implementation file:
void printEdge(){};
The above will compile just fine, but it won't do what you want. It won't define the member function by the same name within the Graph class. Rather, it will declare and define a new free function called printEdge.
This is good and proper, if by your point of view a bit of a pain, because you just might want two functions with the same name but in different scopes. Consider:
// Header File
class A
{
void foo();
};
class B
{
void foo();
};
void foo();
// Implementation File
void foo()
{
}
Which scope should the definition apply to? C++ does not restrict you from having different functions with the same names in different scopes, so you have to tell the compiler what function you're defining.
//yes it is possible using preprocessor like this:
#define $ ClassName //in .cpp
void $::Method1()
{
}
//or like this: in the header .h:
#undef $
#define $ ClassName'
// but you have to include the class header in last #include in your .cpp:
#include "truc.h"
#include "bidule.h" ...
#include "classname.h"
void $::Method() { }
//i was using also
#define $$ BaseClass
//with single inheritance than i can do this:
void $::Method()
{
$$::Method(); //call base class method
}
//but with a typedef defined into class like this it's better to do this:
class Derived : Base
{
typedef Base $$;
}
EDIT: I misread your question. This would be an answer to the question whether you can split header-files. It doesn't help you to avoid using LongClassName::-syntaxes, sorry.
The simple answer: You can split up c++-file, but you can not split up header-files.
The reason is quite simple. Whenever your compiler needs to compile a constructor, it needs to know exactly how many memory it needs to allocate for such an object.
For example:
class Foo {
double bar; //8 bytes
int goo; //4 bytes
}
new Foo() would require the allocation of 12 bytes memory. But if you were allowed to extend your class definitions over multiple files, and hence split header files, you could easily make a mess of this. Your compiler would never know if you already told it everything about the class, or whether you did not. Different places in your code could have different definitions of your class, leading to either segmentation faults or cryptic compiler errors.
For example:
h1.h:
class Foo {
double bar; // 8 bytes
int goo; // 4 bytes
}
h2.h:
#include "h1.h"
class Foo {
double goo; // 8 bytes
} // we extend foo with a double.
foo1.cpp:
#include "foo1.h"
Foo *makeFoo() {
return new Foo();
}
foo2.cpp:
#include "foo2.h"
void cleanupFoo(Foo *foo) {
delete foo;
}
foo1.h:
#include "h1.h"
Foo *makeFoo();
foo2.h:
#include "h1.h"
#include "h2.h"
void cleanupFoo(Foo *foo)
main.cpp:
#include foo1.h
#include foo2.h
void main() {
Foo *foo = makeFoo();
cleanupFoo(foo);
}
Carefully check what happens if you first compile main.cpp to main.o, then foo1.cpp to foo1.o and foo2.cpp to foo2.o, and finally link all of them together. This should compile, but the makeFoo() allocates something else then the cleanupFoo() deallocated.
So there you have it, feel free to split .cpp-files, but don't split up classes over header files.