I dati protetti nella classe genitore non sono disponibili nella classe figlio?

StackOverflow https://stackoverflow.com/questions/1414506

  •  06-07-2019
  •  | 
  •  

Domanda

Sono confuso: pensavo che i dati protetti fossero letti / scrivibili dai bambini di una determinata classe in C ++.

Lo snippet seguente non riesce a compilare nel compilatore MS

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;
}

Messaggio di errore:

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'

Cosa sto facendo di sbagliato?

È stato utile?

Soluzione

Secondo TC ++ PL, pag. 404:

  

Una classe derivata può accedere ai membri protetti di una classe base solo per oggetti del proprio tipo .... Questo impedisce errori sottili che altrimenti si verificherebbero quando una classe derivata corrompe i dati appartenenti ad altre classi derivate.

Naturalmente, ecco un modo semplice per risolvere questo problema nel tuo 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;
}

Altri suggerimenti

Lo standard C ++ dice sui membri non statici protetti su 11.5/1

  

Quando un amico o una funzione membro di una classe derivata fa riferimento a una funzione membro non statica protetta o a un membro dati non statico protetto di una classe base, si applica un controllo di accesso in aggiunta a quelli descritti in precedenza nella clausola 11. Tranne quando si forma un puntatore a membro (5.3.1), l'accesso deve avvenire tramite un puntatore, riferimento o oggetto della classe derivata stessa (o qualsiasi classe derivata da quella classe) (5.2.5). Se l'accesso deve formare un puntatore al membro, l'identificatore del nome nidificato deve nominare la classe derivata (o qualsiasi classe derivata da quella classe).

Oltre a sistemare le cose menzionate in precedenza da altri (il costruttore di B è privato), penso che il modo di rlbond lo farà bene. Tuttavia, una conseguenza diretta del precedente paragrafo della norma è che è possibile utilizzare quanto segue un puntatore membro, che è probabilmente un buco nel sistema dei tipi, ovviamente

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

Ovviamente, questo codice non è consigliato, ma mostra che puoi accedervi, se ne hai davvero bisogno (ho visto questo modo essere usato per stampare un std :: stack , std :: queue , std :: priority_queue accedendo al suo membro contenitore protetto c )

Devi solo non copiare un oggetto A in un costruttore B . L'intenzione è di lasciare l'inizializzazione dei membri di A al proprio costruttore:

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

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

Il costruttore di B è privato. Se non specifichi nulla, in una classe, il modificatore predefinito è privato (per le strutture è pubblico). Quindi in questo esempio il problema è che non è possibile costruire B. Quando si aggiunge pubblico al costruttore B si presenta un problema anoter:

B ha il diritto di modificare la parte di A da cui deriva ma non un'altra A come in questo caso.

Puoi fare quanto segue:

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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top