user4709059
user4709059

Reputation: 125

Confusion with virtual keyword in C++

I was studying on effects of virtual keyword in C++ and I came up with this code.

#include<iostream>

using namespace std;

class A {
public:
    virtual void show(){
        cout << "A \n";
    }
};

class B : public A {
public:
    void show(){
        cout << "B \n";
    }
};

class C : public B {
public: 
    void show(){
        cout << "C \n"; 
    }
};

int main(){

    A *ab = new B;
    A *ac = new C;
    B *bc = new C;
    ab->show();
    ac->show();
    bc->show();

}

The expected output is:

B
C
B

Since show function in B is non-virtual. But the outcome when you compile this is:

B
C
C

It behaves as if show function in B is virtual. Why is this the case? Does B class gets overridden here? How come I point to the A class if I'm pointing a C class to the B class?

Upvotes: 6

Views: 1001

Answers (3)

Vlad from Moscow
Vlad from Moscow

Reputation: 310920

According to the C++ 2017 Standard (10.1.2 Function specifiers)

2 The virtual specifier shall be used only in the initial declaration of a non-static class member function; see 13.3.

And (13.3 Virtual functions)

2 If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (11.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides111 Base::vf. For convenience we say that any virtual function overrides itself. A virtual member function C::vf of a class object S is a final overrider unless the most derived class (4.5) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf. In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.

Thus the function show in the class B is a virtual function because it has the same signature as the function declared in the class A.

Consider a more interesting example when in the class B there is added the qualifier const to the member function show.

#include<iostream>

using namespace std;

class A {
public:
    virtual void show(){
        cout << "A \n";
    }
};

class B : public A {
public:
    void show() const{
        cout << "B \n";
    }
};

class C : public B {
public: 
    void show() {
        cout << "C \n"; 
    }
};

int main(){

    A *ab = new B;
    A *ac = new C;
    B *bc = new C;
    ab->show();
    ac->show();
    bc->show();

}

In this case the output will look like

A 
C 
B 

In this expression statement

    ab->show();

there is called the virtual function show declared in the class A.

In this statement

    ac->show();

there is called the same virtual function that is overridden in the class C. The compier uses the virtual function declaration in the class A because the static type of the pointer ac is A *.

In this statement

    bc->show();

there is called non-virtual member function show with the qualifier const because the static type of the pointer bc is B * and the compiler finds the function in the class B that hides the virtual function declared in the class A..

For the original program you could use the specifier override to make the class definitions more clear. For example

#include<iostream>

using namespace std;

class A {
public:
    virtual void show(){
        cout << "A \n";
    }
};

class B : public A {
public:
    void show() override{
        cout << "B \n";
    }
};

class C : public B {
public: 
    void show() override{
        cout << "C \n"; 
    }
};

int main(){

    A *ab = new B;
    A *ac = new C;
    B *bc = new C;
    ab->show();
    ac->show();
    bc->show();

}

Upvotes: 7

Horia Coman
Horia Coman

Reputation: 8781

The behaviour is the correct one. Since the show function is virtual, the version invoked will be the one attached to the instance you're calling it on, rather than the one described by the type of that instance (which can be a base of that instance's real type).

Upvotes: 0

Gaurav Sehgal
Gaurav Sehgal

Reputation: 7542

You don't need to specify a function as virtual in derived class, if specified in the base class.

Upvotes: 7

Related Questions