When to Mark a Function in C++ as a Virtual

When to mark a function in C++ as a virtual?

The simple answer is if you intend functions of your class to be overridden for runtime polymorphism you should mark them as virtual, and not if you don't intend so.

Don't mark your functions virtual just because you feel it imparts additional flexibility, rather think of your design and purpose of exposing an interface. For ex: If your class is not designed to be inherited then making your member functions virtual will be misleading. A good example of this is Standard Library containers,which are not meant to be inherited and hence they do not have virtual destructors.

There are n no of reasons why not to mark all your member functions virtual, to quote some performance penalties, non-POD class type and so on, but if you really intent that your class is intended for run time overidding then that is the purpose of it and its about and over the so-called deficiencies.

Why should I mark all methods virtual in C++? Is there a trade-off?

No, you should not "mark all methods as virtual".

If you want the method to be virtual, then mark it as such. If not, leave the keyword out.

There is an overhead for virtual methods compared to regular ones. If you want to read more about this, check out the Wikipedia side about VTables.

Why do we need virtual functions in C++?

Without "virtual" you get "early binding". Which implementation of the method is used gets decided at compile time based on the type of the pointer that you call through.

With "virtual" you get "late binding". Which implementation of the method is used gets decided at run time based on the type of the pointed-to object - what it was originally constructed as. This is not necessarily what you'd think based on the type of the pointer that points to that object.

class Base
{
public:
void Method1 () { std::cout << "Base::Method1" << std::endl; }
virtual void Method2 () { std::cout << "Base::Method2" << std::endl; }
};

class Derived : public Base
{
public:
void Method1 () { std::cout << "Derived::Method1" << std::endl; }
void Method2 () { std::cout << "Derived::Method2" << std::endl; }
};

Base* basePtr = new Derived ();
// Note - constructed as Derived, but pointer stored as Base*

basePtr->Method1 (); // Prints "Base::Method1"
basePtr->Method2 (); // Prints "Derived::Method2"

EDIT - see this question.

Also - this tutorial covers early and late binding in C++.

Does it make sense to add final keyword to the virtual function in a class that has no base class (is not derived)

If you don't mark the function as virtual and final then the child-class can still implement the function and hide the base-class function.

By making the function virtual and final the child-class can not override or hide the function.

What's the point of a final virtual function?

Typically final will not be used on the base class' definition of a virtual function. final will be used by a derived class that overrides the function in order to prevent further derived types from further overriding the function. Since the overriding function must be virtual normally it would mean that anyone could override that function in a further derived type. final allows one to specify a function which overrides another but which cannot be overridden itself.

For example if you're designing a class hierarchy and need to override a function, but you do not want to allow users of the class hierarchy to do the same, then you might mark the functions as final in your derived classes.


Since it's been brought up twice in the comments I want to add:

One reason some give for a base class to declare a non-overriding method to be final is simply so that anyone trying to define that method in a derived class gets an error instead of silently creating a method that 'hides' the base class's method.

struct Base {
void test() { std::cout << "Base::test()\n"; }
};

void run(Base *o) {
o->test();
}

// Some other developer derives a class
struct Derived : Base {
void test() { std::cout << "Derived::test()\n"; }
};

int main() {
Derived o;
o.test();
run(&o);
}

Base's developer doesn't want Derived's developer to do this, and would like it to produce an error. So they write:

struct Base {
virtual void test() final { ... }
};

Using this declaration of Base::foo() causes the definition of Derived to produce an error like:

<source>:14:13: error: declaration of 'test' overrides a 'final' function
void test() { std::cout << "Derived::test()\n"; }
^
<source>:4:22: note: overridden virtual function is here
virtual void test() final { std::cout << "Base::test()\n"; }
^

You can decide if this purpose is worthwhile for yourself, but I want to point out that declaring the function virtual final is not a full solution for preventing this kind of hiding. A derived class can still hide Base::test() without provoking the desired compiler error:

struct Derived : Base {
void test(int = 0) { std::cout << "Derived::test()\n"; }
};

Whether Base::test() is virtual final or not, this definition of Derived is valid and the code Derived o; o.test(); run(&o); behaves exactly the same.

As for clear statements to users, personally I think just not marking a method virtual makes a clearer statement to users that the method is not intended to be overridden than marking it virtual final. But I suppose which way is clearer depends on the developer reading the code and what conventions they are familiar with.

Should I use virtual, override, or both keywords?

When you override a function you don't technically need to write either virtual or override.

The original base class declaration needs the keyword virtual to mark it as virtual.

In the derived class the function is virtual by way of having the ¹same type as the base class function.

However, an override can help avoid bugs by producing a compilation error when the intended override isn't technically an override. For instance, the function type isn't exactly like the base class function. Or that a maintenance of the base class changes that function's type, e.g. adding a defaulted argument.

In the same way, a virtual keyword in the derived class can make such a bug more subtle by ensuring that the function is still virtual in the further derived classes.

So the general advice is,

  • Use virtual for the base class function declaration.

    This is technically necessary.

  • Use override (only) for a derived class' override.

    This helps maintenance.

Example:

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


Notes:
¹ C++ supports covariant raw pointer and raw reference results. With covariance the type of the override isn't exactly the same. It just has a compatible type.

Should I mark all methods virtual?

In C# you have to mark method as virtual to make it possible to override. Does it mean that in C# you should mark all methods virtual (except a few ones that you don't want to be overridden), since most likely you don't know in what way your class can be inherited?

No. If the language designers thought that virtual should have been the default then it would have been the default.

Overridablility is a feature, and like all features it has costs. The costs of an overrideable method are considerable: there are big design, implementation and testing costs, particularly if there is any "sensitivity" to the class; virtual methods are ways of introducing untested third-party code into a system and that has a security impact.

If you don't know how you intend your class to be inherited then don't publish your class because you haven't finished designing it yet. Your extensibility model is definitely something you should know ahead of time; it should deeply influence your design and testing strategy.

I advocate that all classes be sealed and all methods be non-virtual until you have a real-world customer-focussed reason to unseal or to make a method virtual.

Basically your question is "I am ignorant of how my customers intend to consume my class; should I therefore make it arbitrarily extensible?" No; you should become knowledgable! You wouldn't ask "I don't know how my customers are going to use my class, so should I make all my properties read-write? And should I make all my methods read-write properties of delegate type so that my users can replace any method with their own implementation?" No, don't do any of those things until you have evidence that a user actually needs that capability! Spend your valuable time designing, testing and implementing features that users actually want and need, and do so from a position of knowledge.

When is it safe to call a virtual function in a constructor

It is absolutely safe to call any non-abstract virtual function in the constructor or the destructor! However, its behavior may be confusing as it may not do what is expected. While the constructor of a class is executed, the static and dynamic type of the object is the type of the constructor. That is, the virtual function will never be dispatched to the override of a further derived class. Other than that, virtual dispatch actually works: e.g. when calling a virtual function via a base class pointer or reference correctly dispatches to the override in the class being currently constructor or destructed. For example (probably riddled with typos as I currently can't this code):

#include <iostream>
struct A {
virtual ~A() {}
virtual void f() { std::cout << "A::f()\n"; }
void g() { this->f(); }
};
struct B: A {
B() { this->g(); } // this prints 'B::f()'
void f() { std::cout << "B::f()\n"; }
};
struct C: B {
void f() { std::cout << "C::f()\n"; } // not called from B::B()
};

int main() {
C c;
}

That is, you can call a virtual function, directly or indirectly, in the constructor or a destructor of a class if you don't want the virtual function to be dispatched to a further derived function. You can even do this is virtual function is abstract in the given class as long as it is defined. However, having an undefined abstract function being dispatched to will cause a run-time error.



Related Topics



Leave a reply



Submit