web-dev-qa-db-fra.com

Base ambiguë avec héritage multiple

J'essaie d'écrire des sous-classes de classes dans une grande bibliothèque. Je reçois une erreur "de base ambiguë". Voici un exemple compilable du problème:

#include <iostream>

// I can't change these because they are in the library:
class InteractorStyle {};
class InteractorStyleCamera : public InteractorStyle {};
class InteractorStyleImage : public InteractorStyle {};

// These are my subclasses (so I can change them):
class PointSelector : public InteractorStyle {};
class PointSelector2D : public InteractorStyleCamera, public PointSelector
{
  // This function has to exist exactly like this (a requirement of the library):
  static PointSelector2D* SafeDownCast(InteractorStyle *o)
  {
    return static_cast<PointSelector2D *>(o);
  } 
};


int main()
{

  return 0;
}

L'erreur est

erreur: "InteractorStyle" est une base ambiguë de "PointSelector2D".

Y a-t-il quelque chose que je puisse faire dans ce cas?

21
David Doria

Votre problème est que le style Interactor est hérité deux fois - une fois par PointSelector2D et une fois par InteractorStyleCamera. Cela signifie que vous avez 2 versions de chaque membre de celle-ci dans votre classe.

Check-out:

Comment puis-je éviter le Diamant de la Mort en utilisant l'héritage multiple?

Et essayez l'héritage virtuel.

16

Vous pouvez le "réparer" superficiellement en utilisant un casting en deux étapes. Par exemple

static_cast<PointSelector2D *>(static_cast<InteractorStyleCamera *>(o));

Bien sûr, vous devez garder à l'esprit que cela "corrige" la syntaxe, mais pas le problème structurel sous-jacent. Votre PointSelector2D contient deux sous-objets InteractorStyle base. Selon les sous-objets de base InteractorStyle que vous démarrez, le chemin de la diffusion ascendante est différent. Et il est très important de prendre le bon chemin. Ce que j'ai écrit ci-dessus est pour InteractorStyle à l'intérieur de InteractorStyleCamera. Pour l’autre base, le upcast approprié serait

static_cast<PointSelector2D *>(static_cast<PointSelector *>(o));

Si un pointeur InteractorStyle * ne contient que des informations supplémentaires sur la base pointée, il est impossible de résoudre votre problème avec static_cast. Il n'y a aucun moyen de savoir quel chemin upcast prendre. Prendre le mauvais produira un résultat totalement dénué de sens.

Comme il a déjà été noté, dynamic_cast peut aider dans cette situation, mais il a des exigences supplémentaires (type de départ polymorphe). Vos types ne sont pas polymorphes (du moins dans votre exemple cité), donc dynamic_cast ne les acceptera pas pour les diffusions ultérieures.

4
AnT

Je crois que vous pouvez résoudre ce problème en utilisant un dynamic_cast au lieu d'un static_cast. Le dynamic_cast peut examiner l'objet au moment de l'exécution pour déterminer laquelle des deux classes de base InteractorStyle est pointée, puis à partir de là, il peut ajuster le pointeur au type approprié.

3
templatetypedef

Vous pouvez obtenir votre code à compiler (votre exemple à compiler au moins) en ajoutant InteractorStyle aux classes dont PointSelector2D hérite. Je ne sais pas s'il s'agit d'une solution à long terme.

0
Seth Carnegie