Pourquoi membre superclasse protégé ne peut pas être accessible dans une fonction de sous-classe lorsqu'elle est transmise comme un argument?

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

Question

Je reçois une erreur de compilation, que je suis un peu confus au sujet. Ceci est le VS2003.

error C2248: 'A :: y': ne peut pas accéder à un membre protégé déclaré dans la classe 'A'

class A
{
public:
  A() : x(0), y(0) {}
protected:
  int x;
  int y;
};

class B : public A
{
public:
  B() : A(), z(0) {}
  B(const A& item) : A(), z(1) { x = item.y;}
private:
  int z;
};

Le problème est avec x = item.y;

L'accès est spécifié comme protégé. Pourquoi ne pas le constructeur de la classe B ont accès à A :: y?

Était-ce utile?

La solution

Il est à cause de ceci:

class base_class
{
protected:
    virtual void foo() { std::cout << "base::foo()" << std::endl; }
};

class A : public base_class
{
protected:
    virtual void foo() { std::cout << "A::foo()" << std::endl; }
};

class B : public base_class
{
protected:
    virtual void foo() { std::cout << "B::foo()" << std::endl; }

public:
    void bar(base_class *b) { b->foo(); }
};

Si vous pouviez faire juridique, étaient ceci:

A a;
B b;
b.bar(&a);

Et vous appellerez un membre de protected de A à B, ce qui est interdit.

Autres conseils

Les autres réponses expliquent le raisonnement derrière la prévention de votre objet B d'accéder aux parties protégées de A dans votre exemple, même si B « est-a » A. Bien sûr, la meilleure façon de résoudre ce problème est de rendre les parties de A you want access topublic` ou ont des méthodes d'accès accessibles au public.

Cependant, vous pouvez décider que est inappropriée (ou vous pourriez ne pas avoir le contrôle sur la définition de A). Voici quelques suggestions pour vous permettre de contourner le problème, dans l'ordre croissant de subvertir le contrôle d'accès A. Notez que toutes ces solutions de contournement supposent que class A est copie constructible.

Dans le premier cas, vous utilisez simplement le constructeur de copie pour A de mettre en place un état initial pour cette partie de l'objet B, puis le corriger ensuite:

class B1 : public A
{
public:
  B1() : A(), z(0) {}
  B1(const A& item) : A(item), z(1) {
    // fix up the A sub-object that was copy constructed 
    //  not quite the way we wanted
    x = y;
    y = 0;
  }
private:
  int z;
};

Je trouve cette erreur incroyablement confus et probablement très tendance (en supposant que nous voulons que le sous-objet A dans l'objet B être différent de l'objet A étant passé au constructeur - une situation inhabituelle, mais il est ce qui a été donné en le problème). Cependant, le fait que cela peut être fait donne une justification pour les exemples les plus subversives qui suivent ...

L'exemple suivant crée un objet B temporaire qui a une copie exacte de l'objet que nous voulons A accès. On peut alors utiliser l'objet B temporaire pour accéder aux éléments qui ont été protégés:

class B2 : public A
{
public:
  B2() : A(), z(0) {}
  B2(const A& item) : A(), z(1) {
    // create a special-use B2  object that can get to the 
    //  parts of the A object we want access to
    B2 tmp( item, internal_use_only);

    x = tmp.y;  // OK since tmp is of type B
  }

private:
  int z;

  // create a type that only B2 can use as a 
  //    'marker' to call a special constructor 
  //    whose only purpose in life is to create
  //    a B object with an exact copy of another
  //    A sub-object in it
  enum internal_use {
    internal_use_only
  };
  B2( const A& item, internal_use marker) : A(item), z(0) {};
};

Je trouve que la solution soit un peu moins confus que le premier, mais il est encore confus (à mon avis). Avoir une version bâtarde de l'objet B juste pour obtenir les parties du Un objet que nous voulons est impair.

Nous pouvons faire quelque chose à ce sujet en créant une procuration spéciale pour les objets A qui donne l'accès que nous voulons. Notez que ceci est la solution de contournement « plus subversive », car il est quelque chose que toute la classe pourrait faire pour obtenir des pièces protégées de A, même si elles ne sont pas des sous-classes d'eux-mêmes A. Dans le cas de la classe B, il y a une certaine légitimité pour obtenir des pièces protégées d'objets A, puisque B est-un A, et comme nous l'avons déjà vu il y a des solutions de contournement qui nous permettent d'obtenir un accès qui utilisent les droits seulement qui class B déjà a, donc je considère cela une version plus propre de ces solutions de contournement dans le cas de class B.

class B3 : public A
{
public:
  B3() : A(), z(0) {}
  B3(const A& item) : A(), z(1) { 
    // a special proxy for A objects that lets us
    //  get to the parts of A we're interested in
    A_proxy tmp( item);
    x = tmp.get_y();
  }

private:
  int z;

    class A_proxy : public A
    {
    public:
        A_proxy( const A& other) : A(other) {};
        int get_x() {return x;};
        int get_y() {return y;};
    };

};

La documentation d'IBM résume le mieux:

  

Une classe de base non statique protégé   membre peut être consulté par les membres et   amis de toutes les classes dérivées de   cette classe de base en utilisant l'un des   suivant:

     
      
  • Un pointeur sur une classe dérivée directement ou indirectement
  •   
  • Une référence à une classe dérivée directement ou indirectement
  •   
  • Un objet d'une classe dérivée directement ou indirectement
  •   

Ainsi, en utilisant votre exemple ci-dessus comme base:

B::B(const A& item) : A(), z(1) {
  // NOT OK because `item` is not a reference to the derived class B
  //int i = item.y; 

  // OK because `item` reinterpreted as a reference to the derived class B
  // Do not do this (bad!) -- for illustrative purposes only
  int i = reinterpret_cast< const B& >(item).y;

  // OK because it is equivalent to `this->x = i`,
  //  where `this` is a pointer to the derived class B
  x = i;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top