[class.derived] (original) (raw)

11 Classes [class]

11.7 Derived classes [class.derived]

11.7.1 General [class.derived.general]

A list of base classes can be specified in a class definition using the notation:

access-specifier:
private
protected
public

A class-or-decltype shall denote a (possibly cv-qualified) class type that is not an incompletely defined class ([class.mem]); any cv-qualifiers are ignored.

The class denoted by the class-or-decltype of a base-specifier is called adirect base classfor the class being defined.

A class B is a base class of a class D if it is a direct base class ofD 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.

Members of a base class are also members of the derived class.

[Note 2:

Constructors of a base class can be explicitly inherited ([namespace.udecl]).

Base class 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]).

The scope resolution operator ​::​ ([expr.prim.id.qual]) can be used to refer to a direct or indirect base member explicitly, even if it is hidden 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 thebase class subobjects contained in an object of the derived class type.

[Example 1: 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 classDerived which in turn will have a subobject of classBase.

— _end example_]

The order in which the base class subobjects are allocated in the most derived object ([intro.object]) is unspecified.

[Note 3:

A derived class and its base class subobjects can be represented by a directed acyclic graph (DAG) where an arrow means “directly derived from” (see Figure 3).

An arrow need not have a physical representation in memory.

A DAG of subobjects is often referred to as a “subobject lattice”.

— _end note_]

dag Base Base Derived1 Derived1 Derived1->Base Derived2 Derived2 Derived2->Derived1

Figure 3: Directed acyclic graph [fig:class.dag]

[Note 4:

Initialization of objects representing base classes can be specified in constructors; see [class.base.init].

— _end note_]

[Note 5:

A base class subobject can have a layout different from the layout of a most derived object of the same type.

A base class subobject can have a polymorphic behavior ([class.cdtor]) different from the polymorphic behavior of a most derived object of the same type.

A base class subobject can be of zero size; however, two subobjects that have the same class type and that belong to the same most derived object cannot be allocated at the same address ([intro.object]).

— _end note_]

11.7.2 Multiple base classes [class.mi]

A class can be derived from any number of base classes.

[Note 1:

The use of more than one direct base class is often called multiple inheritance.

— _end note_]

[Example 1: class A { };class B { };class C { };class D : public A, public B, public C { }; — _end example_]

A class shall not be specified as a direct base class of a derived class more than once.

[Note 3:

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; lookup that finds its non-static data members and member functions in the scope of the derived class will be ambiguous.

However, the static members, enumerations and types can be unambiguously referred to.

— _end note_]

[Example 2: class X { };class Y : public X, public X { }; class L { public: int next; };class A : public L { };class B : public L { };class C : public A, public B { void f(); }; class D : public A, public L { void f(); }; — _end example_]

A base class specifier that does not contain the keywordvirtual specifies a non-virtual base class.

A base class specifier that contains the keyword virtual specifies avirtual 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.

[Note 4:

For an object of class type C, each distinct occurrence of a (non-virtual) base class L in the class lattice of Ccorresponds 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 in Figure 4.

nonvirt L1 L L2 L A A A->L1 B B B->L2 C C C->A C->B

Figure 4: Non-virtual base [fig:class.nonvirt]

In such lattices, explicit qualification can be used to specify which subobject is meant.

The body of function C​::​f can refer to the member next of each L subobject:void C::f() { A::next = B::next; }

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

— _end note_]

[Note 5:

In contrast, consider the case with a virtual base class: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 class subobject of c that has avirtual base class of type V.

Given the class Cdefined above, an object of class C will have one subobject of class V, as shown in Figure 5.

— _end note_]

[Note 6:

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 distinctB 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 in Figure 6.

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 6: Virtual and non-virtual base [fig:class.virtnonvirt]

— _end note_]

11.7.3 Virtual functions [class.virtual]

A non-static member function is a virtual functionif it is first declared with the keyword virtual or if it overrides a virtual member function declared in a base class (see below).93

[Note 1:

Virtual functions support dynamic binding and object-oriented programming.

— _end note_]

A class with a virtual member function is called a polymorphic class.94

If a virtual member function F is declared in a class B, and, in a class D derived (directly or indirectly) from B, a declaration of a member function Gcorresponds ([basic.scope.scope]) to a declaration of F, ignoring trailing requires-clauses, then G overrides95 F.

For convenience, we say that any virtual function overrides itself.

A virtual member function V 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) has another member function that overrides V.

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 1: 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(); c.C::f(); } — _end example_]

[Example 2: struct A { virtual void f(); };struct B : A { };struct C : A { void f(); };struct D : B, C { }; — _end example_]

[Note 2:

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 classD2 has the same name and the same parameter list asB​::​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 thevirt-specifier final and in a class D derived from Ba function D​::​f overrides B​::​f, the program is ill-formed.

[Example 3: struct B { virtual void f() const final;};struct D : B { void f() const; }; — _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 4: struct B { virtual void f(int);};struct D : B { virtual void f(long) override; virtual void f(int) override; }; — _end example_]

[Example 5: template<typename T> struct A { virtual void f() requires true; }; — _end example_]

The ref-qualifier, or lack thereof, of an overriding function shall be the same as that of the overridden function.

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:

If the class type in the covariant return type of D​::​f differs from that ofB​::​f, the class type in the return type of D​::​f shall be complete at the locus ([basic.scope.pdecl]) of the overriding declaration 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 6: 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(); };class A;struct Derived : public Base { void vf1(); void vf2(int); char vf3(); D* vf4(); A* vf5(); void f();};void g() { Derived d; Base* bp = &d; bp->vf1(); bp->vf2(); bp->f(); B* p = bp->vf4(); Derived* dp = &d; D* q = dp->vf4(); dp->vf2(); } — _end example_]

[Note 3:

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 4:

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 7:

Here are some uses of virtual functions with multiple base classes:struct A { virtual void f();};struct B1 : A { void f();};struct B2 : A { void f();};struct D : B1, B2 { };void foo() { D d; B1* b1p = &d; A* ap = b1p; D* dp = &d; ap->f(); dp->f(); }

In class D above there are two occurrences of class Aand 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 8:

The following example shows a function that does not have a unique final overrider:struct A { virtual void f();};struct VB1 : virtual A { void f();};struct VB2 : virtual A { void f();};struct Error : VB1, VB2 { };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 9:

The following example uses the well-formed classes from above.

struct VB1a : virtual A { };struct Da : VB1a, VB2 { };void foe() { VB1a* vb1ap = new Da; vb1ap->f(); } — _end example_]

Explicit qualification with the scope operator ([expr.prim.id.qual]) suppresses the virtual call mechanism.

[Example 10: class B { public: virtual void f(); };class D : public B { public: void f(); };void D::f() { B::f(); }

Here, the function call inD​::​freally does callB​::​fand notD​::​f.

— _end example_]

A deleted function ([dcl.fct.def]) shall not override a function that is not deleted.

Likewise, a function that is not deleted shall not override a deleted function.

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.

11.7.4 Abstract classes [class.abstract]

[Note 1:

The abstract class mechanism supports the notion of a general concept, such as a shape, of which only more concrete variants, such ascircle 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.

— _end note_]

A virtual function is specified as a pure virtual function by using apure-specifier ([class.mem]) in the function declaration in the class definition.

[Note 2:

Such a function might be inherited: see below.

— _end note_]

A class is an abstract classif it has at least one pure virtual function.

[Note 3:

An abstract class 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 ([basic.def], [class.mem]).

— _end note_]

[Example 1: class point { };class shape { point center;public: point where() { return center; } void move(point p) { center=p; draw(); } virtual void rotate(int) = 0; virtual void draw() = 0; }; — _end example_]

[Note 4:

A function declaration cannot provide both a pure-specifierand a definition.

— _end note_]

[Example 2: struct C { virtual void f() = 0 { }; }; — _end example_]

[Note 5:

An abstract class type cannot be used as a parameter or return type of a function being defined ([dcl.fct]) or called ([expr.call]), except as specified in [dcl.type.simple].

However, pointers and references to abstract class types can appear in such contexts.

— _end note_]

A class is abstract if it has at least one pure virtual function for which the final overrider is pure virtual.

[Example 3: class ab_circle : public shape { int radius;public: void rotate(int) { } };

Since shape​::​draw() is a pure virtual functionab_circle​::​draw() is a pure virtual by default.

The alternative declaration,class circle : public shape { int radius;public: void rotate(int) { } void draw(); };would make class circle non-abstract and a definition ofcircle​::​draw() must be provided.

— _end example_]

[Note 6:

An abstract class can be derived from a class that is not abstract, and a pure virtual function can 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.