Function name resolution in base class

Viewed 66

Consider the following code snippet,

#include <memory>

template <typename Derived>
class Base
{
public:
    int foo()
    {
        return static_cast<Derived*>(this)->bar(); // I expected a compilation error here
    }

private:
    int bar()
    {
        return 1;
    }
};

class Derived : public Base<Derived> {};

int baz()
{
    return std::unique_ptr<Derived>()->foo();
}

From my understanding, the template class Base declares the function bar as private and is hence not visible to even Derived class, let alone the users of any Derived object.

In the public function foo of the template class Base, I try to access a non-existing function bar through a Derived object. I expected the compiler to fail to find the function bar.

Q. How does the compiler find the private bar function of the Base template class through the use of a Derived object? https://godbolt.org/z/jVxW-k

Now consider a slight variation to the snippet in which the Derived class is no longer empty.

class Derived : public Base<Derived>
{
private:
    int bar()
    {
        return 1;
    }
};

Here, the output is expected with the compiler erroring out with the message,

<source>: In instantiation of 'int Base<Derived>::foo() [with Derived = Derived]':

<source>:30:44:   required from here

<source>:9:49: error: 'int Derived::bar()' is private within this context

    9 |         return static_cast<Derived*>(this)->bar();

      |                                                 ^

<source>:22:9: note: declared private here

   22 |     int bar()

      |         ^~~

Compiler returned: 1

Q. Why wasn't the compiler able to find the private function bar now? Is there some way in which I can force Derived implementations to implement the function bar? https://godbolt.org/z/PrkNo6

Compiler used: g++ 9.2. Compiler flags used: -std=c++17 -O3 -Wall -Werror.

Thanks in Advance!!!

2 Answers

Since Derived is inheriting from Base, when you do static_cast<Derived*>(this)->bar() and bar() is not implemented in Derived, the lookup goes to the base class. As you are using the function within the Base class, the private specifier is fine.

When you define a Derived::bar() and call it from Base, it is private and cannot be accessed outside the Derived class

Q. How does the compiler find the private bar function of the Base template class through the use of a Derived object?

For

return static_cast<Derived*>(this)->bar();

Derived has no bar,
looking in base class founds Base::bar.

We are in Base scope, so we have access to Base::bar (even if applied to other type)

Q. Why wasn't the compiler able to find the private function bar now? Is there some way in which I can force Derived implementations to implement the function bar?

Now, Derived has a bar, stopping the look-up.

but Derived::bar is private in Base's scope (even if applied to Derived instance).

Related