关于VisualC++:C++静态成员方法调用类实例

C++ Static member method call on class instance

下面是一个小测试程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#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)上,它编译得很好:控制台只显示"测试它!".

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

  • 我错了吗?从标准角度看,此代码是否正确?
  • 如果是正确的,那为什么?我找不到为什么会允许它,或者它可能有助于在模板中使用"static or not"方法?

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

    C++ 03,9.4个静态成员

    A static member s of class X may be referred to using the
    qualified-id expression X::s; it is
    not necessary to use the class member access syntax (5.2.5) to refer
    to a static member. A static member
    may
    be referred to using the class member access syntax, in which
    case the object-expression is
    evaluated.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class process {
    public:
       static void reschedule();
    };

    process& g();

    void f()
    {
       process::reschedule(); // OK: no object necessary            
       g().reschedule(); // g() is called
    }


    静态函数不需要调用已声明的对象,因此

    1
    k.DoCrash();

    行为与

    1
    Test::DoCrash();

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

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


    2) If it's correct, why is that? I can't find why it would be allowed, or maybe it's to help using"static or not" method in templates?

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

    • [您建议的模板中的"static or not"方法:]TTR允许多态(virtual)发送和使用成员数据

    • 最小化代码维护

      • 如果一个函数从需要特定于实例的数据发展到不需要它-因此使static允许简单的实例自由使用,并防止意外使用实例数据-现有客户机使用的所有点不需要费力地更新

      • 如果类型已更改,则var.f()调用将继续使用var类型的函数,而Type::f()可能需要手动更正。

    • 当您有一个表达式或函数调用返回一个值并希望调用(可能或始终)static函数时,.表示法可能会阻止您使用decltype或支持模板来访问该类型,这样您就可以使用::表示法。

    • 有时变量名只是更短、更方便或以更自我记录的方式命名。


    静态方法也可以使用类的对象来调用,就像它可以在Java中完成一样。不过,你不应该这样做。使用像Test::DoCrash();这样的作用域运算符,也许您会想到名称空间:

    1
    2
    3
    4
    5
    namespace Test {
        void DoCrash() {
            std::cout <<"Crashed!!" << std::endl;
        }
    };

    如果函数不是使用using directive/declaration显式导入到调用方的作用域中,则只能由Test::DoCrash();从该命名空间外部调用。