Вот небольшая тестовая программа:
#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!».
Насколько мне известно, статические методы-члены не должны вызываться для экземпляров объекта.
Исправлено: в то время я мог смешивать с msvc, я думал, что это проблема компилятора.





статические методы могут быть вызваны также с использованием объекта класса, как это можно сделать в Java. Тем не менее, делать этого не стоит. Используйте оператор области видимости, например Test::DoCrash();. Возможно, вы думаете о пространствах имен:
namespace Test {
void DoCrash() {
std::cout << "Crashed!!" << std::endl;
}
};
который может быть вызван Test::DoCrash(); только из-за пределов этого пространства имен, если функция не импортирована явно с использованием using directive/declaration в область действия вызывающего.
Да, я знаю, что должен это сделать, поэтому я спрашиваю, почему другой способ (звонки как член) разрешен / не запрещен. :)
Стандарт гласит, что нет необходимости вызывать метод через экземпляр, это не означает, что вы не можете этого сделать. Есть даже пример, где он используется:
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.
class process {
public:
static void reschedule();
};
process& g();
void f()
{
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
Вау, я никогда этого не знал. Я предполагаю, что вызываемая функция основана только на типе времени компиляции (а не на типе времени выполнения) выражения?
@SethCarnegie: Да, он использует тип времени компиляции объекта (или его ссылку), вы не можете получить динамическую отправку статическим методам-членам.
Статические функции не нуждаются в инстанциированном объекте для вызова, поэтому
k.DoCrash();
ведет себя точно так же, как
Test::DoCrash();
используя оператор разрешения области видимости (: :) для определения статической функции внутри класса.
Обратите внимание, что в обоих случаях компилятор не помещает указатель this в стек, поскольку статической функции он не нужен.
Я лучше скажу передать указатель this в качестве параметра вместо положи это в стопку. Фактический способ зависит от соглашения о вызовах конкретной платформы. Однако +1 за упоминание об этой особенности статических методов.
Есть одно отличие: в k.DoCrash() оценивается префикс k. Если k - это просто имя объекта, это, вероятно, не имеет значения, но это может быть вызов функции или какое-либо другое выражение с побочными эффектами: func().DoCrash()
@KeithThompson Вау, это выглядит странно. func() в вашем примере обязательно возвращает объект Test?
@feng: Да, для того, чтобы func().DoCrash() был действительным, func() должен возвращать результат типа Test. Или у вас может быть arr[func()].DoCrash(), где arr - это массив объектов Test, а func() - функция, возвращающая некоторый целочисленный тип.
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?
Это потенциально полезно в нескольких сценариях:
[предлагаемый вами метод "статический или нет" в шаблонах:], когда в шаблоне могло быть указано много типов, а затем шаблон хочет вызвать член: типы, обеспечивающие статическую функцию, могут быть вызваны с использованием той же нотации, что и функция-член - первая может быть более эффективной (нет указателя this для передачи / связывания), в то время как последний позволяет полиморфную (virtual) отправку и использование данных-членов
минимизация обслуживания кода
если функция эволюционирует от потребности в данных, специфичных для экземпляра, до того, что она не нужна - и поэтому она сделана static, чтобы обеспечить простое использование без экземпляра и предотвратить случайное использование данных экземпляра - все точки существующего использования клиента не нуждаются в кропотливом обновлении
если тип изменился, вызов var.f() продолжает использовать функцию типа var, тогда как для Type::f() может потребоваться ручная коррекция
когда у вас есть выражение или вызов функции, возвращающий значение, и вы хотите вызвать (потенциально или всегда) функцию static, нотация . может помешать вам использовать decltype или вспомогательный шаблон для получения доступа к типу, чтобы вы могли использовать обозначение ::
иногда имя переменной просто намного короче, удобнее или именуется более самодокументированным способом
По крайней мере, в компиляторе MSVC 2013 вызов статических методов через экземпляр работает, но генерирует предупреждение компилятора о переменной, на которую нет ссылки, если переменная не используется ни для чего, кроме вызова статического метода.
Что с тегом mvc?