3
#include <iostream>
class X{
public:
    virtual void f() {std::cout << "1";}
};

class Y : public X{
public:
    void f() {std::cout << "2";}
    void g() {std::cout << "3";}
};

class Z : public Y{
public:
    virtual void f() {std::cout << "4";}
    void g() {std::cout << "5";}
    virtual void k() {std::cout << "6";}
};

void main()
{
    X *x = new Z;
    Y *y = new Z;
    Z *z = new Z;
    x->f(); // 4
    y->f(); // 4
    y->g(); // 3
    z->f(); // 4
    z->g(); // 5
    z->k(); // 6
    system("PAUSE");
}

Output: 443456.

I got confused, why did it not print '2' when doing 'y->f()'? f() inside Y class isn't a virtual function.

I'd like to know more about it, thank you for the help.

Tom S
  • 511
  • 1
  • 4
  • 19
  • 3
    "f() inside Y class isn't a virtual function."? Um... Actually, it is. Also: what is `y->f(x)`? I don't see anything like that in your code. – AnT stands with Russia Feb 26 '19 at 23:56
  • 1
    Very closely related. https://stackoverflow.com/questions/4895294/c-virtual-keyword-for-functions-in-derived-classes-is-it-necessary – R Sahu Feb 26 '19 at 23:59
  • You might as well write `void f() override { std::cout << "2"; }` inside the `Y` class – alter_igel Feb 27 '19 at 00:07

2 Answers2

5

why did it not print '2' when doing 'y->f(x)'? f() inside Y class isn't a virtual function.

Y::f is a virtual function. If a base class has a virtual function by the same name, then the derived class function is implicitly virtual as well.

eerorika
  • 232,697
  • 12
  • 197
  • 326
4

First of all, overloading isn't relevant here--you don't have any overloaded functions (which would be functions with the same name, but different signatures, at the same scope).

Second, you're not really dealing much with virtual functions either. One one hand, it's true that you've (quite correctly) declared f() as a virtual function in your base class (X).

You've also overridden that virtual function in your derived class Y.

But, the primary time a virtual function means something is when you invoke the virtual function in an object of a derived class via a pointer (or reference) to the base class:

#include <iostream>

class base {
public:
    virtual void f() { std::cout << "base::f()\n"; }
    void g() { std::cout << "base::g()\n"; }
};

class derived : public base { 
public:
    virtual void f() { std::cout << "derived::f()\n"; }
    virtual void g() { std::cout << "derived::g()\n"; }
};

int main() { 
    base *b = new base;          // first case: pointer to base, base object
    base *d = new derived;       // second case: pointer to base, derived object
    derived *d2 = new derived;   // third case: pointer to derived, derived object

    b->f(); // invokes base::f
    b->g(); // invokes base::g

    d->f(); // invokes derived::f
    d->g(); // invokes base::g

    d2->f(); // invokes derived::f
    d2->g(); // invokes derived::g
}

So, in the first case, we have a base pointer, referring to a base object. With this, the derived class might as well not exist--we always get the base class member functions, regardless of whether they're virtual.

The case you asked about is pretty much the same as the third case in this code: we have a pointer to the derived object referring to an object of the derived class. Here again, it doesn't matter whether a function is virtual or not. Since we're using a pointer to a derived, we always get the derived version of each function, regardless of whether it's virtual or not.

The case where virtual functions get interesting is the second one, where we have a pointer to the base class, but it's referring to an object of the derived class. In this case, g() (which isn't virtual) is statically bound, so the function that gets called depends on the type of the pointer. Since we're using a pointer to base, we get base::g() even though the pointer is actually referring to a derived object.

But, with f() (which is virtual), we get "late binding"--even though we're using a pointer to base, when we invoke f(), we invoke derived::f(), because the object being pointed at is a derived object.

So yes, in your code, derived::f() is virtual because it's declared virtual in base--but even if it wasn't virtual, since you used a pointer to the derived class, you'd still have gotten derived::f() even if f() wasn't virtual at all.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111