Why Do We Need Virtual Functions in C++

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++.

Why use virtual functions? [duplicate]

You use virtual functions when you want to override a certain behavior (read method) for your derived class rather than the one implemented for the base class and you want to do so at run-time through a pointer to the base class.

The classic example is when you have a base class called Shape and concrete shapes (classes) that derive from it. Each concrete class overrides (implements a virtual method) called Draw().

The class hierarchy is as follows:

Class hierarchy

The following snippet shows the usage of the example; it creates an array of Shape class pointers wherein each points to a distinct derived class object. At run-time, invoking the Draw() method results in the calling of the method overridden by that derived class and the particular Shape is drawn (or rendered).

Shape *basep[] = { &line_obj, &tri_obj,
&rect_obj, &cir_obj};
for (i = 0; i < NO_PICTURES; i++)
basep[i] -> Draw ();

The above program just uses the pointer to the base class to store addresses of the derived class objects. This provides a loose coupling because the program does not have to change drastically if a new concrete derived class of shape is added anytime. The reason is that there are minimal code segments that actually use (depend) on the concrete Shape type.

The above is a good example of the Open Closed Principle of the famous SOLID design principles.

Why are virtual functions preferable over derived class objects?

The huge benefit that you get for using the base class pointer type and virtual functions is that you can have one single list that contains several different types of Shape and you can process them all in a single function where they will all have different behaviors due to their derived types.

As an example, I modified your code by adding the function DrawAllShapes that takes in a vector<Shapes*>&. (Be careful of using raw pointers. You really should use vector<std::unique_ptr<Shape>>&here or something like that.

You have incredible flexibility with this pattern that lets you call the same function on a collection of base class pointer objects but results in different behavior for every object in the collection depending on its derived type.

#include <iostream>
#include <vector>
using namespace std;

//////////////////////////////////////////////////////
//base class
class Shape {

public:
virtual void draw() = 0; //pure virtual function
};

//derived classes
class Square : public Shape {

public:
void draw() {
cout << "Draw square" << endl;
}

};

class Circle : public Shape {

public:
void draw() {
cout << "Draw circle " << endl;
}

};

void DrawAllShapes(std::vector<Shape*>& shapes) {
for (int i = 0; i < shapes.size(); ++i) {
shapes[i]->draw();
}
}

//////////////////////////////////////////////////////
int main()
{
std::vector<Shape*> shapeVec{ new Square, new Circle, new Square, new Square, new Circle };
DrawAllShapes(shapeVec);

system("pause");
}

Also, imagine if you were using a prebuilt graphical library that already had a Shape class and several shapes defined. What if you wanted to add your own new type of Shape and have it work perfectly with all of the library's functions? All you would have to do is create your own derived class and implement all of the necessary virtual functions exposed by the library's Shape class and then you've literally extended the library beyond its original capabilities.

why do we actually have virtual functions?

ABSTRACT

In this paper, we discuss virtual functions in C++. Part zero explains how virtual functions are declared and overridden. Part one attempts (and perhaps fails) to explain how virtual functions are implemented. Part two is a sample program that uses the example classes defined in parts zero and one. Part three is the classic animal example given in every virtual function - polymorphism tutorial.

PART ZERO

A method of a class is said to be virtual if and only if its declared to be so.

class my_base
{
public:
void non_virtual_test() { cout << 4 << endl; } // non-virtual
virtual void virtual_test() { cout << 5 << endl; } // virtual
};

(Of course, I am assuming the programmer did not previously do anything like #define virtual.)

A class that redeclares and re-implements a non-virtual method of one of its bases is said to overload that method. A class that redeclares and re-implements a virtual method of one of its bases is said to override that method.

class my_derived : public my_base
{
public:
void non_virtual_test() { cout << 6 << endl; } // overloaded
void virtual_test() { cout << 7 << endl; } // overriden
};

PART ONE

When the compiler detects a class has virtual methods, it automatically adds a virtual method table (also known as vtable) to the class' memory layout. The result is similar to what would have been generated from compiling this code:

class my_base
{
//<vtable>
// The vtable is actually a bunch of member function pointers
protected:
void (my_base::*virtual_test_ptr)();
//</vtable>

// The actual implementation of the virtual function
// is hidden from the rest of the program.
private:
void virtual_test_impl() { cout << 5 << endl; }

// Initializing the real_virtual_test pointer in the vtable.
public:
my_base() : virtual_test_ptr(&my_base::virtual_test_impl) {}

public:
void non_virtual_test() { cout << 4 << endl; }
// The interface of the virtual function is a wrapper
// around the member function pointer.
inline void virtual_test() { *virtual_test_ptr(); }
};

When the compiler detects a class has overridden a virtual method, it replaces its associated entry in the vtable. The result is similar to what would have been generated from compiling this code:

class my_derived : public my_base
{
// The actual implementation of the virtual function
// is hidden from the rest of the program.
private:
void virtual_test_impl() { cout << 7 << endl; }

// Initializing the real_virtual_test pointer in the vtable.
public:
my_derived() : virtual_test_ptr(&my_derived::virtual_test_impl) {}

public:
void non_virtual_test() { cout << 6 << endl; }
};

PART TWO

Now that it's clear that virtual functions are implemented using vtables, which are nothing but a bunch of function pointers, it should be clear what this code does:

#include <iostream>

using namespace std;

class my_base
{
public:
void non_virtual_test() { cout << 4 << endl; }
virtual void virtual_test() { cout << 5 << endl; }
};

class my_derived : public my_base
{
public:
void non_virtual_test() { cout << 6 << endl; }
void virtual_test() { cout << 7 << endl; }
}

int main()
{
my_base* base_obj = new my_derived();

// This outputs 4, since my_base::non_virtual_test() gets called,
// not my_derived::non_virtual_test().
base_obj->non_virtual_test();

// This outputs 7, since the vtable pointer points to
// my_derived::virtual_test(), not to my_base::virtual_test().
base_obj->virtual_test();

// We shall not forget
// there was an object that was pointed by base_obj
// who happily lived in the heap
// until we killed it.
delete base_obj;

return 0;
}

PART THREE

Since no virtual function example is complete without an example with animals...

#include <iostream>

using namespace std;

class animal
{
public:
virtual void say_something()
{ cout << "I don't know what to say." << endl
<< "Let's assume I can growl." << endl; }

/* A more sophisticated version would use pure virtual functions:
*
* virtual void say_something() = 0;
*/
};

class dog : public animal
{
public:
void say_something() { cout << "Barf, barf..." << endl; }
};

class cat : public animal
{
public:
void say_something() { cout << "Meow, meow..." << endl; }
};

int main()
{
animal *a1 = new dog();
animal *a2 = new cat();
a1->say_something();
a2->say_something();
}

Why use virtual function instead of regular? [duplicate]

You can redefine it but it won't work in a polymorphic way.

so if I have a

class base
{
int foo(){ return 3; }
};

class Der : public base
{
int foo() {return 5;}
};

and then have a function that takes a base

void dostuff(base &b)
{
b.foo(); // This will call base.foo and return 3 no matter what
}

and I call it like this

Der D; 
dostuff(D);

Now if I change the base to

class base
{
virtual int foo(){ return 3; }
};

void dostuff(base &b)
{
b.foo(); // This will call the most derived version of foo
//which in this case will return 5
}

so the real answer is if you want to write common code that will call the correct function from the base it needs to be virtual.

Why are virtual functions handled at runtime?

Because we don't always know, what instance we will face at runtime.

For example, you have classes: SuperClass, Subclass1 and Subclass2, and they all have a method doACoolThing(). The user presses a button 0, 1 or 2, and, depending on his input, an instance of the appropriate class is created, and its doACoolThing() method is called.

There is no way for us (and the compiler too) to figure out what class's method will be called at runtime.

That's why such tricks require a runtime support.

A small example to illustrate an idea (P.S. don't write the code like this, it's here just to illustrate polymorphism :) ):

#include <iostream>

using namespace std;

class SuperClass
{
public:
virtual void doACoolThing();
};

void SuperClass::doACoolThing()
{
cout << "Hello from the SuperClass!" << endl;
}

class Subclass1 : public SuperClass
{
virtual void doACoolThing() override;
};

void Subclass1::doACoolThing()
{
cout << "Hello from the Subclass1" << endl;
}

class Subclass2 : public SuperClass
{
virtual void doACoolThing() override;
};

void Subclass2::doACoolThing()
{
cout << "Hello from the Subclass2" << endl;
}

int main()
{
int userInput;
cout << "Enter 0, 1 or 2: ";
cin >> userInput;
SuperClass *instance = nullptr;
switch (userInput)
{
case 0:
instance = new SuperClass();
break;
case 1:
instance = new Subclass1();
break;
case 2:
instance = new Subclass2();
break;
default:
cout << "Unknown input!";
}

if (instance)
{
instance->doACoolThing();
delete instance;
}
return 0;
}

So, why do I have to define virtual function in a base class?

Yes, non-pure virtual function should be defined.

[class.virtual]/12:

A virtual function declared in a class shall be defined, or declared pure ([class.abstract]) in that class, or both; no diagnostic is required ([basic.def.odr]).

You might provide a definition, or mark it as pure virtual.

class Animal {
public:
virtual void speak() = 0;
};

Why would I want to implement virtual functions without implementation in an abstract class?

virtual void f();     // virtual member function
virtual void g() = 0; // pure abstract member function

A class with at least one pure virtual member function is an abstract class, and cannot be constructed itself, which is often desired (only non-abstract, "concrete" if you will, derive classes should be able to be constructed);

struct Abstract {
virtual void g() = 0;
};

struct NonAbstract {
virtual void f() {}
};

int main() {
NonAbstract na{}; // OK
Abstract a{}; // Error: cannot declare variable 'a'
// to be of abstract type 'Abstract'
}

Abstract classes are typically used polymorphically, to allow dynamic dispatch to derived object methods:

struct Derived : public Abstract {
void g() override {} // #1
}

void h(Abstract const& obj) {
obj.g(); // dynamic dispatch
}

int main() {
Derived d{};
h(d); // Will result in invoke #1
}

Difference between using virtual functions and redefining

TL;DR

The only way to take advantage of the polymorphism in C++ is via virtual functions and pointers (and references). The virtual keyword will tell the compiler to allocate a virtual function table where to look when deciding what version of the virtual function to call when dealing with pointer to the base class with a dynamic type that is of a child class.

How does polymorphism work in C++

Let's take a simple example:

class A { public: virtual void eat() { std::cout << "Class A" << std::endl; }
class B : public A {};
class C : public B { virtual void eat() { std::cout << "Class C" << std::endl; }

Note: the virtual keyword could be omitted after the first function/method definition.

The following:

A a; B b; C c;
A* ptrA = &a; A* ptrB = &b; A* ptrC = &c;
ptrA->eat();
ptrB->eat();
ptrC->eat();

will print:

Class A
Class A
Class C

If we wouldn't have declared the function eat virtual, the output would have simply been:

Class A
Class A
Class A


Related Topics



Leave a reply



Submit