命名空间、类和自由函数 - 何时需要使用完全限定名称?

9
在我的下面的示例中,为什么我必须在cpp文件中完全限定自由函数的名称以避免链接错误,而对于类函数却不需要呢?你能解释一下其中的区别吗? ctest.h:
namespace Test
{
    int FreeFunction();

    class CTest
    {
        public:
            CTest();
            ~CTest();
    };
}

ctest.cpp:

#include "ctest.h"

using namespace Test;

// int FreeFunction()     -> undefined reference error
int Test::FreeFunction()  -> works just fine
{
    return 0;
}

CTest::CTest()                -> no need to fully qualify name, i.e. Test::CTest
{}

CTest::~CTest()
{}

感谢您的时间和帮助。

请注意,在C语言中指定void作为参数是有用的,但在C++中被认为是无用和不良风格:http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.4 - log0
@Ugo:我编辑了我的问题,删除了那个可怕的东西。感谢你指出来。 - nabulke
4个回答

12
int FreeFunction(void);  

这只是一个声明,而下面的是定义。

class CTest 
{ 
    public: 
        CTest(); 
        ~CTest(); 
}; 

如果您想为命名空间中已声明的实体提供定义(例如在封闭的命名空间中),则它必须是完全限定名称。

编辑2:

这里有一些内容可以让您更加清楚。请注意,此代码中未使用使用指令。

namespace Test { 
    int FreeFunction(void);   // declare

    class CTest;              // declare
} 

int Test::FreeFunction(){return 0;} // define
class Test::CTest{            // define
};

int main(){}

编辑 3: 声明 vs 定义 (C++0x) $3.1/2-

除非声明一个没有指定函数体的函数(8.4),包含extern说明符(7.1.1)或链接说明符25(7.5)且既没有初始化器也没有函数体,声明一个类定义中的静态数据成员(9.4),是一个类名声明(9.1),是一个不透明的枚举声明(7.2),或者是typedef声明(7.1.3),using声明(7.3.3),static_assert声明(Clause 7),属性声明(Clause 7),空声明(Clause 7),或using指令(7.3.4),否则这个声明就是定义。


在我的ctest.h文件中,定义了CTest类,但是我只声明了CTest的成员函数,这样说是否正确? - nabulke
是的,你说得对。此外,一个函数可以在命名空间中内联定义,也可以在任何一个封闭的命名空间中通过完全限定名称进行定义。 - Chubsdad
非常好的答案,附有示例和很好的解释。帮助我理解了问题。谢谢。 - nabulke

2
FreeFunction指的是Test::FreeFunction,如果你在提供了using namespace Test;后引用或调用它,但就函数定义而言,编译器无法知道你是在定义一个完全新的函数FreeFunction,还是在定义已经声明的Test::FreeFunction。编译器默认认为你正在定义一个全新的函数。
然而对于CTest::CTest,你已经在引用Test::CTest类,由于没有在Test命名空间外定义CTest类或命名空间,因此对CTest::anything的引用是明确的。所以编译器知道构造函数和析构函数定义是指向命名空间内的CTest类。
我认为写Test::FreeFunction是一个小代价。
希望这可以帮到你!

1

如果您不符合FreeFunction定义的条件,编译器就无法确定您是要为先前声明的Test::FreeFunction提供实现,还是要为当前命名空间中的另一个FreeFunction提供实现。

另一方面,解析CTest名称只有一种方法 - 作为来自Test命名空间的类定义。因此,没有必要完全限定它。

但是,如果CTest名称解析存在歧义(例如当前命名空间中还有另一个CTest类),则必须完全限定方法声明。


0

在实现函数时,通常最好打开命名空间。记住你可以重新打开它们...

// in Test.cpp
namespace Test
{
   int FreeFunction()
   {
       return 0;
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接