Search code examples
c++inheritancepolymorphismambiguity

Virtual inheritance / Polymorphism


So I'm looking at some weird cases of Polymorhpism and ambiguity. And there's one case which I cannot understand. I don't understand why the last line of the code below act this way.

#include <stdio.h>
#include <iostream>

class Article
{
public :
    virtual bool compare(Article *a) { std::cout << "ACA" << std::endl;}; // ACA
};

 class Clothe : public Article
 {
    public :
        bool compare (Clothe *c) { std::cout << "CCC" << std::endl;}; // CCC
        bool compare (Article *a) { std::cout << "CCA" << std::endl;}; // CCA
};



int main()
{
Article *pta1 = new Article;
Article *pta2 = new Clothe;
Clothe *ptv1 = new Clothe;

pta1->compare(pta2); // print ACA
pta2->compare(pta1); // print CCA
pta2->compare(pta2); // print CCA because compiler needs to explore pta2 to determine which compare to use.
                     // pta2 is instanced as a Clothe, so one of Clothe's compare will be called. 
                     // And judging by its declaration pta2 is an Article (even thought it's instanced as a Clothe),
                     // so it will Call Clothe::Compare(Article*). I'm OK with this 

pta2->compare(ptv1); // print CCA ??? WHY , pta2 is explored, thus it's type is determined to be of type Clothe.
                     // And ptv1 is declared as a Clothe, so it should call Clothe::compare(Clothe* c)
                     // should print CCC, shouldn't it ?
}

I'm lost. I don't understand how g++ resolve the ambiguity that way. Any help / explanation would be nice. Thanks for reading, and even more thanks to those who answer.

PS : I know compare should return bool, but it's not really important here.

EDIT : typo slided during my on-the-fly translation of variable names, names were originally in french sorry for that. It's fixed now


Solution

  • This line

    pta2->compare(ptv1);
    

    prints CCA because there is only a virtual function bool compare(Article *a) in the base class.

    Your assumption about pta2 is wrong.

    pta2 is explored, thus it's type is determined to be of type Clothe.

    Which is not the case. The type of pta2 is Article * and nothing else. It only points to a Clothe object and it is therefore possible to call functions of Clothe through it, if (and only if) they are present and virtual and the base class and overrided (with the same Signature!) in the derived class.

    Simply speaking:

    The compiler can only "find" overloads in the derived class which are present and virtual in the base class if the call is performed via base class pointer.

    What is happening here:

    1. pta2 is a pointer to Article. Thus, when calling compare, the different possibilities of compare functions in Article are considered.

    2. The only match is bool Article::compare (Article *a).

    3. Now the compiler finds compare in Article to be virtual and uses some internal mechanism to make a virtual call through the 'vtable' of the object.

    4. As Clothe overrides bool compare (Article *a), the overrided function is called.

    The Base class knows nothing about bool compare (Clothe *c) since it does not know anything about Clothe and therefore the output is not CCV.