Подтвердить что ты не робот

Почему вызывает статическую функцию-член. или → синтаксис законный?

Возможный дубликат:
Вызов метода статического члена С++ в экземпляре класса

Сегодня я обнаружил, что что-то, что у меня было давно (и я имею в виду давно, например, двадцать лет), считалось незаконным в С++, действительно легально. А именно, вызов статической функции-члена, как если бы она принадлежала отдельному объекту. Например:

struct Foo
{
    static void bar() { cout << "Whatever."; }
};

void caller()
{
    Foo foo;
    foo.bar();    // Legal -- what?
}

Обычно я вижу, что статические функции-члены называются строго с "синтаксисом разрешения разрешения", таким образом:

Foo::bar();

Это имеет смысл, потому что статическая функция-член не связана с каким-либо конкретным экземпляром класса, поэтому мы не ожидаем, что конкретный экземпляр будет синтаксически "прикреплен" к вызову функции.

Однако я обнаружил, что GCC 4.2, GCC 4.7.1 и Clang 3.1 (как случайная выборка компиляторов) принимают прежний синтаксис, а также:

Foo* foo = new Foo;
foo->bar();

В моем конкретном случае законность этого выражения привела к ошибке времени выполнения, которая убедила меня в том, что особенность этого синтаксиса имеет больший академический интерес - это имеет практические последствия.

Почему С++ разрешает статические функции-члены вызываться так, как если бы они были непосредственными членами отдельных объектов, то есть с помощью. или → , прикрепленный к экземпляру объекта?

4b9b3361

Ответ 1

Предположительно, вы можете вызвать его в местах, где вы, возможно, не знаете тип класса, но компилятор делает.

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

class Foo
{
    static const char* ClassName() { return "Foo"; }
};

class Bar
{
    static const char* ClassName() { return "Bar"; }
};

Затем по всему моему коду я мог делать такие вещи, как:

Foo foo;

printf( "This is a %s\n", foo.ClassName() );    

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

Ответ 2

В дизайне и эволюции С++ на стр. 288 Bjarne Stroustrup упоминает, что за несколько дней до статических функций-членов программисты использовали хаки типа ((X*)0)->f() для вызова функций-членов, которым не нужен объект. Я предполагаю, что когда статические функции-члены были добавлены к языку, доступ через -> был разрешен, так что программисты с таким кодом могли бы изменить f на static без необходимости выслеживать и изменять каждое его использование.

Ответ 3

Это так, потому что стандарт говорит, что он работает. n3290 § 9.4:

Статический член класса X может ссылаться на использование идентификатора с квалификацией выражение X::s; нет необходимости использовать доступ к члену класса синтаксис (5.2.5) для ссылки на статический член. Статический член может быть ссылается на использование синтаксиса доступа к члену класса, и в этом случае выражение объекта оценивается. [Пример:

struct process { 
  static void reschedule(); 
}; 

process& g();

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

конец примера]

Ответ 4

Из Эволюция С++ (pdf), раздел 8. Статические функции участника:

... Было также отмечено, что непереносимый код, например

    ((x*)0)->f();

использовался для моделирования статических функций-членов.

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

Ответ 5

Если вы не подписываетесь на "потому что стандарт говорит так" школу причинности, я также предлагаю, чтобы статические методы были достаточно старыми, чтобы происходить с того времени, когда люди действительно беспокоились о дополнительных накладных расходах от прохождения this аргумент для вызова функции, поэтому чистые функции "статические" в качестве оптимизации, вероятно, были в ярости в 1985 году.