【问题标题】:Why can static member function definitions not have the keyword 'static'?为什么静态成员函数定义不能有关键字'static'?
【发布时间】:2017-07-24 10:17:46
【问题描述】:

根据this C++ 中“静态”关键字的链接:

static 关键字仅与静态声明一起使用 成员,在类定义中,但不在定义中 那个静态成员

为什么在成员函数定义中禁止使用 static 关键字?我确实理解在定义中将函数重新声明为“静态”是多余的。但是在函数定义的编译过程中使用它应该是无害的,因为它不会导致任何歧义。那么为什么编译器会禁止它呢?

【问题讨论】:

  • static 在类外函数定义上表示内部链接,但是类成员函数具有外部链接。这会令人困惑
  • 编译器始终处于判断函数是成员函数还是全局函数的状态。不应该对此感到太困惑。 :-/
  • @M.M 但他说的是类成员函数。
  • @MichaelWalz 别开玩笑了
  • @aakashbhowmick 阅读代码的人会感到困惑,而不是编译器。

标签: c++ static


【解决方案1】:

有歧义好吧。成员函数完全不需要相同的定义。

考虑一下:

namespace foo {
    static void bar();
}

static void foo::bar() {

}

foo::bar需要使用相同的链接说明符进行定义。

但是,对于成员函数,static 不是链接说明符。如果允许,foo::bar 定义的正确性将是 非常非常 上下文取决于 foo 是什么。禁用static 实际上减轻了编译器的负担。

将其扩展到一般成员,而不仅仅是成员函数,这是一个一致性问题。

【讨论】:

  • Delphi 将此类函数称为“类”函数而不是“静态”函数,使用class 关键字来表示它们。事后看来,这对 C++ 来说可能是一个更好的主意,而不是将“静态”重新用于完全不同的事情......
  • @MarkKCowan - 我同意,“重载”关键字(以及从 C 继承的关键字,不少于)不是最好的主意。我不确定使用class 会更好(部分是因为结构和类是可以互换的,然后呢?“结构”成员函数?)。也许一个完全不同的关键字会更好。这样编译器就可以减少对上下文的依赖了。
  • 类已经为模板参数重载,即使我们可以模板结构,也不能在其位置使用“struct”
  • 我接受了这个答案,因为它提供了编译器想要强制执行此规则的充分理由。
  • @MarkKCowan - 但这不是不匹配明显的情况。如果你用 struct 关键字定义一个类型,那么用“class”来指定函数会很奇怪。好吧,无论如何,IMO。
【解决方案2】:

重点是,static 有几个非常不同的含义:

class Foo {
    static void bar();
}

这里的static 关键字意味着函数barFoo 类相关联,但它不会在Foo 的实例上调用。 static 的这个含义与面向对象密切相关。但是,声明

static void bar();

意思很不一样:表示bar只在文件范围内可见,不能直接从其他编译单元调用该函数。

你看,如果你在类声明中说static,那么稍后将函数限制在文件范围内没有任何意义。如果你有一个static 函数(具有文件范围),那么将它作为类定义的一部分发布到公共头文件中是没有意义的。 这两种含义是如此不同,以至于它们实际上是相互排斥的。


static 有更多不同的含义:

void bar() {
    static int hiddenGlobal = 42;
}

是另外一个意思,即类似,但不完全相同

class Foo {
    static int classGlobal = 6*7;
}

在编程时,单词在所有上下文中的含义并不总是相同。

【讨论】:

  • 问题不在于 C++ 中“静态”的不同含义。作为一个体面的 C++ 程序员,我知道所有这些。
  • @aakashbhowmick 但是您问为什么您的编译器不允许您将这两种不同的含义结合起来,似乎认为static 在两种情况下都会产生相同的效果。当你在类范围之外的函数上使用static 时,它与在类范围内使用它时完全不同。
  • 我很清楚静态成员函数与静态全局函数有何不同。我的问题是为什么静态成员函数定义不应该包含关键字'static',尽管同一函数的声明可以(并且应该)。
  • @AAkashbhowmick 好吧,从语法上讲,静态成员函数定义和文件范围函数定义之间没有区别。两种定义的唯一区别是,成员函数定义一般需要使用作用域解析操作符。但是,如果该运算符是命名空间的一部分,它也可能出现在文件范围函数中,因此它没有语法差异,只是语义差异。
【解决方案3】:

您必须了解声明和实现之间的区别,这将回答您的问题:

声明:是在编译程序之前如何看到 C++ 函数和方法。它放在头文件(.h 文件)中。

实现:是编译器如何将声明链接到二进制代码中的实际任务。实现可以即时编译(从源文件、.cpp 或 .cxx 或 .cc),也可以已经编译(从共享库或目标文件)。

现在回到您的问题,当您将某些内容声明为静态时,它与实现无关,但与编译器在编译代码时如何看到声明有关。例如,如果您将源文件中的函数标记为“静态”,那么这是没有意义的,因为该信息无法传送到编译对象和共享库。为什么允许?反而只会造成歧义。

出于完全相同的原因,默认参数必须进入头文件,而不是源文件。因为源文件(包含实现)不能将默认参数信息传递给编译对象。

【讨论】:

    【解决方案4】:

    猜想,但如果定义是静态的,它可以被解释为 C 意义上的文件范围变量。

    【讨论】:

      猜你喜欢
      • 2013-09-04
      • 2020-11-15
      • 2013-11-17
      • 2016-07-03
      • 2023-03-06
      • 2011-01-18
      • 2014-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多