Overriding Non-Virtual Methods

Overriding non-virtual methods

Yep, you are misunderstanding a little.

The method of the same name on the derived class will hide the parent method in this case. You would imagine that if this weren't the case, trying to create a method with the same name as a base class non-virtual method should throw an error. It is allowed and it's not a problem - and if you call the method directly as you have done it will be called fine.

But, being non-virtual, C++ method lookup mechanisms that allow for polymorphism won't be used. So for example if you created an instance of your derived class but called your 'Display' method via a pointer to the base class, the base's method will be called, whereas for 'vDisplay' the derived method would be called.

For example, try adding these lines:

Base *b = &ba;
b->Display();
b->vDisplay();
b = &de;
b->Display();
b->vDisplay();

...and observe the output as expected:

Base: Non-virtual display.

Base: Virtual display.

Base: Non-virtual display.
Derived: Virtual display.

Can i use a method overriding a non-virtual method?

Is there a point to override a non-virtual method?

You are not actually overriding, but this is the behavior, i.e

B* b = new B();
A* a = new B();
b->method(); //Calls B's method
a->method(); // Calls A's method

So, the pointer/reference type determines the method called.

can i create an instance of B and somehow use the method defined in B?

Yes. The pointer/reference type has to be of type B. (see previous example).

If you don't declare method to be virtual, you cannot override it, but you can hide it.

Can i override non virtual function in c++

You do not override say in B

from C++ override specifier :

In a member function declaration or definition, override ensures that the function is virtual and is overriding a virtual function from a base class. The program is ill-formed (a compile-time error is generated) if this is not true.

Look at that example :

#include <iostream>

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

class B : public A {
public:
void say()
//override
{
std::cout << "From B\n";
}
};

int main()
{
A a;
B b;

a.say();
b.say();
((A &) b).say();
}

Compilation and execution :

pi@raspberrypi:/tmp $ g++ c.cc
pi@raspberrypi:/tmp $ ./a.out
From A
From B
From A
pi@raspberrypi:/tmp $

Putting say virtual in A (so implicitely in B) ((A &) b).say(); prints From B because that time there is overriding

Is it possible to override a non-virtual method?

No, you cannot override a non-virtual method. The closest thing you can do is hide the method by creating a new method with the same name but this is not advisable as it breaks good design principles.

But even hiding a method won't give you execution time polymorphic dispatch of method calls like a true virtual method call would. Consider this example:

using System;

class Example
{
static void Main()
{
Foo f = new Foo();
f.M();

Foo b = new Bar();
b.M();
}
}

class Foo
{
public void M()
{
Console.WriteLine("Foo.M");
}
}

class Bar : Foo
{
public new void M()
{
Console.WriteLine("Bar.M");
}
}

In this example both calls to the M method print Foo.M. As you can see this approach does allow you to have a new implementation for a method as long as the reference to that object is of the correct derived type but hiding a base method does break polymorphism.

I would recommend that you do not hide base methods in this manner.

I tend to side with those who favor C#'s default behavior that methods are non-virtual by default (as opposed to Java). I would go even further and say that classes should also be sealed by default. Inheritance is hard to design for properly and the fact that there is a method that is not marked to be virtual indicates that the author of that method never intended for the method to be overridden.

Edit: "execution time polymorphic dispatch":

What I mean by this is the default behavior that happens at execution time when you call virtual methods. Let's say for example that in my previous code example, rather than defining a non-virtual method, I did in fact define a virtual method and a true overridden method as well.

If I were to call b.Foo in that case, the CLR would correctly determine the type of object that the b reference points to as Bar and would dispatch the call to M appropriately.

Overriding non-virtual function from abstract grandparent class

You cannot override a non-virtual function. It is as simple as that.

Methods in child classes can hide methods of parent classes when they have the same name, for example:

struct A {
void foo(){}
};
struct B : A {
void foo() {}
};

But thats not overriding. To override the method must be virtual. Thats one of the conditions that the override specifier helps to check:

struct A {
virtual void foo(){}
};
struct B : A {
void foo() override {} // <- error if A::foo is not virtual
};

PS: I have seen poor tutorials, that use the first example and call that overriding. Thats just wrong.

Preventing the use of an overridden non-virtual function - The correct way?

In response to OP's second edit:

Aliases are not like macros.

If you write using PtrType = T*, then const PtrType is actually
equivalent to T* const, which is a const pointer to a T object, not a pointer to a const T object. When aliases are used, further cv-qualifiers are always added on the top level. It is intuitive - if PtrType is a pointer to T, then const PtrType should be a const pointer to T.


As per the question, if you don't want users to call a virtual function, make it protected, so derived classes can implement it, but outside users cannot call it.


It is likely that you made the return type of bstnodeiterator::get_pointer() T* (instead of const T*).

You may be experiencing the pitfall of c++ covariant return types.

  • Both types are pointers or references (lvalue or rvalue) to classes. Multi-level pointers or references are not allowed.

  • The referenced/pointed-to class in the return type of Base::f() must be a unambiguous and accessible direct or indirect base class of (or is the same as) the
    referenced/pointed-to class of the return type of Derived::f().

  • The return type of Derived::f() must be equally or less cv-qualified than the return type of Base::f().

Note: c++ reference does not have the "(or is the same as)" clause, but it is added to be coherent with the standard"

So std::string* is a valid return type if the function is overriding a function with return type const std::string*.

Consider this example:

#include <string>

std::string s = "Hello, world";

struct Base {
virtual const std::string* foo() = 0;
};

struct Derived : Base {
std::string* foo() override {
return &s;
}
};

int main() {
Derived d;
d.foo()->assign("You can do this.");
return 0;
}

The above code compiles: you can modify the string pointed by d.foo() because it returns a std::string*.

C++ override specifier without virtual? Does override imply virtual?

The answer you're looking for is in https://en.cppreference.com/w/cpp/language/virtual

If some member function vf is declared as virtual in a class Base, and some class Derived, which is derived, directly or indirectly, from Base, has a declaration for member function with the same
name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers
Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration) and overrides Base::vf (whether or not the word override is used in its declaration).

Is it a good idea to always mark non-virtual methods with final?

A program that contains a non-virtual function, and which has every non-virtual function as final and follows the C++ standard, is guaranteed to be completely bug free.

So there is that.

Still: I advise against it.

It also does not exist. The final positional keyword can only be applied to virtual functions. The first paragraph is known as a vacuous satisfaction joke: every example of a non-existing thing has every property, because there are no examples.

Creating a non-overriding virtual final function would be confusing to people reading it. It would prevent a descendent type from declaring a method with identical signature: but it would not prevent a slightly different signature, so it is mostly pointless.



Related Topics



Leave a reply



Submit