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

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

#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!».

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

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

Что с тегом mvc?

Kiril 14.04.2012 01:02

Исправлено: в то время я мог смешивать с msvc, я думал, что это проблема компилятора.

Klaim 14.04.2012 06:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
46
2
69 429
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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

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

Да, я знаю, что должен это сделать, поэтому я спрашиваю, почему другой способ (звонки как член) разрешен / не запрещен. :)

Klaim 28.11.2008 17:38
Ответ принят как подходящий

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

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
}

Вау, я никогда этого не знал. Я предполагаю, что вызываемая функция основана только на типе времени компиляции (а не на типе времени выполнения) выражения?

Seth Carnegie 14.04.2012 06:44

@SethCarnegie: Да, он использует тип времени компиляции объекта (или его ссылку), вы не можете получить динамическую отправку статическим методам-членам.

David Rodríguez - dribeas 14.04.2012 07:33

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

k.DoCrash();

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

Test::DoCrash();

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

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

Я лучше скажу передать указатель this в качестве параметра вместо положи это в стопку. Фактический способ зависит от соглашения о вызовах конкретной платформы. Однако +1 за упоминание об этой особенности статических методов.

Melebius 23.10.2014 16:22

Есть одно отличие: в k.DoCrash() оценивается префикс k. Если k - это просто имя объекта, это, вероятно, не имеет значения, но это может быть вызов функции или какое-либо другое выражение с побочными эффектами: func().DoCrash()

Keith Thompson 27.08.2015 04:01

@KeithThompson Вау, это выглядит странно. func() в вашем примере обязательно возвращает объект Test?

feng 12.03.2019 08:40

@feng: Да, для того, чтобы func().DoCrash() был действительным, func() должен возвращать результат типа Test. Или у вас может быть arr[func()].DoCrash(), где arr - это массив объектов Test, а func() - функция, возвращающая некоторый целочисленный тип.

Keith Thompson 12.03.2019 12:04

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 вызов статических методов через экземпляр работает, но генерирует предупреждение компилятора о переменной, на которую нет ссылки, если переменная не используется ни для чего, кроме вызова статического метода.

abelenky 24.11.2015 01:54

Другие вопросы по теме