为什么要调用静态成员函数.或 - >语法合法?

Old*_*ier 18 c++ static member-functions

可能重复:
类实例上的C++静态成员方法调用

今天我发现我长期以来的事情(我的意思是长期的,二十年),在C++中被认为是非法的,实际上是合法的.即,调用静态成员函数,就好像它属于单个对象一样.例如:

struct Foo
{
    static void bar() { cout << "Whatever."; }
};

void caller()
{
    Foo foo;
    foo.bar();    // Legal -- what?
}
Run Code Online (Sandbox Code Playgroud)

我通常会看到静态成员函数严格使用"作用域解析语法"调用,因此:

Foo::bar();
Run Code Online (Sandbox Code Playgroud)

这是有道理的,因为静态成员函数不与类的任何特定实例相关联,因此,我们不希望一个特定的实例进行语法"连接到"函数调用.

然而我今天发现GCC 4.2,GCC 4.7.1和Clang 3.1(作为编译器的随机抽样)接受前一种语法,以及:

Foo* foo = new Foo;
foo->bar();
Run Code Online (Sandbox Code Playgroud)

在我的具体情况,该表达式的合法性导致运行时错误,印证了这种语法的特点是比学术更感兴趣,它有着实际的后果.

为什么C++允许调用静态成员函数,就像它们是单个对象的直接成员一样 - 也就是说,通过使用.或 - >语法附加到对象实例?

Pet*_*ker 16

C++的设计和演变(第288页)中,Bjarne Stroustrup提到在静态成员函数之前的几天,程序员使用hacks喜欢((X*)0)->f()调用不需要对象的成员函数.我的猜测是,当静态成员函数加入到语言,通过访问->被允许使用这样的代码的程序员可以改变fstatic无需追捕并改变每个使用它.

  • +1用于参考[可能]设计师的洞察力/决策. (4认同)

Raf*_*sta 9

据推测,你可以在你可能不知道类的东西的地方调用它,但是编译器会这样做.

假设我有一堆类,每个类都有一个返回类名的静态成员:

class Foo
{
    static const char* ClassName() { return "Foo"; }
};

class Bar
{
    static const char* ClassName() { return "Bar"; }
};
Run Code Online (Sandbox Code Playgroud)

然后在我的代码中,我可以做以下事情:

Foo foo;

printf( "This is a %s\n", foo.ClassName() );    
Run Code Online (Sandbox Code Playgroud)

无需担心一直知道我的对象类.例如,在编写模板时,这将非常方便.

  • @OldPeculier:另一种情况是当类型无法获得时,例如函数的返回类型,因为在C11的`decltype`之前,语言不支持获取返回类型.它允许`add(a,b).ClassName()`而不是用模板函数编写样板代码,模板函数的唯一目的是推导返回类型并在类型上调用静态`ClassName`方法:`getClassName( (添加(A,b))`. (3认同)
  • @OldPeculier:考虑一种情况,您更改上述代码,以便“Foo foo;”现在是“Bar foo;”。如果您使用“foo.ClassName()”,这是您需要进行的唯一更改。如果您使用了 `Foo::ClassName()`,您需要记住进行 2 处更改。少量的改变就可以了。同样适用于 `sizeof foo` 与 `sizeof Foo`、typedef 和许多其他您只想声明一次的声明。 (2认同)
  • @OldPeculier,当`Foo :: ClassName`是静态但"Bar :: ClassName"不是静态的时,请考虑你的模板示例,实际上它可能是虚拟的. (2认同)

Fle*_*exo 6

就像这样,因为标准说的是它是如何工作的.n3290§9.4声明:

可以使用qualified-id表达式引用类X的静态成员,X::s;不必使用类成员访问语法(5.2.5)来引用静态成员.可以使用类成员访问语法来引用静态成员,在这种情况下,评估对象表达式.[例如:

struct process { 
  static void reschedule(); 
}; 

process& g();

void f() { 
  process::reschedule(); // OK: no object necessary
  g().reschedule(); // g() is called 
} 
Run Code Online (Sandbox Code Playgroud)

最后的例子]

  • @RafaelBaptista - 回答那将是猜测.我怀疑"这是一个静态函数"被认为是一个实现细节,与使用它的人无关. (4认同)
  • @OldPeculier我认为在SO**上"正确"解决这些问题的唯一方法是**使用规范.C++是C++,因为它是.没有其他理由.当然,详细说明为什么语言被*设计*的参考文献会给出"为什么?",但这样的*理由*信息往往似乎丢失了......也许在某些文章或采访手稿中埋藏了一个引用. (3认同)
  • C++标准没有*基本原则*([与C99不同](http://www.open-std.org/JTC1/SC22/WG14/www/C99RationaleV5.10.pdf)),因此具体部分一般不解释标准. (3认同)
  • OOOOH琦.但是"因为圣经所说的",在软件工程的情况下并不是一个充分的答案.为什么圣经这么说?为什么标准委员会认为这是一件令人满意的事情?它似乎本质上令人困惑,因为该对象被忽略(除了它的类型)并且规则改变了它的含义.和 - >. (2认同)

MSN*_*MSN 6

来自C++的演变(pdf),第8节.静态成员函数:

...还观察到不可移植的代码,例如

    ((x*)0)->f();
Run Code Online (Sandbox Code Playgroud)

用于模拟静态成员函数.

所以我的猜测是(基于几乎所有其他奇怪的语法事物的基本原理模式),当你只是提供类型来提供向后兼容已建立但破坏的习语时,它们允许调用静态成员函数.