11 Classes [class]

11.7 Derived classes [class.derived]

11.7.2 Virtual functions [class.virtual]

A non-static member function is a virtual function if it is first declared with the keyword virtual or if it overrides a virtual member function declared in a base class (see below).107
Note
:
Virtual functions support dynamic binding and object-oriented programming.
โ€” end note
 ]
A class that declares or inherits a virtual function is called a polymorphic class.108
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 ([dcl.fct]), cv-qualification, and ref-qualifier (or absence of same) as Baseโ€‹::โ€‹vf is declared, then Derivedโ€‹::โ€‹vf overrides109 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 ([intro.object]) 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.
Example
:
struct A {
  virtual void f();
};
struct B : virtual A {
  virtual void f();
};
struct C : B , virtual A {
  using A::f;
};

void foo() {
  C c;
  c.f();            // calls Bโ€‹::โ€‹f, the final overrider
  c.C::f();         // calls Aโ€‹::โ€‹f because of the using-declaration
}
โ€” end example
 ]
Example
:
struct A { virtual void f(); };
struct B : A { };
struct C : A { void f(); };
struct D : B, C { };            // OK: Aโ€‹::โ€‹f and Cโ€‹::โ€‹f are the final overriders
                                // for the B and C subobjects, respectively
โ€” end example
 ]
Note
:
A virtual member function does not have to be visible to be overridden, for example,
struct B {
  virtual void f();
};
struct D : B {
  void f(int);
};
struct D2 : D {
  void f();
};
the function f(int) in class D hides the virtual function f() in its base class B; Dโ€‹::โ€‹f(int) is not a virtual function.
However, f() declared in class D2 has the same name and the same parameter list as Bโ€‹::โ€‹f(), and therefore is a virtual function that overrides the function Bโ€‹::โ€‹f() even though Bโ€‹::โ€‹f() is not visible in class D2.
โ€” end note
 ]
If a virtual function f in some class B is marked with the virt-specifier final and in a class D derived from B a function Dโ€‹::โ€‹f overrides Bโ€‹::โ€‹f, the program is ill-formed.
Example
:
struct B {
  virtual void f() const final;
};

struct D : B {
  void f() const;   // error: Dโ€‹::โ€‹f attempts to override final Bโ€‹::โ€‹f
};
โ€” end example
 ]
If a virtual function is marked with the virt-specifier override and does not override a member function of a base class, the program is ill-formed.
Example
:
struct B {
  virtual void f(int);
};

struct D : B {
  virtual void f(long) override;        // error: wrong signature overriding Bโ€‹::โ€‹f
  virtual void f(int) override;         // OK
};
โ€” end example
 ]
A virtual function shall not have a trailing requires-clause ([dcl.decl]).
Example
:
struct A {
  virtual void f() requires true;       // error: virtual function cannot be constrained ([temp.constr.decl])
};
โ€” end example
 ]
Even though destructors are not inherited, a destructor in a derived class overrides a base class destructor declared virtual; see [class.dtor] and [class.free].
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 classes110
  • 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.
If the class type in the covariant return type of Dโ€‹::โ€‹f differs from that of Bโ€‹::โ€‹f, the class type in the return type of Dโ€‹::โ€‹f shall be complete at the point of declaration of Dโ€‹::โ€‹f or shall be the class type D.
When the overriding function is called as the final overrider of the overridden function, its result is converted to the type returned by the (statically chosen) overridden function ([expr.call]).
Example
:
class B { };
class D : private B { friend class Derived; };
struct Base {
  virtual void vf1();
  virtual void vf2();
  virtual void vf3();
  virtual B*   vf4();
  virtual B*   vf5();
  void f();
};

struct No_good : public Base {
  D*  vf4();        // error: B (base class of D) inaccessible
};

class A;
struct Derived : public Base {
    void vf1();     // virtual and overrides Baseโ€‹::โ€‹vf1()
    void vf2(int);  // not virtual, hides Baseโ€‹::โ€‹vf2()
    char vf3();     // error: invalid difference in return type only
    D*   vf4();     // OK: returns pointer to derived class
    A*   vf5();     // error: returns pointer to incomplete class
    void f();
};

void g() {
  Derived d;
  Base* bp = &d;                // standard conversion:
                                // Derived* to Base*
  bp->vf1();                    // calls Derivedโ€‹::โ€‹vf1()
  bp->vf2();                    // calls Baseโ€‹::โ€‹vf2()
  bp->f();                      // calls Baseโ€‹::โ€‹f() (not virtual)
  B*  p = bp->vf4();            // calls Derivedโ€‹::โ€‹vf4() and converts the
                                // result to B*
  Derived*  dp = &d;
  D*  q = dp->vf4();            // calls Derivedโ€‹::โ€‹vf4() and does not
                                // convert the result to B*
  dp->vf2();                    // error: argument mismatch
}
โ€” end example
 ]
Note
:
The interpretation of the call of a virtual function depends on the type of the object for which it is called (the dynamic type), whereas the interpretation of a call of a non-virtual member function depends only on the type of the pointer or reference denoting that object (the static type) ([expr.call]).
โ€” end note
 ]
Note
:
The virtual specifier implies membership, so a virtual function cannot be a non-member ([dcl.fct.spec]) function.
Nor can a virtual function be a static member, since a virtual function call relies on a specific object for determining which function to invoke.
A virtual function declared in one class can be declared a friend ([class.friend]) in another class.
โ€” end note
 ]
A virtual function declared in a class shall be defined, or declared pure ([class.abstract]) in that class, or both; no diagnostic is required ([basic.def.odr]).
Example
:
Here are some uses of virtual functions with multiple base classes:
struct A {
  virtual void f();
};

struct B1 : A {                 // note non-virtual derivation
  void f();
};

struct B2 : A {
  void f();
};

struct D : B1, B2 {             // D has two separate A subobjects
};

void foo() {
  D   d;
//   A*  ap = &d;                  // would be ill-formed: ambiguous
  B1*  b1p = &d;
  A*   ap = b1p;
  D*   dp = &d;
  ap->f();                      // calls Dโ€‹::โ€‹B1โ€‹::โ€‹f
  dp->f();                      // error: ambiguous
}
In class D above there are two occurrences of class A and hence two occurrences of the virtual member function Aโ€‹::โ€‹f.
The final overrider of B1โ€‹::โ€‹Aโ€‹::โ€‹f is B1โ€‹::โ€‹f and the final overrider of B2โ€‹::โ€‹Aโ€‹::โ€‹f is B2โ€‹::โ€‹f.
โ€” end example
 ]
Example
:
The following example shows a function that does not have a unique final overrider:
struct A {
  virtual void f();
};

struct VB1 : virtual A {        // note virtual derivation
  void f();
};

struct VB2 : virtual A {
  void f();
};

struct Error : VB1, VB2 {       // error
};

struct Okay : VB1, VB2 {
  void f();
};
Both VB1โ€‹::โ€‹f and VB2โ€‹::โ€‹f override Aโ€‹::โ€‹f but there is no overrider of both of them in class Error.
This example is therefore ill-formed.
Class Okay is well-formed, however, because Okayโ€‹::โ€‹f is a final overrider.
โ€” end example
 ]
Example
:
The following example uses the well-formed classes from above.
struct VB1a : virtual A {       // does not declare f
};

struct Da : VB1a, VB2 {
};

void foe() {
  VB1a*  vb1ap = new Da;
  vb1ap->f();                   // calls VB2โ€‹::โ€‹f
}
โ€” end example
 ]
Explicit qualification with the scope operator ([expr.prim.id.qual]) suppresses the virtual call mechanism.
Example
:
class B { public: virtual void f(); };
class D : public B { public: void f(); };

void D::f() { /* ... */ B::f(); }
Here, the function call in Dโ€‹::โ€‹f really does call Bโ€‹::โ€‹f and not Dโ€‹::โ€‹f.
โ€” end example
 ]
A function with a deleted definition ([dcl.fct.def]) shall not override a function that does not have a deleted definition.
Likewise, a function that does not have a deleted definition shall not override a function with a deleted definition.
A consteval virtual function shall not override a virtual function that is not consteval.
A consteval virtual function shall not be overridden by a virtual function that is not consteval.
The use of the virtual specifier in the declaration of an overriding function is valid but redundant (has empty semantics).
โฎฅ
If all virtual functions are immediate functions, the class is still polymorphic even though its internal representation might not otherwise require any additions for that polymorphic behavior.
โฎฅ
A function with the same name but a different parameter list ([over]) as a virtual function is not necessarily virtual and does not override.
Access control ([class.access]) is not considered in determining overriding.
โฎฅ
Multi-level pointers to classes or references to multi-level pointers to classes are not allowed.
โฎฅ