next up previous contents
Next: Liaison dynamique Up: Héritage multiple Previous: Héritage partagé

Ambiguïtés

En C++,l'accès aux membres de la classe doit être sans ambiguïté. Le contrôle d'accès n'intervient pas en ce qui concerne l'ambiguïté.

class A{
  int a;
  void f();
public:
  void g();  
};
class B{
  int b;
  void f()
public:
  int a;
};
class C: public A, public B{
  int b; // occulte B::b
public:
  void g(int);  // occulte A::g()
}c;
//...
c.g();            // interdit A::g() hors de portée
c.g(i);           // ok C::g(int)
c.a;              // interdit A::a ou B::a ?
c.B::a;           // ok visible
c.A::a;           // interdit A::a est privé

Pour associer un nom de fonction à sa déclaration le compilateur procédera ainsi:

  1. portée : rechercher dans la relation d'héritage, les classes de base telles qu'il y a une déclaration dans la protée du nom : s'il y en a plusieurs, et qu'aucune ne domine les autres (cf. plus loin) il y a ambiguïté et le compilateur rejette.
  2. surcharge : ensuite associer le nom à sa déclaration avec les règles de la surcharge : il ne doit bien sûr ne pas y avoir d'ambiguïté.
  3. contrôle d'accès : vérifier que l'on a droit d'accéder au nom trouvé dans les étapes précédentes

En partageant les noms, l'héritage virtuel permet aussi d'éviter les ambiguïtés:

class V{
public:
  int v;};
class A{
public:
  int a;};
class D1: public A, virtual public V{};
class D2: public A, virtual public V{};
class X:public D1, public D2{
public:void f();
};
void X::f(){
  v++; // partage de V.v
  a++; // a de D1 ou de D2
};

Le C++ définit une relation de domination entre les noms : un nom B::f domine un nom A::f si la classe A est une classe de base pour B (c'est la relation d'héritage telle qu'elle a été définie ci-dessus). En ce qui concerne l'héritage ``non-virtuel'' (simple ou multiple) c'est la règle standard : on parcourt la relation d'héritage, et on associe le nom à la déclaration la plus proche pour cette relation d'héritage ; avec l'héritage virtuel, cela signifie, que si un nom dans une classe de base héritée virtuellement est redéfini par un des descendants c'est cette redéfinition qui sera choisie :

class V{
public: void f(); int x;
};
class B : public virtual V{
public: void f(); int x;
}; //cache V::f et V::x
class C: public virtual V {};
class D: public B, public C {
void essai();
}
void D::essai(){
  x;   // ici B::x domine V::x
  f(); // B::f() domine V::f()
}




Mon Oct 20 14:02:48 MET 1997