Что значит, если вызов метода начинается с двух двоеточий?

сотрудник обычно пишет что-то вроде этого:

::someObject->someMethod(anAttribute, anotherAttribute);

someObject глобальная переменная.
Эти две двоеточия кажутся мне странными. Код компилируется и отлично работает без них.

коллега утверждает, что эти двоеточия сделать someObject явно глобальный и, таким образом, предотвращает путаницу с возможным локальным someObject. Я бы подумал, что вы не сможете определить someObject локально, если он уже был определен во всем мире?

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

4 ответов


ваш коллега прав. Вы действительно можете определить local someObject который скроет глобальный someObject в этой области:

SomeClass* someObject = ...;

// here the global object is visible
someObject->someMethod(anAttribute, anotherAttribute); // calls the global object

void someMethod() {
  SomeClass* someObject = ...;
  // here the local object hides the global
  ::someObject->someMethod(anAttribute, anotherAttribute); // calls the global object
  someObject->someMethod(anAttribute, anotherAttribute);   // calls the local object
}

// here again only the global object is visible
someObject->someMethod(anAttribute, anotherAttribute); // calls the global object

области могут быть внедрены в другие области рекурсивно, таким образом, у вас может быть пространство имен в глобальной области, класс в пространстве имен, внутренний класс в классе, метод во внутреннем классе, блок в методе... так далее. И у вас могут быть переменные / классы/методы/... одинаковых имен в любой из этих областей. Итак, идентификация то, на что ссылается конкретное имя, не является тривиальной задачей в C++. Он известен как имя подстановки.

короче говоря, всякий раз, когда компилятор находит имя, он ищет это имя, начиная с самой внутренней области. Т. е. внутри someMethod имя someObject соответствует объекту, определенному локально. ::someObject переопределяет это поведение по умолчанию и делает поиск компилятора только в самой внешней (глобальной) области, таким образом, он находит глобальный объект вместо местный.


вы действительно можете определить someObject локально, даже если есть глобальный. Две переменные имеют разную область действия, поэтому компилятор знает, что между ними есть разница, и двойные двоеточия позволяют ссылаться на глобальный.

Это также относится к классам вне пространства имен; т. е. для ссылки на класс Foo из класса Bar:: Foo вы используете:: Foo, чтобы сообщить компилятору, что вы говорите о том, которого нет в пространстве имен.

вот пример это показывает, что он работает:

#include<stdio.h>

int someInt = 4;

int main() {
        int someInt = 5;
        printf("%d", someInt+::someInt);
        return 0;
}

Если вы скомпилируете и запустите этот фрагмент кода, он выведет 9.


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

Yes-это означает, что функция может и должна быть сопоставлена только в глобальном пространстве имен. Это делает очевидным, что вы имеете дело с глобальным и предотвратит случайное сопоставление с чем-то более локальным (локальная функция beit, член объекта, член пространства имен, в пространстве имен, которое вы используете, поиск Koenig матч и т. д.).

Я бы подумал, что вы не будете возможность определить someObject локально, если он уже был определен глобально?

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

относительно преимуществ::, рассмотрим:

namespace X
{
    void fn() {
        rip(data, bytes); // MP3 rip this data
    }
}

...тогда fn() необходимо быстро переместить в пространство имен Y...

namespace Y
{
    void rip(const char* message, int exit_code); /* for fatal errors */
    ...
}

...случайная вставка копии в кишки Y может легко пропустить, что журнал не будет соответствовать той же глобальной функции, которую он использовал, когда fn был в пространстве имен X, но - как показано-функциональность может заметно отличаться :-).

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

не могли бы вы пролить свет на то, что эти двоеточия означают и являются ли они надо?

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


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

в основном :: вызывает полный поиск имен в глобальном пространстве имен. Однако это не гарантирует отсутствия проблем, особенно перед лицом неизбирательного использования директив.

показанный код иллюстрирует важное свойство поиска полного имени. Дело в том, что пространства имен, выдвинутых с помощью директив глобального namspace искали. Однако использование директив в пространствах имен, в которых выполняется поиск имени, пропускаются.

    namespace Z{
        void f(){cout << 1;}
    }

    namespace Y{
        void f(){cout << 2;}
        using namespace Y;     // This namespace is not searched since 'f' is found in 'Y'
    }

#if 0
    namespace Z{
        void f(){cout << 3;}
        using namespace Y;     // This namespace is not searched since 'f' is found in 'Y'
    }
    using namespace Z;
#endif
    using namespace Y;

    int main(){
        ::f();                 // Prints 2. There is no ambiguity
    }

в показанном коде, если строки с директивой #if включены, существует двусмысленность в разрешении имени "f".