2009-05-30 54 views
7

我是reading导致我问这个问题的关联问题。嵌套函数不被允许,但为什么嵌套函数原型被允许? [C++]

考虑下面的代码

int main() 
{ 
    string SomeString(); 
} 

所有说,编译器将其视为函数原型,而不是作为一个字符串对象。现在考虑下面的代码。

int main() 
{ 
    string Some() 
    { 
     return ""; 
    } 
} 

编译器说这是无效的,因为我猜嵌套函数定义是不允许的。 如果不允许,为什么允许嵌套的函数原型?它没有给予任何好处,而不是让人混淆(或者我在这里错过了一些有效的观点?)。

我想通以下是有效的。

int main() 
{ 
    string SomeFun(); 
    SomeFun(); 
    return 0; 
} 

string SomeFun() 
{ 
    std::cout << "WOW this is unexpected" << std::endl; 
} 

这也令人困惑。我期待功能SomeFun()将只有在主要有一个范围。但是我错了。为什么编译器允许编译上面的代码?是否有任何实时情况下,上述代码有意义?

有什么想法?

+0

+1只需点击相同的查询,&下面的答案包含所有信息和更多信息。 – slashmais 2010-11-04 05:39:14

回答

8

您的原型仅为'Forward Declaration'。请查看Wikipedia文章。

基本上,它告诉编译器“如果以这种方式使用标签'SomeFun',不要惊慌”。但是你的链接器是负责找到正确的函数体的东西。

你实际上可以声明一个伪造的原型,例如, 'char SomeFun()'并将它用在你的主体上。链接器尝试查找虚假函数的主体时,只会出现错误。但是你的编译器会很酷。

有很多好处。你必须记住函数体并不总是在同一个源代码文件中。它可以位于链接库中。此外,链接库可能具有特定的“链接签名”。使用条件定义,甚至可以在构建时使用范围化原型选择正确的链接签名。尽管大多数人会使用函数指针相反。

希望这会有所帮助。

5

这是一个来自C的惯例 - 就像许多人一样 - 这是C++采用的。

在C中另一个函数中声明函数的能力是大多数程序员可能认为令人遗憾和不必要的决定。特别是随着现代OOP的设计,其中函数定义比他们在C.

如果你想有,只有在另一个函数的范围存在功能相对较小,有两个选项boost::lambdaC++1x lambda

3

编译器的函数原型是提示。他们表示,这些功能是在其他地方实施的,如果不是已经发现的。而已。

3

当你在声明原型时,你基本上是告诉编译器等待链接器来解决它。根据您编写原型的范围规则适用。在你的main()函数中写入原型没有任何技术上的错误(尽管恕我直言,有点混乱),它只是意味着函数只在main()内部是本地已知的。如果您将原型声明在源文件的顶部(或者更常见的是在头文件中),那么原型/函数将在整个源代码中是已知的。

string foo() 
{ 
    string ret = someString(); // Error 
    return ret; 
} 

int main(int argc,char**argv) 
{ 
    string someString(); 
    string s = somestring(); // OK 
    ... 
} 
7

正如附注,C++ 03确实有一个定义本地函数的迂回方式。它要求滥用地方级功能:

int main() 
{ 
    struct Local 
    { 
     static string Some() 
     { 
      return ""; 
     } 
    }; 
    std::cout << Local::Some() << std::endl; 
} 
+2

令人敬畏的语言滥用。 – Joshua 2009-05-30 15:29:02

+0

这是为什么'滥用'? (我真的很好奇btw) – Samaursa 2012-02-07 20:33:34

5

至于为什么你的

void f() { 
    void g(); g(); 
} 

声明是一个比这

void g(); 
void f() { 
    g(); 
} 

它总体上是好的更好,如果你把声明的地方尽可能避免名称冲突。我认为在本地声明一个函数(这种方式)是否真的是真的是是有争议的,因为我认为普通的包含它的标题还是更好,然后采用“通常”的方式,这对于不知道。有时,它也是有用的解决被遮挡的功能

void f() { 
    int g; 
    // oops, ::g is shadowed. But we can work around that 
    { 
     void g(); g(); 
    } 
} 

当然,在C++中,我们可以用its_namespace::g()调用函数g - 但在过去的C,会​​不会有可能的,而且那件事允许程序员仍然可以访问该函数。还要注意,虽然语法上不同,但从语义上讲,以下内容也在本地范围内声明了一个函数,该函数实际上定位了不同的范围。

int main() { 
    using std::exit; 
    exit(); 
} 

作为一个侧面说明,有更多的情况一样,在那里声明的目标范围是如该声明出现在范围内。一般来说,你声明的实体变为范围中的一员在该声明中出现。但情况并非总是如此。例如,考虑朋友的声明,其中说的事情发生

struct X { friend void f() { std::cout << "WoW"; } }; 
int main() { void f(); f(); } // works! 

即使函数声明(和定义!)的f发生的X范围内,在实体(函数本身)成为封闭命名空间中的一员。