significado - O que a sintaxe de C++ “A:: B: A{}” significa




sintaxe c++ (2)

Antes de mais nada, struct B; é uma declaração direta da estrutura B no namespace global. Pode ser confuso porque na verdade não é relevante neste exemplo. Este B global pode ser acessado como ::B ou apenas como B

struct A {
    struct B;
};

É uma definição de struct A no namespace global com uma declaração avançada de struct aninhada B (não é a mesma que B anteriormente declarada no namespace global). Este aninhado B pode ser acessado como ::A::B ou A::B

struct A::B:A {
};

É uma definição de struct aninhada B de struct A que herda de A (com o especificador de acesso omitido). Pode ser reescrito para:

struct A::B
:   public A
{
};

Note que escrever a definição de uma estrutura aninhada dentro de A definição como esta não funcionará:

struct A {
    struct B: A { // error: A is incomplete at this point
    };
};

E finalmente A::B::A está se referindo à classe base da estrutura aninhada B , que é A , então A::B::A::B é equivalente a apenas A::B

O que a sintaxe de C ++ struct A::B:A {}; significar? Onde esta definição de nome (ou acesso) é descrita no padrão C ++?

#include <iostream>

struct B;

struct A {
    struct B;
};

struct A::B:A {
};

int main() {
    A::B::A::B b;
    std::cout<<"Sizeof A::B::A::B is " << sizeof(A::B::A::B)<<std::endl;
    return 0;
}

Esta definição

struct A {
    struct B;
};

Define uma estrutura A com uma declaração de uma estrutura aninhada B 1 . O nome completo de B é A::B , você poderia dizer que B está dentro do "namespace" de A Então isso:

struct A::B : A { // Note I added spaces
};

É a definição de A::B , e o single : especifica que é derivado de A

Agora, a parte interessante é A::B::A::B Vamos dissecar isso:

  1. A::B nomeia a estrutura aninhada.
  2. A::B::A acessa o nome da classe injetada A dentro de B A injeção é devida à herança.
  3. A::B::A::B nomeia a estrutura aninhada B em A novamente.

E você pode continuar ad-infinitum, ou pelo menos até o seu compilador atingir seu limite de tradução 2 .

Um divertido exercício intelectual, mas evite como a praga no código real.

[class.qual]/1 explica como funciona a pesquisa

Se o aninhado-nome-especificador de um ID-qualificado nomear uma classe, o nome especificado após o especificador -nome-aninhado é procurado no escopo da classe ([class.member.lookup]), exceto para os casos listados abaixo. O nome deve representar um ou mais membros dessa classe ou de uma de suas classes base (Cláusula [class.derived]).

E o texto acima nos permite nomear a classe base porque [class]/2

O nome da classe também é inserido no escopo da própria classe; isso é conhecido como o nome da classe injetada . Para fins de verificação de acesso, o nome da classe injetada é tratado como se fosse um nome de membro público.

O acima diz claramente que iniciar um nome totalmente qualificado com A:: permite que você especifique um membro ou uma classe base. Como A não tem bases, você só pode especificar A::B (um "tipo de membro"). Mas A::B também nomeia uma classe. Portanto, podemos especificar uma base ou um membro disso também com A::B:: , o que nos permite nomear A::B::A Agora enxágüe e repita.

1 - Note que é completamente outro B Nada relacionado com a struct B global struct B
2 - Um mínimo recomendado de 256 de acordo com [implimits]/2.36





scope-resolution