I have a header file:
#ifndef __DATABASE_HELPER_H__
#define __DATABASE_HELPER_H__
class DatabaseHelper{
public:
static QJsonDocument* database;
DatabaseHelper();
static Card* selectJSonCard(std::string cardCode);
static void testFunctions();
static bool isLeader(std::string cardCode);
};
#endif
QJsonDocument* DatabaseHelper::database = &(QJsonDocument());
void DatabaseHelper::testFunctions(){
std::cout << "test" << std::endl;
}
//and so on for the others
Now, I need it to be included from two different files.
With one file is fine, it compiles, but 2 files gives me this error:
[ERROR] ./models/../utils/database_helper.h:38:16: error: redefinition of ‘QJsonDocument* DatabaseHelper::database’
38 | QJsonDocument* DatabaseHelper::database = &(QJsonDocument());
| ^~~~~~~~~~~~~~
./utils/database_helper.h:38:16: note: ‘QJsonDocument* DatabaseHelper::database’ previously declared here
38 | QJsonDocument* DatabaseHelper::database = &(QJsonDocument());
| ^~~~~~~~~~~~~~
./models/../utils/database_helper.h:114:6: error: redefinition of ‘static void DatabaseHelper::testFunctions()’
114 | void DatabaseHelper::testFunctions(){
| ^~~~~~~~~~~~~~
./utils/database_helper.h:114:6: note: ‘static void DatabaseHelper::testFunctions()’ previously defined here
114 | void DatabaseHelper::testFunctions(){
| ^~~~~~~~~~~~~~
Where the first file including this is in folder ./models/
and the other one is in ./
.
My goal is to be able to access the static
function from every file in which I include the header, and have just one instance of the QJsonDocument
variable database
.
Am I missing something? Is there a way to do it?
CodePudding user response:
QJsonDocument* DatabaseHelper::database = &(QJsonDocument());
This defines DatabaseHelper::database
.
Every .cpp
file that includes this header file will define this object. An #include
directive logically inserts the header file into the including .cpp
files. It's as if every one of your .cpp
files, that includes this header file, defines this. That's how #include
works in C .
Therefore, when two or more .cpp
files include this header file, this results in violation of the One Definition Rule, hence your compilation error.
The solution is trivial. Move all definitions into exactly one of your .cpp
files.
The same thing applies to void DatabaseHelper::testFunctions()
, too.
CodePudding user response:
The problem is that you've put the definition QJsonDocument* DatabaseHelper::database = &(QJsonDocument());
inside the header file instead of a source file. So when that header is included in different source files, that definition also gets duplicated and hence the error.
To solve this move QJsonDocument* DatabaseHelper::database = &(QJsonDocument());
to a single source file. This way you will only have a declaration inside the header and having multiple declaration is fine(as opposed to having multiple definitions) while the corresponding definition will be inside a source file.
CodePudding user response:
As several others have stated, you are defining DatabaseHelper::database
in the header file, which means that every translation unit which includes the header will get its own copy of DatabaseHelper::database
, hence the redefinition error during linking.
I want to point out that &(QJsonDocument())
should not even compile, as you can't take the address of a temporary object. The correct way is to create an object whose lifetime is at least as long as DatabaseHelper::database
, and then you can take the address of that object, eg:
static QJsonDocument obj;
QJsonDocument* DatabaseHelper::database = &obj;
That being said, a better option is to not have a static
pointer member at all. The customary approach to creating a singleton class is to use a static
method which returns a pointer/reference to the singleton (and make the constructor private
so that no code outside of the class can instantiate the singleton directly), and then inside that static
method you can define the actual singleton as a static
object, eg:
.h
#ifndef __DATABASE_HELPER_H__
#define __DATABASE_HELPER_H__
class DatabaseHelper{
private:
DatabaseHelper();
public:
static QJsonDocument* GetDatabase(); // <-- HERE
static Card* selectJSonCard(std::string cardCode);
static void testFunctions();
static bool isLeader(std::string cardCode);
};
#endif
.cpp
DatabaseHelper::DatabaseHelper(){
}
QJsonDocument* DatabaseHelper::GetDatabase(){
static QJsonDocument database; // <-- HERE
return &database;
}
void DatabaseHelper::testFunctions(){
std::cout << "test" << std::endl;
}
//and so on for the others