简体   繁体   中英

I am getting an error of redefinition while using extern header file

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.

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.

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 , Theextern 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM