我有一个包含以下内容的简单标题:
// system.h
#pragma once
namespace System
{
void Initialize(void);
int (*Main)(int& argc, char** argv);
void Shutdown(void);
}
在" system.cpp"中,定义了Initialize(),以便将函数指针Main(int,char **)设置为另一个main函数,该函数由预处理器定义,定义为任何系统将被编译(Windows,暂时)。
在程序的main.cpp中,它调用上面的三个函数......
因此,当编译它时,我得到一个链接器错误(对于system.cpp)抱怨已经在main.cpp中定义了System :: Main(int,char **)。这有什么用呢?
〜
// system.cpp
#include "..\system.h"
#ifdef _WINDOWS
#include "windows.h"
#else
#define SYSTEM_UNKNOWN 1
#endif
void System::Initialize(void)
{
#ifdef WINDOWS
System::Main = &Windows::Main;
#else if SYSTEM_UNKNOWN
System::Main = NULL;
#endif
}
void System::Shutdown(void)
{
System::Main = NULL;
}
我添加了' extern'标题的关键字......但仍然没有。
答案 0 :(得分:3)
在
int (*Main)(int& argc, char** argv);
是变量Main
的定义。对于声明,您需要extern
:
extern int (*Main)(int& argc, char** argv);
并在实现文件中移动定义。
您可以使用更简单的示例尝试相同(具有相同效果):
int x;
这也是一个定义。
答案 1 :(得分:2)
您上面的Main
不仅仅是声明。这也是一个定义。如果您在多个文件中包含此标头,则每个文件都将定义Main
的版本。您希望将变量声明为extern
,然后在一个.cpp
文件中对其进行定义:
namespace System {
extern int (*Main)(int&, char**); // declaration
}
int (*Main)(int&, char**) = ...; // definition
答案 2 :(得分:1)
你有一个典型的普通多重定义错误,这是由你在头文件中定义一个带有外部链接的变量这一事实触发的(然后将该头文件包含在其中)多个翻译单位)。命名空间与它无关,并且没有任何区别。
当您将extern
关键字添加到标头后,您将所有这些定义转换为非定义声明。链接器错误立即变得不同。现在,您没有出现多重定义错误,而是出现了缺失定义错误。
在标题中添加extern
关键字是朝着正确方向迈出的一步。现在,您只需为变量
int (*Main)(int& argc, char** argv);
在一个(也是唯一一个)实现文件中。
答案 3 :(得分:0)
不应以读取函数forward-declaration的方式读取行int (*Main)(int& argc, char** argv);
,就像该代码框中的其他两行一样。这一行定义了一个名为Main
的数据变量,它有一个类型“指向函数返回int的指针,用blah blah blah。”这类似于在头文件中说int j;
。
正如其他人所说的那样,在它前面添加extern
,然后在单 cpp
文件中添加该行,将解决您的问题。但是我认为理解这种行为背后的原因是有用的。
编辑:这是一个侧面点,但在这种情况下可能没有理由将argc
作为参考传递:您不会因为指针和{而节省内存{1}}可能大小相同或更差,并且向读者建议您可以修改int
函数中的argc
,其方式需要反映在{{1}中从中我假设Main
被调用,我想我怀疑不是这样。