Bonjour à tous.
J'ai un problème que je ne comprends pas et dont j'ai une solution qui ne me plait pas du tout.

Soient trois d'interfaces avec implémentation par défaut:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
struct BaseSimple {
    virtual ~BaseSimple() = 0;
    virtual void simple() { cout << "BaseSimple" << endl; }
};
 
struct BaseRiche: public BaseSimple {
    virtual ~BaseRiche() = 0;
    virtual void riche() {}
};
 
struct Biduloide {
    virtual ~Biduloide() = 0;
    virtual void operator() () {}
};
Les trois destructeurs sont définis à l'abri des fichiers .cpp.

Jusque là, tout va bien, j'ai trois classes abstraites, dont un héritage.

Viennent ensuite deux classes qui ne pose pas encore problème.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Simple: public BaseSimple, public Biduloide {
public:
    virtual void simple() override final {
        /* un peu d'intelligence */
        do_simple();
    }
protected:
    virtual void do_simple() {}
};
 
 
class MoinsSimple: public Simple {
protected:
    virtual void do_simple() override final { cout << "MoinsSimple" << endl;}
};
Si à présent j'écris ceci:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
BaseSimple * s = new MoinsSimple();
s->simple();
J'espère bien voir s'afficher "MoinsSimple", puisque c'est ainsi que doit fonctionner les fonctions virtuelles.
En effet, s->simple() est Simple::simple(), qui appelle Simple::do_simple(), virtuelle donc trouvée dans MoinsSimple.

Ajoutons une nouvelle classe:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
class Riche: public BaseRiche, public MoinsSimple {
public:
    using MoinsSimple::simple
};
D'après le standard, j'ai le layout suivante: <Riche> = < <<BaseSimple> BaseRiche> <<<BaseSimple> Simple> MoinsSimple> >.
Je vois bien que j'ai deux BaseSimple.
J'ai ainsi trois définitions de simple(): deux dans les BaseSimple, et une dans Simple (cette dernière version étant marquée final)

Si ma lecture était bonne, simple serait ambigüe dans Riche, donc j'ai écris un using MoinsSimple::simple.
Or, ce n'est pas le cas.
Le code suivant affiche "BaseSimple"
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
BaseRiche * s = new Riche();//pour des raisons de smart_ptr à partager un peu partout
s->simple();
EDIT: dans mon vrai problème le pointeur n'est pas Riche* mais BaseRiche*

J'ai bien une solution en rendant Simple::simple() non finale, et en écrivant:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
class Riche: public BaseRiche, public MoinsSimple {
public:
    virtual void simple() override final {MoinsSimple::simple();}
};
Mais je n'ai pas de raison de le faire, puisque c'est précisément pour la rendre final que j'ai créé do_simple().

Je pourrai peut-être m'en sortir avec de l'héritage virtuel, mais j'aimerai surtout comprendre pourquoi j'ai ce problème.