2

I got a little bit confused with the topic of virtual functions in c++. Is there a flowchart that summarize all possible cases?

for example:

    class A {
       public:
          virtual void f(const int i) { cout << "A::f" << endl; }
    };

    class B : public A {
       public:
          // Hide A's f with new implementations
          void f() { cout << "B::f" << endl; }
    };

    class C : public B {
       public:
          void f() { cout << "C::f" << endl; }
    };
class D : public B { public:
    void f(const int i) { cout << "D::f" << endl; }
};


    void main() {
       D d;
       C c;
       B* pb = &c;
       pb->f();
       A* pa = &d;
       A* paa = &c;
       pa->f(1);
       paa->f(1); //in here C::f would be invoked?
    }

In this case, B hides A::f, and C has an override for B::f with the same signature.

Would pb->f() invoke C::f? Would pa->f(1) invoke A::f?

I ask it to know if B::f is still considered virtual so its derivative classes can override it, though it hides A::f.

As well as If C::f is considered virtual by default?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Day_Dreamer
  • 3,311
  • 7
  • 34
  • 61
  • 2
    _"Would `pb->f()` invoke `C::f`?"_ [No.](http://ideone.com/qgVKPt) and [yes](http://ideone.com/emlHrt) if you provide the `virtual` keyword. – πάντα ῥεῖ Feb 03 '15 at 19:44
  • you mean once you hide the the base virtual function, the hiding function is not virtual by default? – Day_Dreamer Feb 03 '15 at 19:45
  • possible duplicate of [Virtual function calling using dereference object](http://stackoverflow.com/questions/3082291/virtual-function-calling-using-dereference-object) – max Feb 03 '15 at 19:57
  • @Day_Dreamer You might want to read here also: http://stackoverflow.com/questions/18198314/override-keyword-in-c – πάντα ῥεῖ Feb 03 '15 at 19:59

4 Answers4

3

A::f and B::f are two different functions, even though they have the same name; since B::f was not declared as virtual only A::f is virtual - and nobody overrides it.

pb->f() uses the static type of the pointer, which is B*, to determine which function to call; that would be B::f.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
2

Would pb->f() invoke C::f?

No, it won't.

I ask it to know if B::f is still considered virtual so its derivative classes can override it, though it hides A::f.

B::f() is not a virtual member function.

To make B::f() a virtual member function, you have to use:

class B : public A {
   public:
      // Hide A's f with new implementations
      virtual void f() { cout << "B::f" << endl; }
};

Update

You updated your post with the following additional question:

Would pa->f(1) invoke A::f?

Yes, it would. Seen through pa, neither B::f() nor C::f() exist, only A::f(int) exists.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • If I would have declared B::f with the same signature it would be virtual by default, even without explicit "virtual". so you imply that the default "virtual" is removed when B::f is hiding A::f with different signature? – Day_Dreamer Feb 03 '15 at 19:48
  • 1
    @Day_Dreamer, that is partially correct. By default, functions are not virtual. Since `B::f()` is not related to `A::f(int)`, it is not virtual by default. Hence removal of "virtual" is not the right way to think about it. "virtual" is not there to start with. – R Sahu Feb 03 '15 at 19:50
  • @Day_Dreamer: That's right, a function is only implicitly virtual if it overrides a virtual function. – Mike Seymour Feb 03 '15 at 19:54
1

Is there a flowchart that summarize all possible cases?

In full generality, you would need to know the entire set of name lookup rules in C++, which is unfortunately very complicated.

Assuming you just want to know what overrides what, you can find all the details in a few paragraphs in the standard.

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 (8.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 overrides Base::vf.

...

Even though destructors are not inherited, a destructor in a derived class overrides a base class destructor declared virtual; see 12.4 and 12.5.

...

The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. If a function D::f overrides a function B::f, the return types of the functions are covariant if they satisfy the following criteria:

  • both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes
  • the class in the return type of B::f is the same class as the class in the return type of D::f, or is an unambiguous and accessible direct or indirect base class of the class in the return type of D::f
  • both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f.

Because B::f does not have the same parameter types as A::f, B::f does not override A::f, and for the same reason, C::f does not override A::f. Since B::f is not declared virtual and it does not override A::f, B::f is not virtual. C::f does not override B::f because B::f is not virtual.

Since B::f is not virtual, pb->f() always invokes B::f and not any function named f in a derived class.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
0

B::f does not override A::f because they do not have the same parameter-type-list and therefore it is also not virtual, [class.virtual]/p2:

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 (8.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 overrides Base::vf.

So a derived class method can be implicitly virtual whether or not it has the virtual specifier, only if it matches certain properties of the base class method. In this case B::f is not virtual and so pb->f() uses the static type of the pointer, B*, and calls B::f and not C::f.

David G
  • 94,763
  • 41
  • 167
  • 253