Qual é o significado de dois pontos duplos "::"?


410

Eu encontrei esta linha de código em uma classe que eu tenho que modificar:

::Configuration * tmpCo = m_configurationDB;//pointer to current db

e não sei exatamente o que significa dois pontos duplos anexado ao nome da classe. Sem isso, eu leria: declaração de tmpCocomo um ponteiro para um objeto da classe Configuration... mas os dois pontos duplos anteriores me confundem.

Eu também encontrei:

typedef ::config::set ConfigSet;

7
Realmente não acho que seja uma resposta, então vou comentar: en.wikipedia.org/wiki/Scope_resolution_operator . Nesse contexto, os ::meios nus referenciam a variável do namespace global / anônimo.
Wkl

Respostas:


490

Isso garante que a resolução ocorra no namespace global, em vez de iniciar no namespace em que você está atualmente. Por exemplo, se você tivesse duas classes diferentes chamadas Configurationcomo tais:

class Configuration; // class 1, in global namespace
namespace MyApp
{
    class Configuration; // class 2, different from class 1
    function blah()
    {
        // resolves to MyApp::Configuration, class 2
        Configuration::doStuff(...) 
        // resolves to top-level Configuration, class 1
        ::Configuration::doStuff(...)
    }
}

Basicamente, ele permite percorrer o espaço para nome global, já que seu nome pode ser derrotado por uma nova definição dentro de outro espaço para nome, nesse caso MyApp.


Qual é a razão para colocar 2 conjuntos de dois pontos duplos? Neste:::Configuration::doStuff(...)
Azurespot

@NoniA. você está perguntando o que o segundo conjunto de dois pontos duplos faz?
FCo 02/06

1
@ WyattAnderson, não o primeiro set. Acho que entendo que os ::dois termos intermediários se referem ao espaço para nome ou classe e seu membro. Mas e o primeiro?
Azurespot 3/17/17

6
@ Azurespot é o que o OP pede, essa é a pergunta que este post responde. Ele certifica-se de usar o identificador do espaço para nome global. Veja o exemplo novamente
hungryWolf

193

O ::operador é chamado de operador de resolução de escopo e, justamente isso, resolve o escopo. Portanto, prefixando um nome de tipo com isso, ele diz ao seu compilador para procurar no espaço de nomes global pelo tipo.

Exemplo:

int count = 0;

int main(void) {
  int count = 0;
  ::count = 1;  // set global count to 1
  count = 2;    // set local count to 2
  return 0;
}

122

Muitas respostas razoáveis ​​já. Vou abordar uma analogia que pode ajudar alguns leitores. ::funciona muito parecido com o separador de diretório do sistema de arquivos ' /', ao pesquisar seu caminho para um programa que você gostaria de executar. Considerar:

/path/to/executable

Isso é muito explícito - apenas um executável no local exato na árvore do sistema de arquivos pode corresponder a essa especificação, independentemente do PATH em vigor. Similarmente...

::std::cout

... é igualmente explícito no espaço para nome C ++ "árvore".

Contrastando com esses caminhos absolutos, você pode configurar boas shells do UNIX (por exemplo, zsh ) para resolver caminhos relativos no diretório atual ou em qualquer elemento da PATHvariável de ambiente, por isso PATH=/usr/bin:/usr/local/bin, se você estiver dentro /tmp, então ...

X11/xterm

... seria executado feliz /tmp/X11/xtermse encontrado, mais /usr/bin/X11/xterm, mais /usr/local/bin/X11/xterm. Da mesma forma, digamos que você estava em um espaço para nome chamado Xe teve um " using namespace Y" efeito, então ...

std::cout

... pode ser encontrada em qualquer um ::X::std::cout, ::std::cout, ::Y::std::cout, e possivelmente outros lugares devido à pesquisa dependentes do argumento (ADL, também conhecido como Koenig lookup). Portanto, apenas ::std::couté realmente explícito exatamente exatamente qual objeto você quer dizer, mas felizmente ninguém em seu perfeito juízo jamais criaria sua própria classe / estrutura ou espaço de nome chamado " std", nem qualquer coisa chamada " cout", portanto, na prática, usar apenas std::coutestá bem.

Diferenças notáveis :

1) shells tendem a usar a primeira correspondência usando a ordem de entrada PATH, enquanto o C ++ gera um erro de compilador quando você é ambíguo.

2) No C ++, nomes sem nenhum escopo à frente podem ser correspondidos no namespace atual, enquanto a maioria dos shells do UNIX só fazem isso se você inserir .o PATH.

3) O C ++ sempre pesquisa no espaço para nome global (como ter /implicitamente o seu PATH).

Discussão geral sobre namespaces e explicitação de símbolos

::abc::def::...Às vezes, o uso de "caminhos" absolutos pode ser útil para isolá-lo de qualquer outro espaço de nome que você esteja usando, parte de, mas realmente não tem controle sobre o conteúdo ou mesmo outras bibliotecas que o código de cliente da sua biblioteca também usa. Por outro lado, também o acopla mais firmemente ao local "absoluto" existente do símbolo e você perde as vantagens da correspondência implícita nos espaços para nome: menos acoplamento, mobilidade mais fácil do código entre espaços para nome e código-fonte legível e conciso .

Como em muitas coisas, é um ato de equilíbrio. Os puts lotes C ++ padrão dos identificadores sob std::que são menos "único" do que cout, que os programadores podem usar para algo completamente diferente no seu código (por exemplo merge, includes, fill, generate, exchange, queue, toupper, max). Duas bibliotecas não-padrão não relacionadas têm uma chance muito maior de usar os mesmos identificadores, já que os autores geralmente não têm ou menos consciência um do outro. E as bibliotecas - incluindo a biblioteca C ++ Standard - alteram seus símbolos ao longo do tempo. Tudo isso potencialmente cria ambiguidade ao recompilar o código antigo, principalmente quando há um uso pesado de using namespaces: a pior coisa que você pode fazer nesse espaço é permitirusing namespaces nos cabeçalhos para escapar do escopo dos cabeçalhos, de forma que uma quantidade arbitrariamente grande de código de cliente direto e indireto não consiga tomar suas próprias decisões sobre quais namespaces usar e como gerenciar ambiguidades.

Portanto, um líder ::é uma ferramenta na caixa de ferramentas do programador C ++ para desambiguar ativamente um conflito conhecido e / ou eliminar a possibilidade de ambiguidade futura.


8
+1 para uma boa analogia. analogias não são usadas quase o suficiente IMO como uma ferramenta de ensino.
Trevor Boyd Smith

38

::é o operador de resolução do escopo. É usado para especificar o escopo de algo.

Por exemplo, ::sozinho é o escopo global, fora de todos os outros namespaces.

some::thing pode ser interpretado de qualquer uma das seguintes maneiras:

  • someé um espaço para nome (no escopo global, ou um escopo externo que o atual) e thingé um tipo , uma função , um objeto ou um espaço para nome aninhado ;
  • someé uma classe disponível no escopo atual e thingé um objeto membro , função ou tipo da someclasse;
  • em uma função de membro da classe , somepode ser um tipo base do tipo atual (ou o próprio tipo atual) e thingé um membro dessa classe, um tipo , função ou objeto .

Você também pode ter escopo aninhado, como em some::thing::bad. Aqui cada nome pode ser um tipo, um objeto ou um espaço para nome. Além disso, o último bad,, também pode ser uma função. Os outros não, porque as funções não podem expor nada dentro de seu escopo interno.

Portanto, voltando ao seu exemplo, ::thingpode haver apenas algo no escopo global: um tipo, uma função, um objeto ou um espaço para nome.

A maneira como você o usa sugere (usado em uma declaração de ponteiro) que é um tipo no escopo global.

Espero que esta resposta seja completa e correta o suficiente para ajudá-lo a entender a resolução do escopo.


2
@obounaim Considere este código liveworkspace.org/code/3Wabw0$5 class some { protected: int thing; }; class some_ext : public some { float thing; void action(){ some::thing = 42; thing = 666; } }; Aqui someestá uma classe base de some_exte quando você escreve some::thingem funções-membro de some_ext, significa o thingobjeto no tipo base some. Sem some::, thingsozinho significa o que está thingno escopo mais próximo some_ext::thing. Está mais claro?
Klaim

17

:: é usado para vincular algo (uma variável, uma função, uma classe, um typedef etc ...) a um espaço para nome ou a uma classe.

se não houver lado esquerdo antes ::, sublinha o fato de que você está usando o espaço para nome global.

por exemplo:

::doMyGlobalFunction();


10

seu chamado operador de resolução de escopo, Um nome global oculto pode ser referido usando o operador de resolução de escopo:
Por exemplo;

int x;
void f2()
{
   int x = 1; // hide global x
   ::x = 2; // assign to global x
   x = 2; // assign to local x
   // ...
}

10

(Essa resposta é principalmente para os googlers, porque o OP já resolveu seu problema.) O significado de prefixado ::- operador de resolução de escopo - foi descrito em outras respostas, mas eu gostaria de acrescentar por que as pessoas o estão usando.

O significado é "pegue o nome do espaço para nome global, e não mais nada". Mas por que isso precisaria ser escrito explicitamente?

Caso de uso - conflito de namespace

Quando você tem o mesmo nome no namespace global e no namespace local / aninhado, o local será usado. Portanto, se você quiser o global, acrescente-o com ::. Este caso foi descrito na resposta de Wyatt Anderson, veja seu exemplo.

Caso de uso - enfatizar função não membro

Quando você está escrevendo uma função de membro (um método), as chamadas para outra função de membro e as chamadas para funções de não membro (gratuitas) são parecidas:

class A {
   void DoSomething() {
      m_counter=0;
      ...
      Twist(data); 
      ...
      Bend(data);
      ...
      if(m_counter>0) exit(0);
   }
   int m_couner;
   ...
}

Mas pode acontecer que Twistseja uma função irmã da classe Ae Bendseja uma função livre. Ou seja, Twistpode usar e modificar m_counere Bendnão pode. Portanto, se você deseja garantir que m_counterpermaneça 0, você precisa verificar Twist, mas não precisa verificar Bend.

Portanto, para tornar isso mais claro, é possível escrever this->Twistpara mostrar ao leitor que Twisté uma função membro ou escrever ::Bendpara mostrar que Bendé gratuito. Ou ambos. Isso é muito útil quando você está fazendo ou planejando uma refatoração.


5

:: é um operador de definição do espaço para nome.

Por exemplo, se você deseja usar o cout sem mencionar using namespace std;no seu código, escreva isto:

std::cout << "test";

Quando nenhum espaço para nome é mencionado, é dito que a classe pertence ao espaço para nome global.


1

"::" representa o operador de resolução do escopo. Funções / métodos com o mesmo nome podem ser definidos em duas classes diferentes. Para acessar os métodos de um operador de resolução de escopo de classe específico, é usado.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.