52

Here is a little test program:

#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;
}

On VS2008 + SP1 (vc9) it compiles fine: the console just display "TEST IT!".

As far as I know, static member methods shouldn't be called on instanced object.

  1. Am I wrong? Is this code correct from the standard point of view?
  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?
Melebius
  • 6,183
  • 4
  • 39
  • 52
Klaim
  • 67,274
  • 36
  • 133
  • 188

4 Answers4

81

The standard states that it is not necessary to call the method through an instance, that does not mean that you cannot do it. There is even an example where it is used:

C++03, 9.4 static members

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.

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

process& g();

void f()
{
   process::reschedule(); // OK: no object necessary             
   g().reschedule(); // g() is called
}
Abdullah
  • 7,143
  • 6
  • 25
  • 41
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • 1
    Wow, I never knew this. I assume the function that gets called is based only on the compile-time type (not on the runtime type) of the expression? – Seth Carnegie Apr 14 '12 at 02:44
  • 1
    @SethCarnegie: Yes, it uses the compile time type of the object (or reference thereof), you cannot get dynamic dispatch to static member methods. – David Rodríguez - dribeas Apr 14 '12 at 03:33
19

Static functions doesn´t need an instanciated object for being called, so

k.DoCrash();

behaves exactly the same as

Test::DoCrash();

using the scope resolution operator (::) to determine the static function inside the class.

Notice that in both case the compiler doesn´t put the this pointer in the stack since the static function doesn't need it.

P0W
  • 46,614
  • 9
  • 72
  • 119
jab
  • 2,844
  • 1
  • 21
  • 22
  • 2
    I’d rather say _pass `this` pointer as a parameter_ instead of _put it in the stack_. The actual manner is subject to calling convention of the particular platform. However, +1 for mentioning this feature of static methods. – Melebius Oct 23 '14 at 12:22
  • 1
    There is one difference: in `k.DoCrash()`, the prefix `k` is evaluated. If `k` is just an object name, that probably doesn't matter, but it could be a function call or some other expression with side effects: `func().DoCrash()` – Keith Thompson Aug 27 '15 at 01:01
  • @KeithThompson Wow, that's looks wierd. Does the `func()` in your example necessarily return an object of Test? – xin Mar 12 '19 at 05:40
  • 1
    @feng: Yes, for `func().DoCrash()` to be valid, `func()` would have to return a result of type `Test`. Or you could have `arr[func()].DoCrash()`, with `arr` being an array of `Test` objects and `func()` being a function returning some integer type. – Keith Thompson Mar 12 '19 at 09:04
4

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?

It's potentially useful in several scenarios:

  • [the '"static or not" method in templates' you suggest:] when many types could have been specified to a template, and the template then wants to invoke the member: the types providing a static function can be called using the same notation as a member function - the former may be more efficient (no this pointer to pass/bind), while the latter allows polymorphic (virtual) dispatch and use of member data

  • minimising code maintenance

    • if a function evolves from needing instance-specific data to not needing it - and is therefore made static to allow easy instance-free use and prevent accidental use of instance data - all the points of existing client usage don't need to be labouriously updated

    • if the type's changed the var.f() invocation continues to use the var type's function, whereas Type::f() may need manual correction

  • when you have an expression or function call returning a value and want to invoke the (potentially or always) static function, the . notation may prevent you needing to use decltype or a supporting template to get access to the type, just so you can use the :: notation

  • sometimes the variable name is just much shorter, more convenient, or named in a more self-documenting way

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • 1
    On MSVC 2013 compiler at least, calling static methods via an instance works, but generates a compiler warning about an unreferenced variable if the variable is not used for anything other than calling a static method. – abelenky Nov 23 '15 at 22:54
2

static methods can be called also using an object of the class, just like it can be done in Java. Nevertheless, you shouldn't do this. Use the scope operator like Test::DoCrash(); Maybe you think of namespaces:

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

which can only be called by Test::DoCrash(); from outside that namespace if the function is not imported explicitly using a using directive/declaration into the scope of the caller.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 2
    Yes, i know i should do this, that's why i ask why the other way (calling like a member) is allowed/not forbidden. :) – Klaim Nov 28 '08 at 14:38