С++ Метод статического члена вызывает экземпляр класса

Вот небольшая тестовая программа:

#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) он компилируется отлично: консоль просто отображает "TEST IT!".

Насколько я знаю, статические методы-члены не должны вызываться на объекте instanced.

  • Я не прав? Правильно ли этот код со стандартной точки зрения?
  • Если это правильно, почему? Я не могу найти, почему это допустимо, или, может быть, это поможет использовать метод "статический или нет" в шаблонах?

Ответы

Ответ 1

В стандарте указано, что нет необходимости вызывать метод через экземпляр, что не означает, что вы не можете этого сделать. Существует даже пример, где он используется:

С++ 03, 9.4 статические элементы

Статический член класса X может быть отнесен к использованию expression-id-выражение 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
}

Ответ 2

Статические функции не нуждаются в подстроенном объекте для вызова, поэтому

k.DoCrash();

ведет себя точно так же, как

Test::DoCrash();

с помощью оператора разрешения области (::) для определения статической функции внутри класса.

Обратите внимание, что в обоих случаях компилятор не ставит указатель this в стек, так как статическая функция не нуждается в нем.

Ответ 3

2) Если это правильно, почему? Я не могу найти, почему это разрешено, или, может быть, это поможет использовать метод "статический или нет" в шаблонах?

Это потенциально полезно в нескольких сценариях:

  • [ "статический или нет" метод в шаблонах "вы предлагаете:] когда многие типы могли быть указаны в шаблоне, а затем шаблон хочет вызвать этот элемент: типы, предоставляющие статическую функцию, могут вызывается с использованием той же нотации, что и функция-член, - первая может быть более эффективной (нет this указатель на передачу/привязку), в то время как последняя допускает полиморфную (virtual) отправку и использование данных элемента

  • минимизация обслуживания кода

    • если функция возникает из-за необходимости получения данных, специфичных для экземпляра, и не нуждается в ней, и поэтому она делает static, чтобы обеспечить удобство использования без экземпляра и предотвратить случайное использование данных экземпляра - все точки использования существующего клиента не нуждайтесь в том, чтобы быть обновленно.

    • если тип изменил вызов var.f(), продолжает использовать функцию типа var, тогда как Type::f() может потребоваться ручная коррекция

  • когда у вас есть вызов выражения или функции, возвращающий значение, и вы хотите вызвать функцию (потенциально или всегда) static, нотация . может помешать вам использовать decltype или поддерживающий шаблон чтобы получить доступ к типу, так что вы можете использовать нотацию ::

  • иногда имя переменной намного короче, удобнее или названо более самодокументированным способом.

Ответ 4

статические методы можно вызвать также с помощью объекта класса, как это можно сделать на Java. Тем не менее, вы не должны этого делать. Используйте оператор области видимости как Test::DoCrash(); Возможно, вы думаете о пространствах имен:

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

который может быть вызван только Test::DoCrash(); извне этого пространства имен, если функция не импортируется явно с помощью using directive/declaration в область действия вызывающего.