Overriding Public Virtual Functions with Private Functions in C++

Overriding public virtual functions with private functions in C++

The problem is that the Base class methods are its way of declaring its interface. It is, in essence saying, "These are the things you can do to objects of this class."

When in a Derived class you make something the Base had declared as public private, you are taking something away. Now, even though a Derived object "is-a" Base object, something that you should be able to do to a Base class object you cannot do to a Derived class object, breaking the Liskov Substitution Prinicple

Will this cause a "technical" problem in your program? Maybe not. But it will probably mean object of your classes won't behave in a way your users expect them to behave.

If you find yourself in the situation where this is what you want (except in the case of a deprecated method referred to in another answer), chances are you have an inheritance model where inheritance isn't really modeling "is-a," (e.g. Scott Myers's example Square inheriting from Rectangle, but you can't change a Square's width independent of its height like you can for a rectangle) and you may need to reconsider your class relationships.

Override public virtual function with private base function?

Is there any way to make this work as I supposed it may have worked?

You should override the member function and explicitly call B::start():

class C: public A, private B {
public:
void start() override { B::start(); }
};

Why would the compiler accept this code as valid? As I see it there
are now two start() functions with the exact same signature in C and
yet the compiler seems fine with it and only calls A::start().

You are right, there are two member functions accessible in C (A::start() and B::start()). And in class C, without overriding start() or making the start() of any of the base classes visible by doing a using ...::start(), you will have ambiguity error when trying to call the member function using unqalified namelookup from an object of C.

class A {
public:
virtual void start() { std::cout << "From A\n"; }
};

class B {
public:
void start() { std::cout << "From B\n"; }
};

class C: public A, private B {
};

int main(){
A* a = new C();
a->start(); //Ok, calls A::start()

C* c = new C();
c->start(); //Error, ambiguous
}

To fix that, you will have to use the qualified name such as:

    C* c = new C();
c->A::start(); //Ok, calls A::start()

Now, doing a using B::start() in class C simply declares the start() to refer to B::start() whenever such name is used from an object of C

class A {
public:
virtual void start() { std::cout << "From A\n"; }
};

class B {
public:
void start() { std::cout << "From B\n"; }
};

class C: public A, private B {
public:
using B::start();
};

int main(){
A* a = new C();
a->start(); //Ok, calls A::start()

C* c = new C();
c->start(); //Ok, calls B::start()
}

using B::start makes the function void B::start() visible in C, it does not override it. To call make all the above unqualified member function call, to call B::start(), you should override the member function in C, and make it call B::start()

class A {
public:
virtual void start() { std::cout << "From A\n"; }
};

class B {
public:
void start() { std::cout << "From B\n"; }
};

class C: public A, private B {
public:
void start() override { B::start(); }
};

int main(){
A* a = new C();
a->start(); //Ok, calls C::start() which in turn calls B::start()
// ^^^^^^^^^^^^^^^^ - by virtual dispatch

C* c = new C();
c->start(); //Ok, calls C::start() which in turn calls B::start()

}

C++ override private pure virtual method as public

According to https://en.cppreference.com/w/cpp/language/virtual#In_detail overriding a base's virtual member function only care about the function name, parameters, const/volatile-ness and ref qualifier. It doesn't care about return type, access modifier or other things you might expect it to care about.

The linked reference also specifically notes that :

Base::vf does not need to be visible (can be declared private, or inherited using private inheritance) to be overridden.

Nothing that I can find explicitly gives permission to do this, but the rules of overriding do not prevent it. It's allowed by virtue of virtual functions and function overriding existing and not disallowing this case.

If you are asking why this is how the language is, you may have to ask the standardization committee.

Overriding private functions

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.

If a private virtual function is overridden as a public function in the derived class, what are the problems?

Accessibility check is performed based on the static type of the object. The type of o is One*. This means that if One::func() is private, then o->func() won't compile.

On the other hand, which virtual member function will be called (i.e. dynamic dispatch) happens at run-time, based on the dynamic type of the object. So if One::func() is public, o->func() will call Two::func(), because o is pointing to an object of type Two.

For your sample code and use case, making One::func() private is just meaningless. But note that there's a famous idiom called Non-Virtual Interface, which makes use of private virtual member functions of base class.


Other suggestions:

  1. Don't forget to delete o;
  2. Add a virtual destructor in the base class One. Otherwise delete o; will lead to undefined behavior; e.g. the destructor of Two might not be invoked.

    class One {
    public:
    virtual ~One() {}
    // ...
    };

Public virtual function derived private in C++

The behavior is correct. Whenever you declare your function as "virtual", you instruct the compiler to generate a virtual call, instead of the direct call to this function. Whenever you override the virtual function in the descendant class, you specify the behavior of this function (you do not change the access mode for those clients, who rely on the "parent's" interface).

Changing the access mode for the virtual function in the descendant class means that you want to hide it from those clients, who use the descendant class directly (who rely on the "child's" interface).

Consider the example:

void process(const A* object) {
object->func();
}

"process" function relies on the parent's interface. It is expected to work for any class, public-derived from A. You cannot public-derive B from A (saying "every B is A"), but hide a part of its interface. Those, who expect "A" must receive a fully functional "A".

overriding virtual function from several base classes

Is such an overriding legal and well-defined in c++?

Yes, it is perfectly legal and well defined as long as you override the virtual function in the derived class.

If you create an object of Derived structure and invoke the foo function it will invoke the overridden function.

The compiler will always search the called function from local to the global scope. So here compiler will check if foo is defined in the Derived scope if not found it will check in the Base scope and since you have provided the definition of foo in the derived scope the compiler won't check Base scope.

Try this code and you will get a better idea.
The output will be This is derived.

#include <iostream>
using namespace std;
struct Base1 {
virtual void foo() {
cout << "This is base1" << endl;
}
};

struct Base2 {
virtual void foo() {
cout << "This is base2" << endl;
}
};

struct Derived : Base1, Base2 {
void foo() {
cout << "This is derived" << endl;
}
};

int main() {
Derived d;
d.foo();
return 0;
}

Overriding a private function, how is it different from protected?

This topic creates a lot of confusion: even though subclasses are allowed to override virtual private member functions, they are not allowed to call them.

Currently, this would not compile (demo 1):

class B : public A {
public:
B() {}
virtual ~B() {}
private:
virtual void GetPart() override {
// This line would not compile
A::GetPart();
std::cout << "GETPART RUN" << std::endl;
}
};

Making GetPart() function protected would let the above code compile without an issue, but it would require you to provide a definition (demo 2).

This is the only difference.



Related Topics



Leave a reply



Submit