Home > Software design >  Error redefinition of static class member and method in C linked to multiple file
Error redefinition of static class member and method in C linked to multiple file

Time:12-20

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
  • Related