Les données protégées dans la classe parente ne sont pas disponibles dans la classe par enfant?

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

  •  06-07-2019
  •  | 
  •  

Question

Je suis confus: je pensais que les données protégées étaient en lecture / écriture pour les enfants d'une classe donnée en C ++.

L'extrait de code ci-dessous ne parvient pas à être compilé dans le compilateur 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;
}

Message d'erreur:

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'

Qu'est-ce que je fais mal?

Était-ce utile?

La solution

Selon TC ++ PL, page 404:

  

Une classe dérivée peut accéder à une classe de base & # 8217; membres protégés uniquement pour les objets de son propre type .... Cela évite les erreurs subtiles qui se produiraient normalement lorsqu'une classe dérivée corrompt des données appartenant à d'autres classes dérivées.

Bien sûr, voici un moyen simple de résoudre ce problème dans votre cas:

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

Autres conseils

La norme C ++ dit à propos des membres non statiques protégés à 11.5 / 1

  

Lorsqu'un ami ou une fonction membre d'une classe dérivée fait référence à une fonction membre non statique protégée ou à un membre de données non statique protégé d'une classe de base, un contrôle d'accès s'applique en plus de ceux décrits précédemment dans l'article 11. Sauf lors de la création d'un pointeur sur membre (5.3.1), l'accès doit se faire par un pointeur, une référence ou un objet de la classe dérivée elle-même (ou de toute classe dérivée de cette classe) (5.2.5). Si l'accès doit former un pointeur sur member, le spécificateur de nom imbriqué doit nommer la classe dérivée (ou toute classe dérivée de cette classe).

En plus de corriger les choses mentionnées précédemment par d'autres (le constructeur de B est privé), je pense que la méthode de rlbond fera l'affaire. Cependant, une conséquence directe du paragraphe ci-dessus de la norme est que ce qui suit est possible en utilisant un pointeur de membre, ce qui est sans doute un trou dans le système de types, bien sûr

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

Bien sûr, ce code n’est pas recommandé, mais il indique que vous pouvez y accéder, si vous en avez vraiment besoin (je l’ai déjà vu utilisé pour imprimer un std :: stack , std :: queue , std :: priority_queue en accédant à son membre de conteneur protégé c )

Vous venez de ne pas copier un objet A dans un constructeur B . L’intention est de laisser l’initialisation des membres de A à son propre constructeur:

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

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

Le constructeur de B est privé. Si vous ne spécifiez rien, dans une classe, le modificateur par défaut est privé (pour les structures, il est public). Ainsi, dans cet exemple, le problème est que vous ne pouvez pas construire B. Lorsque vous ajoutez un problème public au constructeur B, un autre problème se pose:

B a le droit de modifier la partie de A dont il dérive mais pas un autre A comme dans ce cas.

Vous pouvez faire ce qui suit:

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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top