The following code shows a class which privately inherits from an interface having its private functions accessed without granting the calling object friendship. I am baffled by this but can’t really see what better solution the compiler could come up with (code compiles and runs). Why does this work?
#include <iostream>
class IVisitor;
class IVisitable
{
public:
virtual void Accept(IVisitor& visitor) const = 0;
};
class VisitableA;
class VisitableB;
class IVisitor
{
public:
virtual void Visit(const VisitableA& a) = 0;
virtual void Visit(const VisitableB& b) = 0;
};
class VisitableA : public IVisitable
{
public:
virtual void Accept(IVisitor& visitor) const
{
visitor.Visit(*this);
}
};
class VisitableB : public IVisitable
{
public:
virtual void Accept(IVisitor& visitor) const
{
visitor.Visit(*this);
}
};
class PrivateVisitor : private IVisitor
{
public:
PrivateVisitor(IVisitable& v)
{
v.Accept(*this);
}
private:
virtual void Visit(const VisitableA& a)
{
std::cout << "I saw A\n";
}
virtual void Visit(const VisitableB& b)
{
std::cout << "I saw B\n";
}
};
int main(int argc, char* argv[])
{
VisitableA a;
VisitableB b;
PrivateVisitor p_a(a);
PrivateVisitor p_b(b);
}
Access specifiers are only checked at compile time, and there they are checked on the static type of the object on which they are applied.
Inside
PrivateVisitorconstructor, the*thisobject is casted toIVisitor. In this context the type of inheritance does not matter, as we are within thePrivateVisitortype, so we have full access.The object is used inside the
IVisitableobject (VisitableAorVisitableB) and theVisitmember function is called. While the dynamic type of the object isPrivateVisitor, the static type isIVisitor(the reference is of typeIVisitor&). Access specifiers are checked againstIVisitorclass where bothVisitoverloads are public, so the compiler accepts the call.The fact that the function is private in the final overrider does not really matter, as access was performed through the base class, where the functions are public.