10 Derived classes [class.derived]

The type denoted by a base-type-specifier shall be a class type that is not an incompletely defined class (Clause [class]); this class is called a direct base class for the class being defined. During the lookup for a base class name, non-type names are ignored ([basic.scope.hiding]). If the name found is not a class-name, the program is ill-formed. A class B is a base class of a class D if it is a direct base class of D or a direct base class of one of D's base classes. A class is an indirect base class of another if it is a base class but not a direct base class. A class is said to be (directly or indirectly) derived from its (direct or indirect) base classes. [ Note: See Clause [class.access] for the meaning of access-specifier.  — end note ] Unless redeclared in the derived class, members of a base class are also considered to be members of the derived class. The base class members are said to be inherited by the derived class. Inherited members can be referred to in expressions in the same manner as other members of the derived class, unless their names are hidden or ambiguous ([class.member.lookup]). Note: The scope resolution operator :: ([expr.prim]) can be used to refer to a direct or indirect base member explicitly. This allows access to a name that has been redeclared in the derived class. A derived class can itself serve as a base class subject to access control; see [class.access.base]. A pointer to a derived class can be implicitly converted to a pointer to an accessible unambiguous base class ([conv.ptr]). An lvalue of a derived class type can be bound to a reference to an accessible unambiguous base class ([dcl.init.ref]).  — end note ]

The base-specifier-list specifies the type of the base class subobjects contained in an object of the derived class type. [ Example:

struct Base {
  int a, b, c;
};
struct Derived : Base {
  int b;
};
struct Derived2 : Derived {
  int c;
};

Here, an object of class Derived2 will have a subobject of class Derived which in turn will have a subobject of class Base.  — end example ]

A base-specifier followed by an ellipsis is a pack expansion ([temp.variadic]).

The order in which the base class subobjects are allocated in the most derived object ([intro.object]) is unspecified. [ Note: a derived class and its base class subobjects can be represented by a directed acyclic graph (DAG) where an arrow means “directly derived from.” A DAG of subobjects is often referred to as a “subobject lattice.”

dag Base Base Derived1 Derived1 Derived1->Base Derived2 Derived2 Derived2->Derived1
Figure 2 — Directed acyclic graph

The arrows need not have a physical representation in memory.  — end note ]

Note: Initialization of objects representing base classes can be specified in constructors; see [class.base.init].  — end note ]

Note: A base class subobject might have a layout ([basic.stc]) different from the layout of a most derived object of the same type. A base class subobject might have a polymorphic behavior ([class.cdtor]) different from the polymorphic behavior of a most derived object of the same type. A base class subobject may be of zero size (Clause [class]); however, two subobjects that have the same class type and that belong to the same most derived object must not be allocated at the same address ([expr.eq]).  — end note ]

10.1 Multiple base classes [class.mi]

A class can be derived from any number of base classes. [ Note: The use of more than one direct base class is often called multiple inheritance.  — end note ] [ Example:

class A { /* ... */ };
class B { /* ... */ };
class C { /* ... */ };
class D : public A, public B, public C { /* ... */ };

 — end example ]

Note: The order of derivation is not significant except as specified by the semantics of initialization by constructor ([class.base.init]), cleanup ([class.dtor]), and storage layout ([class.mem], [class.access.spec]).  — end note ]

A class shall not be specified as a direct base class of a derived class more than once. [ Note: A class can be an indirect base class more than once and can be a direct and an indirect base class. There are limited things that can be done with such a class. The non-static data members and member functions of the direct base class cannot be referred to in the scope of the derived class. However, the static members, enumerations and types can be unambiguously referred to.  — end note ] [ Example:

class X { /* ... */ };
class Y : public X, public X { /* ... */ };             // ill-formed

class L { public: int next;  /* ... */ };
class A : public L { /* ... */ };
class B : public L { /* ... */ };
class C : public A, public B { void f(); /* ... */ };   // well-formed
class D : public A, public L { void f(); /* ... */ };   // well-formed

 — end example ]

A base class specifier that does not contain the keyword virtual, specifies a non-virtual base class. A base class specifier that contains the keyword virtual, specifies a virtual base class. For each distinct occurrence of a non-virtual base class in the class lattice of the most derived class, the most derived object ([intro.object]) shall contain a corresponding distinct base class subobject of that type. For each distinct base class that is specified virtual, the most derived object shall contain a single base class subobject of that type. [ Example: for an object of class type C, each distinct occurrence of a (non-virtual) base class L in the class lattice of C corresponds one-to-one with a distinct L subobject within the object of type C. Given the class C defined above, an object of class C will have two subobjects of class L as shown below.

nonvirt L1 L L2 L A A A->L1 B B B->L2 C C C->A C->B
Figure 3 — Non-virtual base

In such lattices, explicit qualification can be used to specify which subobject is meant. The body of function C::f could refer to the member next of each L subobject:

void C::f() { A::next = B::next; }      // well-formed

Without the A:: or B:: qualifiers, the definition of C::f above would be ill-formed because of ambiguity ([class.member.lookup]).

For another example,

class V { /* ... */ };
class A : virtual public V { /* ... */ };
class B : virtual public V { /* ... */ };
class C : public A, public B { /* ... */ };

for an object c of class type C, a single subobject of type V is shared by every base subobject of c that has a virtual base class of type V. Given the class C defined above, an object of class C will have one subobject of class V, as shown below.

virt V V A A A->V B B B->V C C C->A C->B
Figure 4 — Virtual base

A class can have both virtual and non-virtual base classes of a given type.

class B { /* ... */ };
class X : virtual public B { /* ... */ };
class Y : virtual public B { /* ... */ };
class Z : public B { /* ... */ };
class AA : public X, public Y, public Z { /* ... */ };

For an object of class AA, all virtual occurrences of base class B in the class lattice of AA correspond to a single B subobject within the object of type AA, and every other occurrence of a (non-virtual) base class B in the class lattice of AA corresponds one-to-one with a distinct B subobject within the object of type AA. Given the class AA defined above, class AA has two subobjects of class B: Z's B and the virtual B shared by X and Y, as shown below.

virtnonvirt B1 B B2 B AA AA X X AA->X Y Y AA->Y Z Z AA->Z X->B1 Y->B1 Z->B2
Figure 5 — Virtual and non-virtual base

 — end example ]

10.2 Member name lookup [class.member.lookup]

Member name lookup determines the meaning of a name (id-expression) in a class scope ([basic.scope.class]). Name lookup can result in an ambiguity, in which case the program is ill-formed. For an id-expression, name lookup begins in the class scope of this; for a qualified-id, name lookup begins in the scope of the nested-name-specifier. Name lookup takes place before access control ([basic.lookup], Clause [class.access]).

The following steps define the result of name lookup for a member name f in a class scope C.

The lookup set for f in C, called S(f,C), consists of two component sets: the declaration set, a set of members named f; and the subobject set, a set of subobjects where declarations of these members (possibly including using-declarations) were found. In the declaration set, using-declarations are replaced by the set of designated members that are not hidden or overridden by members of the derived class ([namespace.udecl]), and type declarations (including injected-class-names) are replaced by the types they designate. S(f,C) is calculated as follows:

If C contains a declaration of the name f, the declaration set contains every declaration of f declared in C that satisfies the requirements of the language construct in which the lookup occurs. [ Note: Looking up a name in an elaborated-type-specifier ([basic.lookup.elab]) or base-specifier (Clause [class.derived]), for instance, ignores all non-type declarations, while looking up a name in a nested-name-specifier ([basic.lookup.qual]) ignores function, variable, and enumerator declarations. As another example, looking up a name in a using-declaration ([namespace.udecl]) includes the declaration of a class or enumeration that would ordinarily be hidden by another declaration of that name in the same scope.  — end note ] If the resulting declaration set is not empty, the subobject set contains C itself, and calculation is complete.

Otherwise (i.e., C does not contain a declaration of f or the resulting declaration set is empty), S(f,C) is initially empty. If C has base classes, calculate the lookup set for f in each direct base class subobject Bi, and merge each such lookup set S(f,Bi) in turn into S(f,C).

The following steps define the result of merging lookup set S(f,Bi) into the intermediate S(f,C):

  • If each of the subobject members of S(f,Bi) is a base class subobject of at least one of the subobject members of S(f,C), or if S(f,Bi) is empty, S(f,C) is unchanged and the merge is complete. Conversely, if each of the subobject members of S(f,C) is a base class subobject of at least one of the subobject members of S(f,Bi), or if S(f,C) is empty, the new S(f,C) is a copy of S(f,Bi).

  • Otherwise, if the declaration sets of S(f,Bi) and S(f,C) differ, the merge is ambiguous: the new S(f,C) is a lookup set with an invalid declaration set and the union of the subobject sets. In subsequent merges, an invalid declaration set is considered different from any other.

  • Otherwise, the new S(f,C) is a lookup set with the shared set of declarations and the union of the subobject sets.

The result of name lookup for f in C is the declaration set of S(f,C). If it is an invalid set, the program is ill-formed. [ Example:

struct A { int x; };                    // S(x,A) = { { A::x }, { A } }
struct B { float x; };                  // S(x,B) = { { B::x }, { B } }
struct C: public A, public B { };       // S(x,C) = { invalid, { A in C, B in C } }
struct D: public virtual C { };         // S(x,D) = S(x,C)
struct E: public virtual C { char x; }; // S(x,E) = { { E::x }, { E } }
struct F: public D, public E { };       // S(x,F) = S(x,E)
int main() {
  F f;
  f.x = 0;                              // OK, lookup finds E::x
}

S(x,F) is unambiguous because the A and B base subobjects of D are also base subobjects of E, so S(x,D) is discarded in the first merge step.  — end example ]

If the name of an overloaded function is unambiguously found, overloading resolution ([over.match]) also takes place before access control. Ambiguities can often be resolved by qualifying a name with its class name. [ Example:

struct A {
  int f();
};

struct B {
  int f();
};

struct C : A, B {
  int f() { return A::f() + B::f(); }
};

 — end example ]

Note: A static member, a nested type or an enumerator defined in a base class T can unambiguously be found even if an object has more than one base class subobject of type T. Two base class subobjects share the non-static member subobjects of their common virtual base classes.  — end note ] [ Example:

struct V {
  int v;
};
struct A {
  int a;
  static int   s;
  enum { e };
};
struct B : A, virtual V { };
struct C : A, virtual V { };
struct D : B, C { };

void f(D* pd) {
  pd->v++;          // OK: only one v (virtual)
  pd->s++;          // OK: only one s (static)
  int i = pd->e;    // OK: only one e (enumerator)
  pd->a++;          // error, ambiguous: two as in D
}

 — end example ]

Note: When virtual base classes are used, a hidden declaration can be reached along a path through the subobject lattice that does not pass through the hiding declaration. This is not an ambiguity. The identical use with non-virtual base classes is an ambiguity; in that case there is no unique instance of the name that hides all the others.  — end note ] [ Example:

struct V { int f();  int x; };
struct W { int g();  int y; };
struct B : virtual V, W {
  int f();  int x;
  int g();  int y;
};
struct C : virtual V, W { };

struct D : B, C { void glorp(); };
virt W1 W V V W2 W B B B->W1 B->V C C C->V C->W2 D D D->B D->C
Figure 6 — Name lookup

Note: The names declared in V and the left-hand instance of W are hidden by those in B, but the names declared in the right-hand instance of W are not hidden at all.  — end note ]

void D::glorp() {
  x++;              // OK: B::x hides V::x
  f();              // OK: B::f() hides V::f()
  y++;              // error: B::y and C's W::y
  g();              // error: B::g() and C's W::g()
}

 — end example ]

An explicit or implicit conversion from a pointer to or an expression designating an object of a derived class to a pointer or reference to one of its base classes shall unambiguously refer to a unique object representing the base class. [ Example:

struct V { };
struct A { };
struct B : A, virtual V { };
struct C : A, virtual V { };
struct D : B, C { };

void g() {
  D d;
  B* pb = &d;
  A* pa = &d;       // error, ambiguous: C's A or B's A?
  V* pv = &d;       // OK: only one V subobject
}

 — end example ]

Note: Even if the result of name lookup is unambiguous, use of a name found in multiple subobjects might still be ambiguous ([conv.mem], [expr.ref], [class.access.base]). — end note ] [ Example:

struct B1 {
  void f();
  static void f(int);
  int i;
};
struct B2 {
  void f(double);
};
struct I1: B1 { };
struct I2: B1 { };

struct D: I1, I2, B2 {
  using B1::f;
  using B2::f;
  void g() {
    f();                        // Ambiguous conversion of this
    f(0);                       // Unambiguous (static)
    f(0.0);                     // Unambiguous (only one B2)
    int B1::* mpB1 = &D::i;     // Unambiguous
    int D::* mpD = &D::i;       // Ambiguous conversion
  }
};

 — end example ]

10.3 Virtual functions [class.virtual]

Virtual functions support dynamic binding and object-oriented programming. A class that declares or inherits a virtual function is called a polymorphic class.

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 is also virtual (whether or not it is so declared) and it overrides112 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 ]

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 classes113

  • 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::pf() and converts the
                                // result to B*
  Derived*  dp = &d;
  D*  q = dp->vf4();            // calls Derived::pf() and does not
                                // convert the result to B*
  dp->vf2();                    // ill-formed: 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 nonmember ([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 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; but 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();                      // ill-formed: 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.

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 {       // ill-formed
};

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.

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]) 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 function with the same name but a different parameter list (Clause [over]) as a virtual function is not necessarily virtual and does not override. The use of the virtual specifier in the declaration of an overriding function is legal but redundant (has empty semantics). Access control (Clause [class.access]) is not considered in determining overriding.

Multi-level pointers to classes or references to multi-level pointers to classes are not allowed.

10.4 Abstract classes [class.abstract]

The abstract class mechanism supports the notion of a general concept, such as a shape, of which only more concrete variants, such as circle and square, can actually be used. An abstract class can also be used to define an interface for which derived classes provide a variety of implementations.

An abstract class is a class that can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it. A class is abstract if it has at least one pure virtual function. [ Note: Such a function might be inherited: see below.  — end note ] A virtual function is specified pure by using a pure-specifier ([class.mem]) in the function declaration in the class definition. A pure virtual function need be defined only if called with, or as if with ([class.dtor]), the qualified-id syntax ([expr.prim]). [ Example:

class point { /* ... */ };
class shape {                   // abstract class
  point center;
public:
  point where() { return center; }
  void move(point p) { center=p; draw(); }
  virtual void rotate(int) = 0; // pure virtual
  virtual void draw() = 0;      // pure virtual
};

 — end example ] [ Note: A function declaration cannot provide both a pure-specifier and a definition  — end note ] [ Example:

struct C {
  virtual void f() = 0 { };     // ill-formed
};

 — end example ]

An abstract class shall not be used as a parameter type, as a function return type, or as the type of an explicit conversion. Pointers and references to an abstract class can be declared. [ Example:

shape x;                        // error: object of abstract class
shape* p;                       // OK
shape f();                      // error
void g(shape);                  // error
shape& h(shape&);               // OK

 — end example ]

A class is abstract if it contains or inherits at least one pure virtual function for which the final overrider is pure virtual. [ Example:

class ab_circle : public shape {
  int radius;
public:
  void rotate(int) { }
  // ab_circle::draw() is a pure virtual
};

Since shape::draw() is a pure virtual function ab_circle::draw() is a pure virtual by default. The alternative declaration,

class circle : public shape {
  int radius;
public:
  void rotate(int) { }
  void draw();                  // a definition is required somewhere
};

would make class circle nonabstract and a definition of circle::draw() must be provided.  — end example ]

Note: An abstract class can be derived from a class that is not abstract, and a pure virtual function may override a virtual function which is not pure.  — end note ]

Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call ([class.virtual]) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined.