使用外部头文件时出现重定义错误
I am getting an error of redefinition while using extern header file
我在使用 extern 时遇到重新定义错误,但我也被告知,应该像这样使用 extern 变量,为什么我会收到此错误以及在这种情况下我应该如何使用 extern 才能正常工作? (即使我没有在 Tab.cpp 中指定它,我也可以使用这个变量,但是我得到一个或多个符号的错误,它被定义了 2 次。)
文件:
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;
行
extern int maxid = 0;
在文件ids.h
中是一个定义,因为它也初始化了变量。相反,它应该只包含一个声明:
extern int maxid;
定义应该在源文件 (.cpp
) 中,而不是头文件 (.h
)。头文件应该只包含变量声明,而不是定义。否则,如果多次包含头文件,或者源文件中已有定义,就会违反 one definition rule。
在您的例子中,您已经在文件 Tab.cpp
中定义了变量。 int maxid;
行是一个定义,因为它没有使用 extern
关键字。如果你想初始化变量,你应该在那个文件中进行。
extern int maxid = 0;
当你分配一些东西时,这是一个定义,extern
变得毫无意义并被忽略。删除分配:
extern int maxid;
您在 Tab.cpp 中有定义,默认情况下它被分配为零作为全局变量。
有定义和声明。 声明 告诉编译器某物存在。 定义 是一个包含 所有 描述该事物所需信息的声明。
对于像maxid
这样的全局变量,extern
表示它会有外部linkage;也就是说,为 linker 所知并在不同的源文件(翻译单元)之间可见。
许多不同的翻译单元可以说 extern int maxid;
并且他们都只是说“好的,我知道这个符号,我最终会在某个地方找到它。”。所以,放入一个成为多个翻译单元的一部分的 header 很好。
然而,当你给它一个初始化器时,在本例中是 =0
(描述初始化的几种可能方式之一),然后它变成了 definition
。它会导致分配存储空间并为该变量设置一个明确的位置。您不应该在 header 中这样做,因为包含它的每个文件都将定义相同的变量。因此,在 link 次你得到了不止一个,这是一个错误。
传统的做法是把extern int x;
放在header里,这样大家都知道x
存在,然后把int x = 0;
放在[=38=里]one CPP 文件,以便这个变量存在于某个地方。写作 extern int x = 0;
意思相同,但写作 un-idiomatic.
处理此问题的现代方法是使用为此目的创建的功能。将 inline int x = 0;
放入 header 文件中。这将在包含它的每个翻译单元中定义它,但是它们将被标记为 linker 理解它们都是相同的并且它应该只选择一个并且忽略其他人。
我在使用 extern 时遇到重新定义错误,但我也被告知,应该像这样使用 extern 变量,为什么我会收到此错误以及在这种情况下我应该如何使用 extern 才能正常工作? (即使我没有在 Tab.cpp 中指定它,我也可以使用这个变量,但是我得到一个或多个符号的错误,它被定义了 2 次。)
文件:
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;
行
extern int maxid = 0;
在文件ids.h
中是一个定义,因为它也初始化了变量。相反,它应该只包含一个声明:
extern int maxid;
定义应该在源文件 (.cpp
) 中,而不是头文件 (.h
)。头文件应该只包含变量声明,而不是定义。否则,如果多次包含头文件,或者源文件中已有定义,就会违反 one definition rule。
在您的例子中,您已经在文件 Tab.cpp
中定义了变量。 int maxid;
行是一个定义,因为它没有使用 extern
关键字。如果你想初始化变量,你应该在那个文件中进行。
extern int maxid = 0;
当你分配一些东西时,这是一个定义,extern
变得毫无意义并被忽略。删除分配:
extern int maxid;
您在 Tab.cpp 中有定义,默认情况下它被分配为零作为全局变量。
有定义和声明。 声明 告诉编译器某物存在。 定义 是一个包含 所有 描述该事物所需信息的声明。
对于像maxid
这样的全局变量,extern
表示它会有外部linkage;也就是说,为 linker 所知并在不同的源文件(翻译单元)之间可见。
许多不同的翻译单元可以说 extern int maxid;
并且他们都只是说“好的,我知道这个符号,我最终会在某个地方找到它。”。所以,放入一个成为多个翻译单元的一部分的 header 很好。
然而,当你给它一个初始化器时,在本例中是 =0
(描述初始化的几种可能方式之一),然后它变成了 definition
。它会导致分配存储空间并为该变量设置一个明确的位置。您不应该在 header 中这样做,因为包含它的每个文件都将定义相同的变量。因此,在 link 次你得到了不止一个,这是一个错误。
传统的做法是把extern int x;
放在header里,这样大家都知道x
存在,然后把int x = 0;
放在[=38=里]one CPP 文件,以便这个变量存在于某个地方。写作 extern int x = 0;
意思相同,但写作 un-idiomatic.
处理此问题的现代方法是使用为此目的创建的功能。将 inline int x = 0;
放入 header 文件中。这将在包含它的每个翻译单元中定义它,但是它们将被标记为 linker 理解它们都是相同的并且它应该只选择一个并且忽略其他人。