在命名空间内的标头中声明的函数指针

时间:2013-12-19 18:50:42

标签: c++

我有一个包含以下内容的简单标题:

// 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'标题的关键字......但仍然没有。

4 个答案:

答案 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被调用,我想我怀疑不是这样。