I have a class heirarchy where there is one base type Base with a list of implementations and another base class, AnotherBase, that is almost like Base but a little different. To express this in the language I used private inheritance on the second base class (so there is no as-is relationship between implementations of the latter with the former).
Let's say this is the code (https://wandbox.org/permlink/2e2EG0eKmcLiyvgt)
#include <iostream>
using std::cout;
using std::endl;
class Base {
public:
virtual ~Base() = default;
virtual void foo() = 0;
};
class Impl : public Base {
public:
void foo() {
cout << "Impl::foo()" << endl;
}
};
class AnotherBase : private Base {
public:
using Base::foo;
// other virtual methods
};
class Derived : public AnotherBase {
public:
explicit Derived(std::unique_ptr<Base> base) : base_{std::move(base)} {}
void foo() override {
base_->foo();
}
private:
std::unique_ptr<Base> base_;
};
int main() {
auto impl = std::make_unique<Impl>();
std::make_unique<Derived>(std::move(impl))->foo();
}
When I try to compile the above code, I get the following error
prog.cc:27:38: error: 'Base' is a private member of 'Base'
What is the best way to express the above idea if this does not work? Also why does it not work?
On these two lines within the declaration of
Derived,Baseis resolved as the the privately-inheritedBasetype since it is in scope -- even though it is private:C++ does not ignore in-scope names that refer to things the current scope doesn't have access to. It seems logical that the compiler would look in an outer scope for a
Basethat it does have access to, but this is not what happens. The compiler simply stops at the closestBaseit sees without regard for any access modifiers.This can be trivially fixed by referring to the
Basetype through the top-level namespace prefix:::Both refer to the same type, but
Deriveddoes not have access to the inheritedBasename, while it does have access to the globalBasename.You could also fix this issue by redefining what
Basemeans withinDerived. At the top of theDeriveddeclaration, you can add:This hides the inherited
Basename behind a type alias thatDeriveddoes have access to.