What's the problem(s) with overriding a method with different access in base vs derived class

Viewed 65

PC-Lint issues a warning when a method is overriden in a derived class with access specifier other than what is the inherited access. For example

class B {
public:
    virtual void fubar(void);
};

class D : public B {
private:
    virtual void fubar(void);
};

One explaination I've seen is that the above would violate the Liskov Substitution Principle, but that's only case where the derived class has stricter access (like the example above), right? I'm also noting that here's a backdoor to D::fubar since we can cast a reference/pointer to D to reference/pointer to B and then we can call D::fubar since it's virtual. Is there any other problems?

What about if the derived class has looser access? For example:

class B {
protected:
    virtual void fubar(void);
};

class D : public B {
public:
    virtual void fubar(void);
};

Is there any problems associated with this type of override?

1 Answers

There is nothing inherently wrong with changing the access type. The language allows it. It is just that it is probable an error to change it, as the base class designer already decided what access should that method have.

If you make it stricter, it really doesn't matter, as any pointer to the base class will be able to call it, so this one is almost always an error.

If you make it less strict, it might expose a design issue, so this should be considered also a probable error.

One possible use case, would be if you don't own the base class (i.e. it is a external library or something). You may use this to directly expose some functionality, but again, this should be treated with caution.

About your "backdoor" access, note that the access specifiers are meant for "correct" usage of the language and diagnosting errors, not against malevolent usage. There are some lines of thought about always treating protected methods as if they were public (or even not using protected at all), just because they can be published at any time....

And finally, note that override has nothing to do with access type. You could do the following, and it would work as expected:

struct Base {
private:
    virtual void foo() = 0;
};

struct Derived: public Base {
private:
    void foo() override;
};

Compiler Explorer

In this snippet, only Base functions can call foo(), but they will call the overriden function in Derived. Note that being private, derived implementations cannot call Base::foo(), so it is a pattern usually used with pure virtual functions.

Related