Pergunta

Estou confuso:. Pensei dados protegidos foi lida / escrita pelas crianças de uma determinada classe em C ++

O fragmento abaixo falha ao compilar em MS Compiler

class A
{
protected:
  int data;
};

class B : public A
{
  public:

  B(A &a)
  {
    data = a.data;
  }
};

int main()
{
  A a;
  B b = a;
  return 0;
}

Mensagem de erro:

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

demoFail.cpp
demoFail.cpp(12) : error C2248: 'A::data' : cannot access protected member declared in class 'A'
        demoFail.cpp(4) : see declaration of 'A::data'
        demoFail.cpp(2) : see declaration of 'A'

O que estou fazendo de errado?

Foi útil?

Solução

De acordo com o TC ++ PL, PG 404:

A classe derivada pode acessar uma classe base membros protegidos apenas para objetos de seu próprio tipo .... Isto evita erros sutis que ocorreriam quando um derivado classe corrompe dados pertencentes a outras classes derivadas.

Claro, aqui está uma maneira fácil de corrigir isso para o seu caso:

class A
{
protected:
    int data;
};

class B : public A
{
public:
    B(const A &a)
        : A(a)
    {
    }
};

int main()
{
    A a;
    B b = a;
    return 0;
}

Outras dicas

O padrão C ++ diz sobre os membros não-estáticos protegidas pelo 11.5/1

Quando um amigo ou uma função de membro de uma classe de derivados referências uma função de membro não estática protegida ou protegida membro dados não estática de uma classe de base, aplica-se uma verificação de acesso em adição às descritas anteriormente na secção 11. Excepto quando se forma um ponteiro para membro (5.3.1), o acesso deve ser por meio de um ponteiro para, a referência a, ou objecto da própria classe derivada (ou qualquer classe derivada a partir dessa classe) (5.2.5). Se o acesso é para formar um ponteiro ao membro, o nested-nome-especificador devem citar a classe derivada (ou qualquer classe derivada a partir dessa classe).

Além de consertar as coisas mencionado anteriormente por outros (construtor de B é privado), eu acho que o caminho de rlbond vai fazê-lo bem. No entanto, uma consequência directa do parágrafo acima da norma é o seguinte que é possível utilizando um ponteiro membro, o que sem dúvida é um furo no sistema tipo, é claro

class B : public A {
public:
  B(A &a){
    int A::*dataptr = &B::data;
    data = a.*dataptr;
  }
};

Claro que, este código não é recomendado fazer, mas mostra que você pode acessá-lo, se você realmente precisa (eu vi desta forma sendo usado para imprimir uma std::stack, std::queue , std::priority_queue acessando sua c membro recipiente protegido)

Você só não deve copiar um objeto A em um construtor B. A intenção é deixar a inicialização de membros de A para seu próprio construtor:

struct A { 
  A( const A& a ): data( a.data ) {}
  protected: int data; 
};

struct B : public A {
  B( const A& a ): A( a ) {}
};

O construtor de B é privado. Se você não especificar nada, em uma classe, o modificador padrão é privado (para estruturas é público). Portanto, neste exemplo, o problema é que você não pode construir B. Quando você adiciona pública para o problema construtor B anoter surge:

B tem o direito de modificar a parte de uma deriva de, mas não outra Um, como neste caso.

Você poderia fazer seguinte:

class A
{
public:
  A()
      : data(0)
  {
  }
  A(A &a)
  {
    data = a.data;
  }
protected:
  int data;
};

class B : public A
{
public:
  B(A &a)
      : A(a)
  {
  }
};

int main()
{
  A a;
  B b = a;
  return 0;
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top