Why do we need virtual functions in C++?
Asked Answered
I

28

1649

From what I've read, virtual functions are functions in the base class that you can override in its derived classes.

But earlier, when learning about basic inheritance, I was able to override base functions in derived classes without using virtual.

What am I missing here? I know there is more to virtual functions, and it seems to be important so I want to be clear on what it is exactly.

Insoluble answered 6/3, 2010 at 7:10 Comment(6)
This is perhaps the biggest benefit of virtual functions -- the ability to structure your code in such a way that newly derived classes will automatically work with the old code without modification!Phonon
tbh, virtual functions are staple feature of OOP, for type erasure. I think, it's non-virtual methods are what is making Object Pascal and C++ special, being optimization of unnecessary big vtable and allowing POD-compatible classes. Many OOP languages expect that every method can be overriden.Deranged
I think if you take a look at early binding-late binding and VTABLE it would be more reasonable and make sense. So there is a good explanation ( learncpp.com/cpp-tutorial/125-the-virtual-table ) here.Luke
@user3530616, yes I would add "with your old code AND even with your old binaries (compiled code). This is extremely powerful, however one pays a big price for this flexibility and it is most of the time unnecessary. youtube.com/watch?v=bIhUE5uUFOA. If you can recompile and not depend on stable binaries or don't need runtime linking, there are better options that are easier to reason about. Late binding can be done with templates in other cases and it is more powerful but in other senses (mathematical or value-semantics reasoning).Heptagonal
@ILCAI I wouldn't call it "abstracted away" but rather virtual by default. The reason it's not by default in C++ is because it potentionally decreases performance when it's not needed and one principle of C++ is to not having to pay performance for features you don't use.Allotropy
This question and its answers are being discussed on meta.Blooded
G
833

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 () override {  std::cout << "Derived::Method2" << std::endl;  }
    // Note - override is optional; adding it to Method1 would result in an error
};

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

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

See Also

Gunshot answered 6/3, 2010 at 7:56 Comment(18)
Excellent, and gets home quickly and with the use of better examples. This is however, simplistic, and the questioner should really just read the page parashift.com/c++-faq-lite/virtual-functions.html. Other folks have already pointed to this resource in SO articles linked from this thread, but I believe this is worth re-mentioning.Egad
I assume: Base* obj = new Base(); obj->Method2(); would print "Base::Method2" -- yes?R
@R - yes. In that case, the pointer type matches the original type the object was constructed as, so early vs. late binding makes no difference.Gunshot
I don't know if early and late binding are terms specificly used in the c++ community, but the correct terms are static (at compile time) and dynamic (at runtime) binding.Suzy
@Suzy - "The term "late binding" dates back to at least the 1960s, where it can be found in Communications of the ACM.". Wouldn't it be nice if there was one correct word for each concept? Unfortunately, it just ain't so. The terms "early binding" and "late binding" predate C++ and even object-oriented programming, and are just as correct as the terms you use.Gunshot
Base* obj = new Derived (); This is not how it's supposed to be done in C++ and in C++11 this would produce compiler error. Pointer to Derived should always be pointer to Derived. You should never assign pointer to one object type to pointer to different object type, this programming style should be avoided. However, if you have no other option then explicit cast should be used.Transfigure
@Transfigure - this answer was written before C++11 was published. Even so, I just compiled it in GCC 6.3.0 (using C++14 by default) with no problems - obviously wrapping the variable declaration and calls in a main function etc. Pointer-to-derived implicitly casts to pointer-to-base (more specialized implicitly casts to more general). Visa-versa you need an explicit cast, usually a dynamic_cast. Anything else - very prone to undefined behavior so make sure you know what you're doing. To the best of my knowledge, this has not changed since before even C++98.Gunshot
@Transfigure - Of course naked raw owner pointers are bad style since C++11, and this example (without changes) has a memory leak as a result of that issue. Modern style = use a unique_ptr. A unique_ptr isn't implicitly castable IIRC, and it would probably violate uniqueness to support that cast, but I'd have to do some checking to be sure.Gunshot
@Transfigure - BTW - it's fairly common to claim that derived classes aren't distinct types from their bases, they're extensions of the same type. It's not an opinion I share, but it does reflect the OOP intent. That's why the implicit cast is supported for raw pointers and references.Gunshot
Note that C++ compilers today can often optimize late into early binding - when they can be certain of what the binding is going to be. This is also referred to as "de-virtualization".Leverage
@Leverage - optimizing away the overhead is certainly a good point, but I'm not really sure it counts as optimizing late binding into early binding. The cases where the compiler can be certain in advance are cases where early binding and late binding are equivalent (give the same behavior) so the compiler has more freedom to choose implementations, but my impression of the terminology is that it's about meaning, not about implementation.Gunshot
One interesting case happens when there's a very common case (determined by instrumented code, I think most often for VM languages like Java) but other cases can still happen. The compiler may generate both specialised and general-case code, and have an "if it's the expected common-case type" check to choose between them. This is still devirtualisation, and it still makes a late-binding decision of which implementation to use.Gunshot
@Steve314: I mean, for example, cases in which you call a virtual function for a base-class pointer, but the compiler can tell that the pointed-to object will actually always have the same implementation of that method.Leverage
@Steve314: std::unique_ptr actually is implicitly castable for this case, specifically to handle this upcast cast, which are totally normal. It doesn't violate uniqueness, since it's a move constructor, and not a copy constructor.Jonme
The code would illustrate the point at hand more strikingly if you renamed obj to basePtr.Chenille
@MooingDuck I think there is no such thing as an "implicit cast" -- that would be a conversion, right? "Cast" is the name for the syntax of explicit conversions, of which some -- those that may fail -- must be explicit (base pointer -> derived pointer), some not (the inverse).Chenille
@Peter-ReinstateMonica - I eventually noticed your comment is to MooingDuck, but as I already wrote this and as I often switch words like this too and maybe did in another comment MooingDuck is referencing - In the C++ standard I assume you're correct. I don't know if that distinction is specific to the C++ standard (which like any complex technical document, needs to define its own meanings for words that may be used differently elsewhere) or if that's a genuine strict distinction throughout programming/computer science or somewhere in-between. On the other point - accepted, will edit.Gunshot
Why even declare Base* basePtr = new Derived ();?Litchfield
E
3144

Here is how I understood not just what virtual functions are, but why they're required:

Let's say you have these two classes:

class Animal
{
    public:
        void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

In your main function:

Animal *animal = new Animal;
Cat *cat = new Cat;

animal->eat(); // Outputs: "I'm eating generic food."
cat->eat();    // Outputs: "I'm eating a rat."

So far so good, right? Animals eat generic food, cats eat rats, all without virtual.

Let's change it a little now so that eat() is called via an intermediate function (a trivial function just for this example):

// This can go at the top of the main.cpp file
void func(Animal *xyz) { xyz->eat(); }

Now our main function is:

Animal *animal = new Animal;
Cat *cat = new Cat;

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating generic food."

Uh oh... we passed a Cat into func(), but it won't eat rats. Should you overload func() so it takes a Cat*? If you have to derive more animals from Animal they would all need their own func().

The solution is to make eat() from the Animal class a virtual function:

class Animal
{
    public:
        virtual void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

Main:

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating a rat."

Done.

Espouse answered 6/3, 2010 at 13:54 Comment(23)
So if I'm understanding this correctly, virtual allows the subclass method to be called, even if the object is being treated as its superclass?Daiseydaisi
I would point out similar explanation in wikipedia en.wikipedia.org/wiki/Virtual_function . Any way, really good explanation.Amaryl
@KennyWorden more specifically, the keyword allows the base class's method to be overridden. Because Cat is derived from Animal, func() accepts a Cat. However, since *xyz is an Animal pointer, and Animal->eat() has not been overridden, it presumes to use that function instead when you don't mark eat() as a virtual function.Linskey
Instead of explaining late binding through the example of an intermediary function "func", here is a more straightforward demonstration -- Animal *animal = new Animal; //Cat *cat = new Cat; Animal *cat = new Cat; animal->eat(); // outputs: "I'm eating generic food." cat->eat(); // outputs: "I'm eating generic food." Even though you're assigning the subclassed object (Cat), the method being invoked is based on the pointer type (Animal) not the type of object it is point to. This is why you need "virtual".Ivey
Am I the only one finding this default behavior in C++ just weird? I would have expected the code without "virtual" to work.Barbwire
@David天宇Wong I think virtual introduces some dynamic binding vs static and yes it is weird if you 're coming from languages like Java.Haukom
@David天宇Wong as Laser mentioned, consider it the way C++ notifies the base class that there may be a more specific definition in one of its derived classesHolothurian
@David天宇Wong how should it work? The func() demands that animal is passed to it. But you pass a cat, which is an animal and has animal properties. Now when you call eat(), since function knows nothing about cat, only about animal, it will display animal's eat(). But virtual calls solve this problem by defining vtables.Lewiss
@David天宇Wong there's another method too, describe two func()s, one which takes animal and the other takes cat. Now the cat functions knows that cat eats rat.Lewiss
Would you ever NOT want to use virtual then? Seems like you would have (potentially) unpredictable behavior if someone inherited from your class.Phidias
First of all, virtual calls are much, much more expensive than regular function calls. The C++ philosophy is fast by default, so virtual calls by default are a big no-no. The second reason is that virtual calls can lead to your code breaking if you inherit a class from a library and it changes its internal implementation of a public or private method (which calls a virtual method internally) without changing the base class behaviour.Obediah
void func(Animal *xyz) { xyz->eat(); } Giving this function a pointer to Cat as an argument will in modern C++ produce a compiler error. It's not the way it should be done generally in C++. The purpose of the virtual functions is to change behavior of the base class, methods of class Animal calling member method eat() will call the Animal's eat().Transfigure
In C++11 you can add the override keyword: void eat() override { std::cout << "I'm eating a rat."; } so that you know you are overriding an existing method of a base class (and make the compiler aware of it).Diner
@BJovke: Why in the world would you expect that to be a compile error, or even bad practice?Catherincatherina
@FredLarson You're right. It might not be a compile error. Regardless of that, in modern C++ it is considered as a bad practice to use explicit casts. For many cases it's also not advisable to use implicit casts (like in this case). This was true even for C long time ago, casts defeat the purpose of strongly typed language. Many developers of libraries in their classes forbid implicit conversions and/or not implement them at all. Furthermore, now that C++ has templates, this is the way use these objects.Transfigure
@BJovke: This is not a cast, implicit or explicit. It is a substitution. See the Liskov Substitution Principle.Catherincatherina
@BradRichardson Non virtual calls are 100% predictable. Virtual introduces "unpredictable" behavior.Modernistic
@Brad There are schools of thought that say "you wouldn't" and therefore "make everything virtual". However, there is a cost to runtime polymorphism, both in terms of performance and in terms of being able to accurately and mathematically guarantee a program's behaviour and correctness. So, if you don't need it to achieve a goal, common wisdom is to avoid it. Like anything: pros and cons, use the right tool for the job.Elayne
@Modernistic "Non virtual calls are 100% predictable", C++: "You are like a little baby, watch this: ADL, Two-phase name lookup, SFINAE, overloading".Exile
Virtual ist not needed but you can model your dynamic binding using dyno library: github.com/ldionne/dyno which already states in its title, that polymorphism by inheritance and virtual calls is not the way to go... Sady, these concepts of louis are still experimental, hopefully they find a way into the standarFimbriation
As a c++ newbie this is a great explanation of void functions. But hold on tonto.. I was confused with your object construction, Animal *animal = new Animal; After a tonne of googling I found this is creating a object dynamically and to quote https://mcmap.net/q/46008/-how-do-i-create-a-class-object-in-c, In Modern C++, this is regarded as a dubious programming practiceNoumenon
@hounded: Unrelated to the problem. The "best" way is std::unique_ptr<Animal> animal = std::make_unique<Cat>();, which has the exact same issues.Jonme
What does polymorphism have to do with this? It should be mentioned in the answer.Lovins
G
833

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 () override {  std::cout << "Derived::Method2" << std::endl;  }
    // Note - override is optional; adding it to Method1 would result in an error
};

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

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

See Also

Gunshot answered 6/3, 2010 at 7:56 Comment(18)
Excellent, and gets home quickly and with the use of better examples. This is however, simplistic, and the questioner should really just read the page parashift.com/c++-faq-lite/virtual-functions.html. Other folks have already pointed to this resource in SO articles linked from this thread, but I believe this is worth re-mentioning.Egad
I assume: Base* obj = new Base(); obj->Method2(); would print "Base::Method2" -- yes?R
@R - yes. In that case, the pointer type matches the original type the object was constructed as, so early vs. late binding makes no difference.Gunshot
I don't know if early and late binding are terms specificly used in the c++ community, but the correct terms are static (at compile time) and dynamic (at runtime) binding.Suzy
@Suzy - "The term "late binding" dates back to at least the 1960s, where it can be found in Communications of the ACM.". Wouldn't it be nice if there was one correct word for each concept? Unfortunately, it just ain't so. The terms "early binding" and "late binding" predate C++ and even object-oriented programming, and are just as correct as the terms you use.Gunshot
Base* obj = new Derived (); This is not how it's supposed to be done in C++ and in C++11 this would produce compiler error. Pointer to Derived should always be pointer to Derived. You should never assign pointer to one object type to pointer to different object type, this programming style should be avoided. However, if you have no other option then explicit cast should be used.Transfigure
@Transfigure - this answer was written before C++11 was published. Even so, I just compiled it in GCC 6.3.0 (using C++14 by default) with no problems - obviously wrapping the variable declaration and calls in a main function etc. Pointer-to-derived implicitly casts to pointer-to-base (more specialized implicitly casts to more general). Visa-versa you need an explicit cast, usually a dynamic_cast. Anything else - very prone to undefined behavior so make sure you know what you're doing. To the best of my knowledge, this has not changed since before even C++98.Gunshot
@Transfigure - Of course naked raw owner pointers are bad style since C++11, and this example (without changes) has a memory leak as a result of that issue. Modern style = use a unique_ptr. A unique_ptr isn't implicitly castable IIRC, and it would probably violate uniqueness to support that cast, but I'd have to do some checking to be sure.Gunshot
@Transfigure - BTW - it's fairly common to claim that derived classes aren't distinct types from their bases, they're extensions of the same type. It's not an opinion I share, but it does reflect the OOP intent. That's why the implicit cast is supported for raw pointers and references.Gunshot
Note that C++ compilers today can often optimize late into early binding - when they can be certain of what the binding is going to be. This is also referred to as "de-virtualization".Leverage
@Leverage - optimizing away the overhead is certainly a good point, but I'm not really sure it counts as optimizing late binding into early binding. The cases where the compiler can be certain in advance are cases where early binding and late binding are equivalent (give the same behavior) so the compiler has more freedom to choose implementations, but my impression of the terminology is that it's about meaning, not about implementation.Gunshot
One interesting case happens when there's a very common case (determined by instrumented code, I think most often for VM languages like Java) but other cases can still happen. The compiler may generate both specialised and general-case code, and have an "if it's the expected common-case type" check to choose between them. This is still devirtualisation, and it still makes a late-binding decision of which implementation to use.Gunshot
@Steve314: I mean, for example, cases in which you call a virtual function for a base-class pointer, but the compiler can tell that the pointed-to object will actually always have the same implementation of that method.Leverage
@Steve314: std::unique_ptr actually is implicitly castable for this case, specifically to handle this upcast cast, which are totally normal. It doesn't violate uniqueness, since it's a move constructor, and not a copy constructor.Jonme
The code would illustrate the point at hand more strikingly if you renamed obj to basePtr.Chenille
@MooingDuck I think there is no such thing as an "implicit cast" -- that would be a conversion, right? "Cast" is the name for the syntax of explicit conversions, of which some -- those that may fail -- must be explicit (base pointer -> derived pointer), some not (the inverse).Chenille
@Peter-ReinstateMonica - I eventually noticed your comment is to MooingDuck, but as I already wrote this and as I often switch words like this too and maybe did in another comment MooingDuck is referencing - In the C++ standard I assume you're correct. I don't know if that distinction is specific to the C++ standard (which like any complex technical document, needs to define its own meanings for words that may be used differently elsewhere) or if that's a genuine strict distinction throughout programming/computer science or somewhere in-between. On the other point - accepted, will edit.Gunshot
Why even declare Base* basePtr = new Derived ();?Litchfield
P
94

You need at least 1 level of inheritance and an upcast to demonstrate it. Here is a very simple example:

class Animal
{        
    public: 
      // turn the following virtual modifier on/off to see what happens
      //virtual   
      std::string Says() { return "?"; }  
};

class Dog: public Animal
{
    public: std::string Says() { return "Woof"; }
};

void test()
{
    Dog* d = new Dog();
    Animal* a = d;       // refer to Dog instance with Animal pointer

    std::cout << d->Says();   // always Woof
    std::cout << a->Says();   // Woof or ?, depends on virtual
}
Podite answered 6/3, 2010 at 7:26 Comment(3)
Your example says that the returned string depends on whether the function is virtual, but it doesn't say which result corresponds to virtual and which corresponds to non-virtual. Additionally, it's a little confusing as you're not using the string that's being returned.Worldweary
With Virtual keyword: Woof. Without Virtual keyword: ?.Peso
@HeshamEraqi without virtual it is early binding and it will show "?" of base classBillingsgate
V
61

Virtual Functions are used to support Runtime Polymorphism.

That is, virtual keyword tells the compiler not to make the decision (of function binding) at compile time, rather postpone it for runtime".

  • You can make a function virtual by preceding the keyword virtual in its base class declaration. For example,

    class Base
    {
       virtual void func();
    }
    
  • When a Base Class has a virtual member function, any class that inherits from the Base Class can redefine the function with exactly the same prototype i.e. only functionality can be redefined, not the interface of the function.

    class Derive : public Base
    {
       void func();
    }
    
  • A Base class pointer can be used to point to Base class object as well as a Derived class object.

  • When the virtual function is called by using a Base class pointer, the compiler decides at run-time which version of the function - i.e. the Base class version or the overridden Derived class version - is to be called. This is called Runtime Polymorphism.

Vincent answered 12/10, 2016 at 9:41 Comment(0)
N
50

You need virtual methods for safe downcasting, simplicity, and conciseness.

That’s what virtual methods do: they downcast safely, with apparently simple and concise code, avoiding the unsafe manual casts in the more complex and verbose code that you otherwise would have.


Non-virtual method ⇒ static binding ========================================

The following code is intentionally “incorrect”. It doesn’t declare the value method as virtual, and therefore produces an unintended “wrong” result, namely 0:

#include <iostream>
using namespace std;

class Expression
{
public:
    auto value() const
        -> double
    { return 0.0; }         // This should never be invoked, really.
};

class Number
    : public Expression
{
private:
    double  number_;
    
public:
    auto value() const
        -> double
    { return number_; }     // This is OK.

    Number( double const number )
        : Expression()
        , number_( number )
    {}
};

class Sum
    : public Expression
{
private:
    Expression const*   a_;
    Expression const*   b_;
    
public:
    auto value() const
        -> double
    { return a_->value() + b_->value(); }       // Uhm, bad! Very bad!

    Sum( Expression const* const a, Expression const* const b )
        : Expression()
        , a_( a )
        , b_( b )
    {}
};

auto main() -> int
{
    Number const    a( 3.14 );
    Number const    b( 2.72 );
    Number const    c( 1.0 );

    Sum const       sum_ab( &a, &b );
    Sum const       sum( &sum_ab, &c );
    
    cout << sum.value() << endl;
}

In the line commented as “bad” the Expression::value method is called, because the statically known type (the type known at compile time) is Expression, and the value method is not virtual.


Virtual method ⇒ dynamic binding. ======================================

Declaring value as virtual in the statically known type Expression ensures that each call will check what actual type of object this is, and call the relevant implementation of value for that dynamic type:

#include <iostream>
using namespace std;

class Expression
{
public:
    virtual
    auto value() const -> double
        = 0;
};

class Number
    : public Expression
{
private:
    double  number_;
    
public:
    auto value() const -> double
        override
    { return number_; }

    Number( double const number )
        : Expression()
        , number_( number )
    {}
};

class Sum
    : public Expression
{
private:
    Expression const*   a_;
    Expression const*   b_;
    
public:
    auto value() const -> double
        override
    { return a_->value() + b_->value(); }    // Dynamic binding, OK!

    Sum( Expression const* const a, Expression const* const b )
        : Expression()
        , a_( a )
        , b_( b )
    {}
};

auto main() -> int
{
    Number const    a( 3.14 );
    Number const    b( 2.72 );
    Number const    c( 1.0 );

    Sum const       sum_ab( &a, &b );
    Sum const       sum( &sum_ab, &c );
    
    cout << sum.value() << endl;
}

Here the output is 6.86 as it should be since the virtual method is called virtually. This is also called dynamic binding of the calls. A little check is performed, finding the actual dynamic type of object, and the relevant method implementation for that dynamic type is called.

The relevant implementation is the one in the most specific (most derived) class.

Note that method implementations in derived classes here are not marked virtual, but are instead marked override. They could be marked virtual but they’re automatically virtual. The override keyword ensures that if there is not such a virtual method in some base class, then you’ll get an error (which is desirable).


The ugliness of doing this without virtual methods ==================================================

Without virtual one would have to implement some Do It Yourself version of the dynamic binding. It’s this that generally involves unsafe manual downcasting, complexity, and verbosity.

For the case of a single function, as here, it suffices to store a function pointer in the object and call via that function pointer, but even so it involves some unsafe downcasts, complexity, and verbosity, to wit:

#include <iostream>
using namespace std;

class Expression
{
protected:
    typedef auto Value_func( Expression const* ) -> double;

    Value_func* value_func_;

public:
    auto value() const
        -> double
    { return value_func_( this ); }
    
    Expression(): value_func_( nullptr ) {}     // Like a pure virtual.
};

class Number
    : public Expression
{
private:
    double  number_;
    
    static
    auto specific_value_func( Expression const* expr )
        -> double
    { return static_cast<Number const*>( expr )->number_; }

public:
    Number( double const number )
        : Expression()
        , number_( number )
    { value_func_ = &Number::specific_value_func; }
};

class Sum
    : public Expression
{
private:
    Expression const*   a_;
    Expression const*   b_;
    
    static
    auto specific_value_func( Expression const* expr )
        -> double
    {
        auto const p_self  = static_cast<Sum const*>( expr );
        return p_self->a_->value() + p_self->b_->value();
    }

public:
    Sum( Expression const* const a, Expression const* const b )
        : Expression()
        , a_( a )
        , b_( b )
    { value_func_ = &Sum::specific_value_func; }
};


auto main() -> int
{
    Number const    a( 3.14 );
    Number const    b( 2.72 );
    Number const    c( 1.0 );

    Sum const       sum_ab( &a, &b );
    Sum const       sum( &sum_ab, &c );
    
    cout << sum.value() << endl;
}

One positive way of looking at this is, if you encounter unsafe downcasting, complexity, and verbosity as above, then often a virtual method or methods can really help.

Noam answered 24/11, 2014 at 7:24 Comment(0)
P
39

If the base class is Base, and a derived class is Der, you can have a Base *p pointer which actually points to an instance of Der. When you call p->foo();, if foo is not virtual, then Base's version of it executes, ignoring the fact that p actually points to a Der. If foo is virtual, p->foo() executes the "leafmost" override of foo, fully taking into account the actual class of the pointed-to item. So the difference between virtual and non-virtual is actually pretty crucial: the former allows runtime polymorphism, the core concept of OO programming, while the latter does not.

Pustulant answered 6/3, 2010 at 7:27 Comment(2)
I hate to contradict you, but compile-time polymorphism is still polymorphism. Even overloading non-member functions is a form of polymorphism - ad-hoc polymorphism using the terminology in your link. The difference here is between early and late binding.Gunshot
@Steve314, you're pedantically correct (as a fellow pedant, I approve that;-) -- editing the answer to add the missing adjective;-).Pustulant
G
30

I would like to add another use of Virtual function though it uses the same concept as above stated answers but I guess its worth mentioning.

VIRTUAL DESTRUCTOR

Consider this program below, without declaring Base class destructor as virtual; memory for Cat may not be cleaned up.

class Animal {
    public:
    ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat() {
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

Output:

Deleting an Animal
class Animal {
    public:
    virtual ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat(){
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

Output:

Deleting an Animal name Cat
Deleting an Animal
Grodin answered 2/3, 2017 at 9:44 Comment(1)
without declaring Base class destructor as virtual; memory for Cat may not be cleaned up. It's worse than that. Deleting a derived object through a base pointer/reference is pure undefined behaviour. So, it's not just that some memory might leak. Rather, the program is ill-formed, so the compiler may transform it into anything: machine code that happens to work fine, or does nothing, or summons demons from your nose, or etc. That's why, if a program is designed in such a way that some user might delete a derived instance through a base reference, the base must have a virtual destructorCatalysis
C
28

Need for Virtual Function explained [Easy to understand]

#include<iostream>

using namespace std;

class A{
public: 
        void show(){
        cout << " Hello from Class A";
    }
};

class B :public A{
public:
     void show(){
        cout << " Hello from Class B";
    }
};


int main(){

    A *a1 = new B; // Create a base class pointer and assign address of derived object.
    a1->show();

}

Output will be:

Hello from Class A.

But with virtual function:

#include<iostream>

using namespace std;

class A{
public:
    virtual void show(){
        cout << " Hello from Class A";
    }
};

class B :public A{
public:
    virtual void show(){
        cout << " Hello from Class B";
    }
};


int main(){

    A *a1 = new B;
    a1->show();

}

Output will be:

Hello from Class B.

Hence with virtual function you can achieve runtime polymorphism.

Coachwhip answered 12/12, 2014 at 11:56 Comment(0)
B
24

You have to distinguish between overriding and overloading. Without the virtual keyword you only overload a method of a base class. This means nothing but hiding. Let's say you have a base class Base and a derived class Specialized which both implement void foo(). Now you have a pointer to Base pointing to an instance of Specialized. When you call foo() on it you can observe the difference that virtual makes: If the method is virtual, the implementation of Specialized will be used, if it is missing, the version from Base will be chosen. It is best practice to never overload methods from a base class. Making a method non-virtual is the way of its author to tell you that its extension in subclasses is not intended.

Bollix answered 6/3, 2010 at 7:27 Comment(2)
Without virtual you are not overloading. You are shadowing. If a base class B has one or more functions foo, and the derived class D defines a foo name, that foo hides all of those foo-s in B. They are reached as B::foo using scope resolution. To promote B::foo functions into D for overloading, you have to use using B::foo.Excited
"overloading" basically means you write another function that by pure coincidence has the same name as an existing one.Tablespoon
G
23

I've my answer in form of a conversation to be a better read:


Why do we need virtual functions?

Because of Polymorphism.

What is Polymorphism?

The fact that a base pointer can also point to derived type objects.

How does this definition of Polymorphism lead into the need for virtual functions?

Well, through early binding.

What is early binding?

Early binding(compile-time binding) in C++ means that a function call is fixed before the program is executed.

So...?

So if you use a base type as the parameter of a function, the compiler will only recognize the base interface, and if you call that function with any arguments from derived classes, it gets sliced off, which is not what you want to happen.

If it's not what we want to happen, why is this allowed?

Because we need Polymorphism!

What's the benefit of Polymorphism then?

You can use a base type pointer as the parameter of a single function, and then in the run-time of your program, you can access each of the derived type interfaces(e.g. their member functions) without any issues, using dereferencing of that single base pointer.

I still don't know what virtual functions are good for...! And this was my first question!

well, this is because you asked your question too soon!

Why do we need virtual functions?

Assume that you called a function with a base pointer, which had the address of an object from one of its derived classes. As we've talked about it above, in the run-time, this pointer gets dereferenced, so far so good, however, we expect a method(== a member function) "from our derived class" to be executed! However, a same method(one that has a same header) is already defined in the base class, so why should your program bother to choose the other method? In other words I mean, how can you tell this scenario off from what we used to see normally happen before?

The brief answer is "a Virtual member function in base", and a little longer answer is that, "at this step, if the program sees a virtual function in the base class, it knows(realizes) that you're trying to use polymorphism" and so goes to derived classes(using v-table, a form of late binding) to find that another method with the same header, but with -expectedly- a different implementation.

Why a different implementation?

You knuckle-head! Go read a good book!

OK, wait wait wait, why would one bother to use base pointers, when he/she could simply use derived type pointers? You be the judge, is all this headache worth it? Look at these two snippets:

//1:

Parent* p1 = &boy;
p1 -> task();
Parent* p2 = &girl;
p2 -> task();

//2:

Boy* p1 = &boy;
p1 -> task();
Girl* p2 = &girl;
p2 -> task();

OK, although I think that 1 is still better than 2, you could write 1 like this either:

//1:

Parent* p1 = &boy;
p1 -> task();
p1 = &girl;
p1 -> task();

and moreover, you should be aware that this is yet just a contrived use of all the things I've explained to you so far. Instead of this, assume for example a situation in which you had a function in your program that used the methods from each of the derived classes respectively(getMonthBenefit()):

double totalMonthBenefit = 0;    
std::vector<CentralShop*> mainShop = { &shop1, &shop2, &shop3, &shop4, &shop5, &shop6};
for(CentralShop* x : mainShop){
     totalMonthBenefit += x -> getMonthBenefit();
}

Now, try to re-write this, without any headaches!

double totalMonthBenefit=0;
Shop1* branch1 = &shop1;
Shop2* branch2 = &shop2;
Shop3* branch3 = &shop3;
Shop4* branch4 = &shop4;
Shop5* branch5 = &shop5;
Shop6* branch6 = &shop6;
totalMonthBenefit += branch1 -> getMonthBenefit();
totalMonthBenefit += branch2 -> getMonthBenefit();
totalMonthBenefit += branch3 -> getMonthBenefit();
totalMonthBenefit += branch4 -> getMonthBenefit();
totalMonthBenefit += branch5 -> getMonthBenefit();
totalMonthBenefit += branch6 -> getMonthBenefit();

And actually, this might be yet a contrived example either!

Gutsy answered 27/6, 2017 at 15:40 Comment(1)
the concept of iterating on different types of (sub-)objects using a single (super-)object type should be highlighted, that's a good point you gave, thanksContorted
K
21

Why do we need Virtual Methods in C++?

Quick Answer:

  1. It provides us with one of the needed "ingredients"1 for object oriented programming.

In Bjarne Stroustrup C++ Programming: Principles and Practice, (14.3):

The virtual function provides the ability to define a function in a base class and have a function of the same name and type in a derived class called when a user calls the base class function. That is often called run-time polymorphism, dynamic dispatch, or run-time dispatch because the function called is determined at run time based on the type of the object used.

  1. It is the fastest more efficient implementation if you need a virtual function call 2.

To handle a virtual call, one needs one or more pieces of data related to the derived object 3. The way that is usually done is to add the address of table of functions. This table is usually referred to as virtual table or virtual function table and its address is often called the virtual pointer. Each virtual function gets a slot in the virtual table. Depending of the caller's object (derived) type, the virtual function, in its turn, invokes the respective override.


1.The use of inheritance, run-time polymorphism, and encapsulation is the most common definition of object-oriented programming.

2. You can't code functionality to be any faster or to use less memory using other language features to select among alternatives at run time. Bjarne Stroustrup C++ Programming: Principles and Practice.(14.3.1).

3. Something to tell which function is really invoked when we call the base class containing the virtual function.

Kibitka answered 27/9, 2015 at 9:37 Comment(0)
U
14

When you have a function in the base class, you can Redefine or Override it in the derived class.

Redefining a method : A new implementation for the method of base class is given in the derived class. Does not facilitate Dynamic binding.

Overriding a method: Redefining a virtual method of the base class in the derived class. Virtual method facilitates Dynamic Binding.

So when you said :

But earlier in the book, when learning about basic inheritance, I was able to override base methods in derived classes without using 'virtual'.

you were not overriding it as the method in the base class was not virtual, rather you were redefining it

Unification answered 6/2, 2012 at 8:29 Comment(0)
S
11

It helps if you know the underlying mechanisms. C++ formalizes some coding techniques used by C programmers, "classes" replaced using "overlays" - structs with common header sections would be used to handle objects of different types but with some common data or operations. Normally the base struct of the overlay (the common part) has a pointer to a function table which points to a different set of routines for each object type. C++ does the same thing but hides the mechanisms i.e. the C++ ptr->func(...) where func is virtual as C would be (*ptr->func_table[func_num])(ptr,...), where what changes between derived classes is the func_table contents. [A non-virtual method ptr->func() just translates to mangled_func(ptr,..).]

The upshot of that is that you only need to understand the base class in order to call the methods of a derived class, i.e. if a routine understands class A, you can pass it a derived class B pointer then the virtual methods called will be those of B rather than A since you go through the function table B points at.

Shanell answered 30/11, 2012 at 8:22 Comment(0)
S
10

The keyword virtual tells the compiler it should not perform early binding. Instead, it should automatically install all the mechanisms necessary to perform late binding. To accomplish this, the typical compiler1 creates a single table (called the VTABLE) for each class that contains virtual functions.The compiler places the addresses of the virtual functions for that particular class in the VTABLE. In each class with virtual functions,it secretly places a pointer, called the vpointer (abbreviated as VPTR), which points to the VTABLE for that object. When you make a virtual function call through a base-class pointer the compiler quietly inserts code to fetch the VPTR and look up the function address in the VTABLE, thus calling the correct function and causing late binding to take place.

More details in this link http://cplusplusinterviews.blogspot.sg/2015/04/virtual-mechanism.html

Syverson answered 23/4, 2015 at 12:49 Comment(0)
T
8

The virtual keyword forces the compiler to pick the method implementation defined in the object's class rather than in the pointer's class.

Shape *shape = new Triangle(); 
cout << shape->getName();

In the above example, Shape::getName will be called by default, unless the getName() is defined as virtual in the Base class Shape. This forces the compiler to look for the getName() implementation in the Triangle class rather than in the Shape class.

The virtual table is the mechanism in which the compiler keeps track of the various virtual-method implementations of the subclasses. This is also called dynamic dispatch, and there is some overhead associated with it.

Finally, why is virtual even needed in C++, why not make it the default behavior like in Java?

  1. C++ is based on the principles of "Zero Overhead" and "Pay for what you use". So it doesn't try to perform dynamic dispatch for you, unless you need it.
  2. To provide more control to the interface. By making a function non-virtual, the interface/abstract class can control the behavior in all its implementations.
Travis answered 7/6, 2017 at 17:59 Comment(0)
M
8

OOP Answer: Subtype Polymorphism

In C++, virtual methods are needed to realise polymorphism, more precisely subtyping or subtype polymorphism if you apply the definition from wikipedia.

Wikipedia, Subtyping, 2019-01-09: In programming language theory, subtyping (also subtype polymorphism or inclusion polymorphism) is a form of type polymorphism in which a subtype is a datatype that is related to another datatype (the supertype) by some notion of substitutability, meaning that program elements, typically subroutines or functions, written to operate on elements of the supertype can also operate on elements of the subtype.

NOTE: Subtype means base class, and subtyp means inherited class.

Further reading regarding Subtype Polymorphism

Technical Answer: Dynamic Dispatch

If you have a pointer to a base class, then the call of the method (that is declared as virtual) will be dispatched to the method of the actual class of the created object. This is how Subtype Polymorphism is realised is C++.

Further reading Polymorphism in C++ and Dynamic Dispatch

Implementation Answer: Creates vtable entry

For each modifier "virtual" on methods, C++ compilers usually create an entry in the vtable of the class in which the method is declared. This is how common C++ compiler realise Dynamic Dispatch.

Further reading vtables


Example Code

#include <iostream>

using namespace std;

class Animal {
public:
    virtual void MakeTypicalNoise() = 0; // no implementation needed, for abstract classes
    virtual ~Animal(){};
};

class Cat : public Animal {
public:
    virtual void MakeTypicalNoise()
    {
        cout << "Meow!" << endl;
    }
};

class Dog : public Animal {
public:
    virtual void MakeTypicalNoise() { // needs to be virtual, if subtype polymorphism is also needed for Dogs
        cout << "Woof!" << endl;
    }
};

class Doberman : public Dog {
public:
    virtual void MakeTypicalNoise() {
        cout << "Woo, woo, woow!";
        cout << " ... ";
        Dog::MakeTypicalNoise();
    }
};

int main() {

    Animal* apObject[] = { new Cat(), new Dog(), new Doberman() };

    const   int cnAnimals = sizeof(apObject)/sizeof(Animal*);
    for ( int i = 0; i < cnAnimals; i++ ) {
        apObject[i]->MakeTypicalNoise();
    }
    for ( int i = 0; i < cnAnimals; i++ ) {
        delete apObject[i];
    }
    return 0;
}

Output of Example Code

Meow!
Woof!
Woo, woo, woow! ... Woof!

UML class diagram of code example

UML class diagram of code example

Marbleize answered 15/12, 2018 at 17:16 Comment(1)
Take my upvote because you show the perhaps most important use of polymorphism: That a base class with virtual member functions specifies an interface or, in other words, an API. Code using such a class frame work (here: your main function) can treat all items in a collection (here: your array) uniformly and does not need to, does not want to, and indeed often cannot know which concrete implementation will be invoked at run time, for example because it does not yet exist. This is one of the foundations of carving out abstract relations between objects and handlers.Chenille
S
7

The problem with explanations to virtual functions, is that they don't explain how it is used in practice, and how it helps with maintainability. I've created a virtual function tutorial which people have already found very useful. Plus, it's based on a battlefield premise, which makes it a bit more exciting: https://nrecursions.blogspot.com/2015/06/so-why-do-we-need-virtual-functions.html.

Consider this battlefield application:
enter image description here

#include "iostream"

//This class is created by Gun1's company
class Gun1 {public: void fire() {std::cout<<"gun1 firing now\n";}};
//This class is created by Gun2's company
class Gun2 {public: void shoot() {std::cout<<"gun2 shooting now\n";}};

//We create an abstract class to interface with WeaponController
class WeaponsInterface {
 public:
 virtual void shootTarget() = 0;
};

//A wrapper class to encapsulate Gun1's shooting function
class WeaponGun1 : public WeaponsInterface {
 private:
 Gun1* g;

 public:
 WeaponGun1(): g(new Gun1()) {}
 ~WeaponGun1() { delete g;}
 virtual void shootTarget() { g->fire(); }
};

//A wrapper class to encapsulate Gun2's shooting function
class WeaponGun2 : public WeaponsInterface {
 private:
 Gun2* g;

 public:
 WeaponGun2(): g(new Gun2()) {}
 ~WeaponGun2() { delete g;}
 virtual void shootTarget() { g->shoot(); }
};

class WeaponController {
 private:
 WeaponsInterface* w;
 WeaponGun1* g1;
 WeaponGun2* g2;
 public:
 WeaponController() {g1 = new WeaponGun1(); g2 = new WeaponGun2(); w = g1;}
 ~WeaponController() {delete g1; delete g2;}
 void shootTarget() { w->shootTarget();}
 void changeGunTo(int gunNumber) {//Virtual functions makes it easy to change guns dynamically
   switch(gunNumber) {
     case 1: w = g1; break;
     case 2: w = g2; break;
   }
 }
};


class BattlefieldSoftware {
 private:
 WeaponController* wc;
 public:
 BattlefieldSoftware() : wc(new WeaponController()) {}
 ~BattlefieldSoftware() { delete wc; }

 void shootTarget() { wc->shootTarget(); }
 void changeGunTo(int gunNumber) {wc->changeGunTo(gunNumber); }
};


int main() {
 BattlefieldSoftware* bf = new BattlefieldSoftware();
 bf->shootTarget();
 for(int i = 2; i > 0; i--) {
     bf->changeGunTo(i);
     bf->shootTarget();
 }
 delete bf;
}

I encourage you to first read the post on the blog to get the gist of why the wrapper classes were created.

As visible in the image, there are various guns/missiles that can be connected to a battlefield software, and commands can be issued to those weapons, to fire or re-calibrate etc. The challenge here is to be able to change/replace the guns/missiles without having to make changes to the blue battlefield software, and to be able to switch between weapons during runtime, without having to make changes in the code and re-compile.

The code above shows how the problem is solved, and how virtual functions with well-designed wrapper classes can encapsulate functions and help in assigning derived class pointers during runtime. The creation of class WeaponGun1 ensures that you've completely separated the handling of Gun1 into the class. Whatever changes you do to Gun1, you'll only have to make changes in WeaponGun1, and have the confidence that no other class is affected.

Because of WeaponsInterface class, you can now assign any derived class to the base class pointer WeaponsInterface and because it's functions are virtual, when you call WeaponsInterface's shootTarget, the derived class shootTarget gets invoked.

Best part is, you can change guns during runtime (w=g1 and w=g2). This is the main advantage of virtual functions and this is why we need virtual functions.

So no more necessity to comment out code in various places when changing guns. It's now a simple and clean procedure, and adding more gun classes is also easier because we just have to create a new WeaponGun3 or WeaponGun4 class and we can be confident that it won't mess up BattlefieldSoftware's code or WeaponGun1/WeaponGun2's code.

Swept answered 20/6, 2020 at 2:46 Comment(1)
I like this the most too. When I see the animal and dog example I had the exact same thought like why would you do that? This is a way better example of a practical way of understanding virtual functions. This one thing I'd to mention. The first example (animal and dog classes) in the original blog post is not complete. If I hadn't read the other examples before I woundn't have been able to understand it.Certes
C
5

Why do we need virtual functions?

Virtual functions avoid unnecessary typecasting problem, and some of us can debate that why do we need virtual functions when we can use derived class pointer to call the function specific in derived class!the answer is - it nullifies the whole idea of inheritance in large system development, where having single pointer base class object is much desired.

Let's compare below two simple programs to understand the importance of virtual functions:

Program without virtual functions:

#include <iostream>
using namespace std;

class father
{
    public: void get_age() {cout << "Fathers age is 50 years" << endl;}
};

class son: public father
{
    public : void get_age() { cout << "son`s age is 26 years" << endl;}
};

int main(){
    father *p_father = new father;
    son *p_son = new son;

    p_father->get_age();
    p_father = p_son;
    p_father->get_age();
    p_son->get_age();
    return 0;
}

OUTPUT:

Fathers age is 50 years
Fathers age is 50 years
son`s age is 26 years

Program with virtual function:

#include <iostream>
using namespace std;

class father
{
    public:
        virtual void get_age() {cout << "Fathers age is 50 years" << endl;}
};

class son: public father
{
    public : void get_age() { cout << "son`s age is 26 years" << endl;}
};

int main(){
    father *p_father = new father;
    son *p_son = new son;

    p_father->get_age();
    p_father = p_son;
    p_father->get_age();
    p_son->get_age();
    return 0;
}

OUTPUT:

Fathers age is 50 years
son`s age is 26 years
son`s age is 26 years

By closely analyzing both the outputs one can understand the importance of virtual functions.

Curvy answered 10/6, 2017 at 10:2 Comment(0)
R
2

About efficiency, the virtual functions are slightly less efficient as the early-binding functions.

"This virtual call mechanism can be made almost as efficient as the "normal function call" mechanism (within 25%). Its space overhead is one pointer in each object of a class with virtual functions plus one vtbl for each such class" [A tour of C++ by Bjarne Stroustrup]

Rampart answered 28/12, 2014 at 14:19 Comment(1)
Late binding doesn't just make function call slower, it makes the called function unknown until run time, so optimizations across the function call can't be applied. This can change everything f.ex. in cases where value propagation removes a lot of code (think if(param1>param2) return cst; where the compiler can reduce the whole function call to a constant in some cases).Modernistic
S
2

Virtual methods are used in interface design. For example in Windows there is an interface called IUnknown like below:

interface IUnknown {
  virtual HRESULT QueryInterface (REFIID riid, void **ppvObject) = 0;
  virtual ULONG   AddRef () = 0;
  virtual ULONG   Release () = 0;
};

These methods are left to the interface user to implement. They are essential for the creation and destruction of certain objects that must inherit IUnknown. In this case the run-time is aware of the three methods and expects them to be implemented when it calls them. So in a sense they act as a contract between the object itself and whatever uses that object.

Superman answered 20/2, 2015 at 3:1 Comment(1)
the run-time is aware of the three methods and expects them to be implemented As they are pure virtual, there is no way to create an instance of IUnknown, and so all subclasses must implement all such methods in order to merely compile. There's no danger of not implementing them and only finding that out at runtime (but obviously one can wrongly implement them, of course!). And wow, today I learned Windows #defines a macro with the word interface, presumably because their users can't just (A) see the prefix I in the name or (B) look at the class to see it's an interface. UghCatalysis
N
2

Here is complete example that illustrates why virtual method is used.

#include <iostream>

using namespace std;

class Basic
{
    public:
    virtual void Test1()
    {
        cout << "Test1 from Basic." << endl;
    }
    virtual ~Basic(){};
};
class VariantA : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantA." << endl;
    }
};
class VariantB : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantB." << endl;
    }
};

int main()
{
    Basic *object;
    VariantA *vobjectA = new VariantA();
    VariantB *vobjectB = new VariantB();

    object=(Basic *) vobjectA;
    object->Test1();

    object=(Basic *) vobjectB;
    object->Test1();

    delete vobjectA;
    delete vobjectB;
    return 0;
}
Novercal answered 2/2, 2018 at 10:29 Comment(0)
C
2

i think you are referring to the fact once a method is declared virtual you don't need to use the 'virtual' keyword in overrides.

class Base { virtual void foo(); };

class Derived : Base 
{ 
  void foo(); // this is overriding Base::foo
};

If you don't use 'virtual' in Base's foo declaration then Derived's foo would just be shadowing it.

Carbamate answered 19/7, 2018 at 20:15 Comment(0)
L
1

Here is a merged version of the C++ code for the first two answers.

#include        <iostream>
#include        <string>

using   namespace       std;

class   Animal
{
        public:
#ifdef  VIRTUAL
                virtual string  says()  {       return  "??";   }
#else
                string  says()  {       return  "??";   }
#endif
};

class   Dog:    public Animal
{
        public:
                string  says()  {       return  "woof"; }
};

string  func(Animal *a)
{
        return  a->says();
}

int     main()
{
        Animal  *a = new Animal();
        Dog     *d = new Dog();
        Animal  *ad = d;

        cout << "Animal a says\t\t" << a->says() << endl;
        cout << "Dog d says\t\t" << d->says() << endl;
        cout << "Animal dog ad says\t" << ad->says() << endl;

        cout << "func(a) :\t\t" <<      func(a) <<      endl;
        cout << "func(d) :\t\t" <<      func(d) <<      endl;
        cout << "func(ad):\t\t" <<      func(ad)<<      endl;
}

Two different results are:

Without #define virtual, it binds at compile time. Animal *ad and func(Animal *) all point to the Animal's says() method.

$ g++ virtual.cpp -o virtual
$ ./virtual 
Animal a says       ??
Dog d says      woof
Animal dog ad says  ??
func(a) :       ??
func(d) :       ??
func(ad):       ??

With #define virtual, it binds at run time. Dog *d, Animal *ad and func(Animal *) point/refer to the Dog's says() method as Dog is their object type. Unless [Dog's says() "woof"] method is not defined, it will be the one searched first in the class tree, i.e. derived classes may override methods of their base classes [Animal's says()].

$ g++ virtual.cpp -D VIRTUAL -o virtual
$ ./virtual 
Animal a says       ??
Dog d says      woof
Animal dog ad says  woof
func(a) :       ??
func(d) :       woof
func(ad):       woof

It is interesting to note that all class attributes (data and methods) in Python are effectively virtual. Since all objects are dynamically created at runtime, there is no type declaration or a need for keyword virtual. Below is Python's version of code:

class   Animal:
        def     says(self):
                return  "??"

class   Dog(Animal):
        def     says(self):
                return  "woof"

def     func(a):
        return  a.says()

if      __name__ == "__main__":

        a = Animal()
        d = Dog()
        ad = d  #       dynamic typing by assignment

        print("Animal a says\t\t{}".format(a.says()))
        print("Dog d says\t\t{}".format(d.says()))
        print("Animal dog ad says\t{}".format(ad.says()))

        print("func(a) :\t\t{}".format(func(a)))
        print("func(d) :\t\t{}".format(func(d)))
        print("func(ad):\t\t{}".format(func(ad)))

The output is:

Animal a says       ??
Dog d says      woof
Animal dog ad says  woof
func(a) :       ??
func(d) :       woof
func(ad):       woof

which is identical to C++'s virtual define. Note that d and ad are two different pointer variables referring/pointing to the same Dog instance. The expression (ad is d) returns True and their values are the same <main.Dog object at 0xb79f72cc>.

Lorca answered 5/9, 2018 at 3:56 Comment(0)
B
1

Are you familiar with function pointers? Virtual functions are a similar idea, except you can easily bind data to virtual functions (as class members). It is not as easy to bind data to function pointers. To me, this is the main conceptual distinction. A lot of other answers here are just saying "because... polymorphism!"

Bauhaus answered 24/4, 2019 at 22:10 Comment(0)
D
0

We need virtual methods for supporting "Run time Polymorphism". When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.

Decameter answered 7/3, 2017 at 3:23 Comment(0)
B
0

The bottom line is that virtual functions make life easier. Let's use some of M Perry's ideas and describe what would happen if we didn't have virtual functions and instead only could use member-function pointers. We have, in the normal estimation without virtual functions:

 class base {
 public:
 void helloWorld() { std::cout << "Hello World!"; }
  };

 class derived: public base {
 public:
 void helloWorld() { std::cout << "Greetings World!"; }
 };

 int main () {
      base hwOne;
      derived hwTwo = new derived();
      base->helloWorld(); //prints "Hello World!"
      derived->helloWorld(); //prints "Hello World!"

Ok, so that is what we know. Now let's try to do it with member-function pointers:

 #include <iostream>
 using namespace std;

 class base {
 public:
 void helloWorld() { std::cout << "Hello World!"; }
 };

 class derived : public base {
 public:
 void displayHWDerived(void(derived::*hwbase)()) { (this->*hwbase)(); }
 void(derived::*hwBase)();
 void helloWorld() { std::cout << "Greetings World!"; }
 };

 int main()
 {
 base* b = new base(); //Create base object
 b->helloWorld(); // Hello World!
 void(derived::*hwBase)() = &derived::helloWorld; //create derived member 
 function pointer to base function
 derived* d = new derived(); //Create derived object. 
 d->displayHWDerived(hwBase); //Greetings World!

 char ch;
 cin >> ch;
 }

While we can do some things with member-function pointers, they aren't as flexible as virtual functions. It is tricky to use a member-function pointer in a class; the member-function pointer almost, at least in my practice, always must be called in the main function or from within a member function as in the above example.

On the other hand, virtual functions, while they might have some function-pointer overhead, do simplify things dramatically.

EDIT: There is another method which is similar by eddietree: c++ virtual function vs member function pointer (performance comparison) .

Bourbon answered 27/5, 2019 at 3:8 Comment(0)
I
0

For my understanding of this question, it's asking why C++ requires a virtual keyword.

Because the compiler may can't determine which instance's method to call at compiling stage.

The following code gives an example:

#include <iostream>
using namespace std;

class Animal {
   public:
    virtual void Say() { cout << "Im animal"; }
};

class Cat : public Animal {
   public:
    void Say() { cout << "Im cat"; }
};

class Dog : public Animal {
   public:
    void Say() { cout << "Im dog"; }
};

Animal* NewAnimal() {
    int v = 1;
    // The input is totally unpredictable.
    cin >> v;
    switch (v) {
        case 1:
            return new Cat();
        case 2:
            return new Dog();
        default:
            return new Animal();
    }
}

int main(void) {
    auto x = NewAnimal();
    // Compiler can't determine what x is (a dog or a cat, or some animal else)
    // in compiling stage. So, to call which Say function, is runtime related.
    // That's to say, the Say function requires dynamically binding.
    // What the keyword virtual does, is to tell the compiler the Say function
    // should be determined at runtime stage, but not compiling stage.
    x->Say();
    return 0;
}

Which animal's Say to call, is totally unpredictable. We have to dynamically decide which one at runtime.

Improvised answered 27/5, 2023 at 10:15 Comment(1)
I think using auto for the variable x might obfuscate the actual point here. It's an Animal* (the base class) even though NewAnimal() returns any of the concrete animals. I'm pointing this out for anyone who is confused about this example.Pintail
I
-2

Following up on @user6359267's answer, the C++ scope hierarchy is

global -> namespace -> class -> local -> statement

Hence, each class defines a scope. If this weren't the case, overridden functions in a subclass would actually be redefining a function in the same scope, which the linker does not allow:

  1. A function must be declared before use in every translation unit, and
  2. A function can only be defined once in a given scope across the entire program (across all translation units)

Since each class defines its own scope, the function that gets called is the one defined in the class of the object that calls the function. So,

#include <iostream>
#include <string>

class Parent
{
public:
    std::string GetName() { return "Parent"; }
};

class Child : public Parent
{
public:
    std:::string GetName() { return "Child"; }
};

int main()
{
    Parent* parent = new Parent();
    std::cout << parent->GetName() << std::endl;

    Child* child = new Child();
    std::cout << child->GetName() << std::endl;

    *parent = child;
    std::cout << child->GetName() << std::endl;

    return 0;
}

outputs

Parent
Child
Parent

Hence, we need a way to tell the compiler that the function to call should be determined at runtime instead of compile time. This is what the virtual keyword does.

This is why function overloading is called a compile-time polymorphism (or early-binding) and virtual function overriding is called a runtime polymorphism (or late-binding).

Details:

Internally, when the compiler sees a virtual function, it creates a class member pointer, which points generically to a member of the class (and not to a specific instance of that member in an object) using the .* and ->* operators. Their job is to allow you to access a member of a class given a pointer to that member. These are rarely used directly by programmers (perhaps unless you're writing a compiler to implement "virtual").

Isagogics answered 20/11, 2021 at 20:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.