Reputation: 873
I am working on a class (call it class D) that is derived from a class (call it class B) and will be inherited by another class (call it class E). I want instances of class E to have access to all the public functions of its parents but I specifically want to prevent class E from overriding any of the virtual functions in parent classes.
I thought by overriding the function in the private part of class D it would prevent the derived classes from overriding, but that appears not to be the case. This compiles and runs the function in class E:
#include <iostream>
//an abstract base class
class b
{
public:
virtual ~b() = default;
protected:
virtual void print() = 0;
virtual void print_two()
{
std::cout << "base class" << std::endl;
}
};
class d: public b
{
public:
virtual ~d() = default;
private:
void print() override // note this is not virtual -adding final here does the trick
{
std::cout << "class d" << std::endl;
}
using b::print_two; //this doesn't work either
};
class e : public d
{
public:
void print() override //why is this possible given the function it's overriding is private and non-virtual?
{
std::cout << "class e" << std::endl;
}
void print_two() override //why is this possible given the function it's overriding is private and non-virtual?
{
std::cout << "print two class e" << std::endl;
}
};
int main()
{
e foo;
foo.print();
foo.print_two();
}
So two questions out of this: Why can I override a function that is virtual in a grandparent but not virtual in a parent? Why can I override a function that is protected in a grandparent but private in a parent?
I tried it in g++ and clang and it compiles with no errors or warnings (-Wall -Wextra -Wpedantic)
Upvotes: 1
Views: 1427
Reputation: 170231
Why can I override a function that is virtual in a grandparent but not virtual in a parent?
There's no such thing. Once a function is declared virtual, it's implicitly virtual in all derived classes. Only way to come close to "unvirtualize" a member function is to declare it final
. That would make it impossible to override it further, but it will still be subject to dynamic dispatch when called via an ancestor reference/pointer. Any access via the child that declared it final
or its decedents, could be resolved statically, however.
Why can I override a function that is protected in a grandparent but private in a parent?
Access specifiers don't affect a name's visibility. They only affect where that name can be used. Defining the same function will override the parent's implementation and be called by dynamic dispatch. Again, because this is not something that falls under the realms of "access" to the name.
The child can't refer to the parent's implementation (Parent::foo
) if it's private in the parent, and neither can outside code that consumes the interface. It ensure the function is only ever called in a controlled manner. Very useful for testing pre and post conditions.
Upvotes: 7