48

这是一个小测试程序:

#include <iostream>

class Test
{
public:
    static void DoCrash(){ std::cout<< "TEST IT!"<< std::endl; }
};

int main()
{
    Test k;
    k.DoCrash(); // calling a static method like a member method...

    std::system("pause");

    return 0;
}

在 VS2008 + SP1 (vc9) 上它编译得很好:控制台只显示“测试它!”。

据我所知,不应在实例对象上调用静态成员方法。

  1. 我错了吗?从标准的角度来看,这段代码是否正确?
  2. 如果它是正确的,那是为什么?我找不到为什么会被允许,或者可能是为了帮助在模板中使用“静态或非静态”方法?
4

4 回答 4

77

标准规定不需要通过实例调用方法,这并不意味着您不能这样做。甚至还有一个使用它的例子:

C++03、9.4 静态成员

可以使用限定 ID 表达式 X::s; 来引用类 X 的静态成员 s;不必使用类成员访问语法 (5.2.5) 来引用静态成员。可以使用类成员访问语法来引用静态成员,在这种情况下,对象表达式会被求值。

class process {
public:
   static void reschedule();
};

process& g();

void f()
{
   process::reschedule(); // OK: no object necessary             
   g().reschedule(); // g() is called
}
于 2008-11-28T11:43:53.160 回答
18

静态函数不需要实例化对象来调用,所以

k.DoCrash();

行为与

Test::DoCrash();

使用范围解析运算符 (::) 来确定类中的静态函数。

请注意,在这两种情况下,编译器都不会将this指针放入堆栈,因为静态函数不需要它。

于 2008-11-28T11:49:10.670 回答
4

2)如果它是正确的,那是为什么?我找不到为什么会被允许,或者可能是为了帮助在模板中使用“静态或非静态”方法?

它在几种情况下可能很有用:

  • [您建议的“模板中的“静态与否”方法”:]当可以为模板指定许多类型,然后模板想要调用该成员时:可以使用相同的表示法调用提供静态函数的类型作为成员函数 - 前者可能更有效(没有this传递/绑定指针),而后者允许多态(virtual)分派和使用成员数据

  • 最小化代码维护

    • 如果一个函数从需要特定于实例的数据演变为不需要它——因此static可以轻松地无实例使用并防止意外使用实例数据——现有客户端使用的所有点都不需要费力地更新

    • 如果类型改变了var.f()调用继续使用var类型的功能,而Type::f()可能需要手动更正

  • 当您有一个表达式或函数调用返回一个值并想要调用(可能或总是)static函数时,该.符号可能会阻止您需要使用decltype或支持模板来访问该类型,以便您可以使用该::符号

  • 有时变量名更短、更方便,或者以更自文档的方式命名

于 2015-06-30T06:41:16.480 回答
2

静态方法也可以使用类的对象来调用,就像在 Java 中一样。不过,您不应该这样做。使用范围运算符,就像Test::DoCrash();您可能会想到命名空间一样:

namespace Test {
    void DoCrash() {
        std::cout << "Crashed!!" << std::endl;
    }
};

Test::DoCrash();如果函数没有使用 a 显式导入using directive/declaration到调用者的范围内,则只能从该命名空间外部调用。

于 2008-11-28T11:42:35.050 回答