Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding (simple?) C++ Inheritance

I'm struggling a bit to understand why this code snippet does not compile.

#include <cstdio>

class A {
public:
    virtual int potential()=0;
    virtual int potential(int arg, int arg2)=0;
};

class B : public A {
public:
    int potential() { return 1; }
    virtual int potential(int arg, int arg2) { return 2; }
};

class C : public B {
public:
    int potential(int arg, int arg2) { return 3; }
};


int main(int argc, char** argv) {
    C c;
    int value = c.potential();
    printf("Got %i\n", value);
    return 0;
}

I have two pure virtual methods, both named potential in the abstract superclass A. The subclass B then defines both, but a further subclass C only needs to redefine one of the methods.

However, on compilation, only the method defined in C is recognized, and potential() isn't seen (this should have been inherited from B):

In function 'int main(int, char**)':
Line 23: error: no matching function for call to 'C::potential()'
compilation terminated due to -Wfatal-errors.

If I rename A::potential(int, int) to something else all the way down the inheritance tree, such as A::somethingElse(int, int), then the code compiles fine, and the output is Got 1, as expected.

This has been verified using clang, g++ and MSVC's cl.

Any ideas on what is going on?

like image 763
Dan Avatar asked May 05 '11 11:05

Dan


1 Answers

However, on compilation, only the method defined in C is recognized, and potential() isn't seen (this should have been inherited from B).

C++ doesn’t work like this: because you implemented a different potential method (a method of the same name but with different parameters) in C, the other method is hidden as far as C is concerned.

Hiding happens because of the way that C++ resolves (overloaded) method names: when you call a method potential on an instance of a class (here c), C++ searches in the class whether a method of that name exists. If that isn’t the case it continues its search in the base classes. It goes further up in the hierarchy until at least one method of that name is found.

But in your case, C++ doesn’t have to search far: the method already exists in C, so it stops its search. Now C++ tries to match the method signature. Unfortunately, the method signature doesn’t match but at this time it’s too late: overload resolution fails; C++ doesn’t search for other methods that might match.

There are three solutions:

  1. Import it with using in C:

    class C : public B {
    public:
        using B::potential;
        int potential(int arg, int arg2) { return 3; }
    };
    
  2. Call the method from a base class instance in main:

    C c;
    B& b = c;
    int value = b.potential();
    
  3. Qualify the name explicitly in main:

    C c;
    int value = c.B::potential();
    
like image 68
Konrad Rudolph Avatar answered Oct 14 '22 10:10

Konrad Rudolph