I'm learning C++ and I'm just getting into virtual functions.
From what I've read (in the book and online), virtual functions are functions in the base class that you can override in derived classes.
But earlier in the book, when learning about basic inheritance, I was able to override base functions in derived classes without using virtual
.
So 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. I just can't find a straight answer online.
转载于:https://stackoverflow.com/questions/2391679/why-do-we-need-virtual-functions-in-c
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.
You need at least 1 level of inheritance and a downcast 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
cout << d->Says(); // always Woof
cout << a->Says(); // Woof or ?, depends on virtual
}
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.
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 allow runtime polymorphism, the core concept of OO programming, while the latter don't.
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* obj = new Derived ();
// Note - constructed as Derived, but pointer stored as Base*
obj->Method1 (); // Prints "Base::Method1"
obj->Method2 (); // Prints "Derived::Method2"
EDIT - see this question.
Also - this tutorial covers early and late binding in C++.
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
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.
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.
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.
Declaring value
as virtual
in the statically known type Expression
ensures that the 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).
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.
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.
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]
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.
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
Why do we need Virtual Methods in C++?
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.
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.
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.
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
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.
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?
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.
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!
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;
}
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.
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>.