Search code examples
c++classoopinheritancename-lookup

Pitfalls of inheritence and nested names


I've come across a peculiar case while designing my C++ object inheritance tree in a project. I expected the below to fail:

struct A {
    protected:
    struct C { };
};

struct B: A { 
    struct C { };
};

But, this compiles just fine. Is this like an override? I can see how this isn't ambiguous because they can be specified as A::C and B::C, but how does this act in polymorphic cases? Will it call the prescribed type's C or the instance's type's C? As in, suppose this code below works and func exists in both implementations of C:

A x = B();
decltype(x)::C::func();

which C would have their function called? More generally, is their a resource that describes how code snippets like these resolve?


Solution

  • This is fine, because you have two unrelated struct C: the one is B::C and the other B::A::C. C is just their shortcut name.

    If you would have a static function f() defined in each C, you would be able to call it from outside the struct and without any object, as you have shown in your code:

    A a =  B();              // the type of a is A (B is sliced, by the way) 
    decltype(a)::C::f();     // so this calls A::C::f() 
    

    Now for the sake of completeness, here a more developed example that shows that at no point there is an ambiguity:

    struct A {
       struct C { static void f() { cout << "A::C::f" <<endl; } };
    };
    
    struct B: A {
        C c1;            // the only C known here is A::C
        struct C { static void f() { cout << "B::C::f" <<endl; }}; // now B::C hides A::C
        C c2;            // so here the closest C known is B::C
        A::C c3;         // and here I can be explicit about the C I want
        using D=A::C;    // and here another way to be explicit:
        D c4; 
    };
    
    int main() {    
        B  b; 
        decltype(b.c1)::C::f();    // A
        decltype(b.c2)::C::f();    // B  
    }
    

    online demo