Init
This commit is contained in:
332
cppdraft/class/virtual.md
Normal file
332
cppdraft/class/virtual.md
Normal file
@@ -0,0 +1,332 @@
|
||||
[class.virtual]
|
||||
|
||||
# 11 Classes [[class]](./#class)
|
||||
|
||||
## 11.7 Derived classes [[class.derived]](class.derived#class.virtual)
|
||||
|
||||
### 11.7.3 Virtual functions [class.virtual]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3830)
|
||||
|
||||
A non-static member function is a [*virtual function*](#def:function,virtual "11.7.3 Virtual functions [class.virtual]") if it is first declared with the keyword virtual or
|
||||
if it overrides a virtual member function declared in a base class
|
||||
(see below)[.](#1.sentence-1)[92](#footnote-92 "The use of the virtual specifier in the declaration of an overriding function is valid but redundant (has empty semantics).")
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Virtual functions support dynamic binding and object-oriented
|
||||
programming[.](#1.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
A class with a virtual member function is called a [*polymorphic class*](#def:class,polymorphic "11.7.3 Virtual functions [class.virtual]")[.](#1.sentence-3)[93](#footnote-93 "If all virtual functions are immediate functions, the class is still polymorphic even if its internal representation does not otherwise require any additions for that polymorphic behavior.")
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3853)
|
||||
|
||||
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 G corresponds ([[basic.scope.scope]](basic.scope.scope "6.4.1 General")) to a declaration of F,
|
||||
ignoring trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]")*s*,
|
||||
then G [*overrides*](#def:function,virtual,override "11.7.3 Virtual functions [class.virtual]")[94](#footnote-94 "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.")F[.](#2.sentence-1)
|
||||
|
||||
For convenience, we say that any virtual function overrides itself[.](#2.sentence-2)
|
||||
|
||||
A virtual member function V of a class object S is a [*final
|
||||
overrider*](#def:final_overrider "11.7.3 Virtual functions [class.virtual]") unless the most derived class ([[intro.object]](intro.object "6.8.2 Object model")) of which S is a
|
||||
base class subobject (if any) has another member function that overrides V[.](#2.sentence-3)
|
||||
|
||||
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[.](#2.sentence-4)
|
||||
|
||||
[*Example [1](#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(); // calls B::f, the final overrider c.C::f(); // calls A::f because of the using-declaration} â *end example*]
|
||||
|
||||
[*Example [2](#example-2)*: 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*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3906)
|
||||
|
||||
[*Note [2](#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[.](#3.sentence-1)
|
||||
|
||||
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[.](#3.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3930)
|
||||
|
||||
If a virtual function f in some class B is marked with the[*virt-specifier*](class.mem.general#nt:virt-specifier "11.4.1 General [class.mem.general]") final and in a class D derived from B a function D::f overrides B::f, the program is ill-formed[.](#4.sentence-1)
|
||||
|
||||
[*Example [3](#example-3)*: struct B {virtual void f() const final;};
|
||||
|
||||
struct D : B {void f() const; // error: D::f attempts to override final B::f}; â *end example*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3946)
|
||||
|
||||
If a virtual function is marked with the [*virt-specifier*](class.mem.general#nt:virt-specifier "11.4.1 General [class.mem.general]") override and
|
||||
does not override a member function of a base class, the program is ill-formed[.](#5.sentence-1)
|
||||
|
||||
[*Example [4](#example-4)*: struct B {virtual void f(int);};
|
||||
|
||||
struct D : B {virtual void f(long) override; // error: wrong signature overriding B::fvirtual void f(int) override; // OK}; â *end example*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3962)
|
||||
|
||||
A virtual function shall not have a trailing [*requires-clause*](temp.pre#nt:requires-clause "13.1 Preamble [temp.pre]") ([[dcl.decl]](dcl.decl "9.3 Declarators"))[.](#6.sentence-1)
|
||||
|
||||
[*Example [5](#example-5)*: template<typename T>struct A {virtual void f() requires true; // error: virtual function cannot be constrained ([[temp.constr.decl]](temp.constr.decl "13.5.3 Constrained declarations"))}; â *end example*]
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3973)
|
||||
|
||||
The [*ref-qualifier*](dcl.decl.general#nt:ref-qualifier "9.3.1 General [dcl.decl.general]"), or lack thereof, of an overriding function
|
||||
shall be the same as that of the overridden function[.](#7.sentence-1)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L3977)
|
||||
|
||||
The return type of an overriding function shall be either identical to
|
||||
the return type of the overridden function or [*covariant*](#def:return_type,covariant "11.7.3 Virtual functions [class.virtual]") with
|
||||
the classes of the functions[.](#8.sentence-1)
|
||||
|
||||
If a function D::f overrides a
|
||||
function B::f, the return types of the functions are covariant
|
||||
if they satisfy the following criteria:
|
||||
|
||||
- [(8.1)](#8.1)
|
||||
|
||||
both are pointers to classes, both are lvalue references to
|
||||
classes, or both are rvalue references to classes[95](#footnote-95 "Multi-level pointers to classes or references to multi-level pointers to classes are not allowed.")
|
||||
|
||||
- [(8.2)](#8.2)
|
||||
|
||||
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
|
||||
|
||||
- [(8.3)](#8.3)
|
||||
|
||||
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[.](#8.sentence-2)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4002)
|
||||
|
||||
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]](basic.scope.pdecl "6.4.2 Point of declaration")) of the overriding declaration or shall be the
|
||||
class type D[.](#9.sentence-1)
|
||||
|
||||
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]](expr.call "7.6.1.3 Function call"))[.](#9.sentence-2)
|
||||
|
||||
[*Example [6](#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(); // 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 classvoid 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*]
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4054)
|
||||
|
||||
[*Note [3](#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]](expr.call "7.6.1.3 Function call"))[.](#10.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4063)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
The virtual specifier implies membership, so a virtual function
|
||||
cannot be a non-member ([[dcl.fct.spec]](dcl.fct.spec "9.2.3 Function specifiers")) function[.](#11.sentence-1)
|
||||
|
||||
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[.](#11.sentence-2)
|
||||
|
||||
A virtual
|
||||
function declared in one class can be declared a friend ([[class.friend]](class.friend "11.8.4 Friends")) in
|
||||
another class[.](#11.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4073)
|
||||
|
||||
A virtual function declared in a class shall be defined, or declared
|
||||
pure ([[class.abstract]](class.abstract "11.7.4 Abstract classes")) in that class, or both; no diagnostic is
|
||||
required ([[basic.def.odr]](basic.def.odr "6.3 One-definition rule"))[.](#12.sentence-1)
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4080)
|
||||
|
||||
[*Example [7](#example-7)*:
|
||||
|
||||
Here are some uses of virtual functions with multiple base classes:struct A {virtual void f();};
|
||||
|
||||
struct B1 : A { // note non-virtual derivationvoid 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[.](#13.sentence-2)
|
||||
|
||||
The final overrider of B1::A::f is B1::f and the final
|
||||
overrider of B2::A::f is B2::f[.](#13.sentence-3)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4116)
|
||||
|
||||
[*Example [8](#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 { // note virtual derivationvoid 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[.](#14.sentence-2)
|
||||
|
||||
This example is
|
||||
therefore ill-formed[.](#14.sentence-3)
|
||||
|
||||
Class Okay is well-formed, however,
|
||||
because Okay::f is a final overrider[.](#14.sentence-4)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4146)
|
||||
|
||||
[*Example [9](#example-9)*:
|
||||
|
||||
The following example uses the well-formed classes from above[.](#15.sentence-1)
|
||||
|
||||
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*]
|
||||
|
||||
[16](#16)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4163)
|
||||
|
||||
Explicit qualification with the scope operator ([[expr.prim.id.qual]](expr.prim.id.qual "7.5.5.3 Qualified names"))
|
||||
suppresses the virtual call mechanism[.](#16.sentence-1)
|
||||
|
||||
[*Example [10](#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::f really does callB::f and notD::f[.](#16.sentence-2)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[17](#17)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4184)
|
||||
|
||||
A deleted function ([[dcl.fct.def]](dcl.fct.def "9.6 Function definitions")) shall
|
||||
not override a function that is not deleted[.](#17.sentence-1)
|
||||
|
||||
Likewise,
|
||||
a function that is not deleted shall not override a
|
||||
deleted function[.](#17.sentence-2)
|
||||
|
||||
[18](#18)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/classes.tex#L4191)
|
||||
|
||||
A consteval virtual function shall not override
|
||||
a virtual function that is not consteval[.](#18.sentence-1)
|
||||
|
||||
A consteval virtual function shall not be overridden by
|
||||
a virtual function that is not consteval[.](#18.sentence-2)
|
||||
|
||||
[92)](#footnote-92)[92)](#footnoteref-92)
|
||||
|
||||
The use of the virtual specifier in the
|
||||
declaration of an overriding function is valid but redundant (has empty
|
||||
semantics)[.](#footnote-92.sentence-1)
|
||||
|
||||
[93)](#footnote-93)[93)](#footnoteref-93)
|
||||
|
||||
If
|
||||
all virtual functions are immediate functions,
|
||||
the class is still polymorphic even if
|
||||
its internal representation does not otherwise require
|
||||
any additions for that polymorphic behavior[.](#footnote-93.sentence-1)
|
||||
|
||||
[94)](#footnote-94)[94)](#footnoteref-94)
|
||||
|
||||
A function
|
||||
with the same name but a different parameter list ([[over]](over "12 Overloading"))
|
||||
as a virtual function is not necessarily virtual and
|
||||
does not override[.](#footnote-94.sentence-1)
|
||||
|
||||
Access control ([[class.access]](class.access "11.8 Member access control")) is not considered in
|
||||
determining overriding[.](#footnote-94.sentence-2)
|
||||
|
||||
[95)](#footnote-95)[95)](#footnoteref-95)
|
||||
|
||||
Multi-level pointers to classes or references to multi-level pointers to
|
||||
classes are not allowed[.](#footnote-95.sentence-1)
|
||||
Reference in New Issue
Block a user