6.3. Inheritance
-
CoreCpp.Typing.compat[complete] -
CoreCpp.Typing.related[complete] -
CoreCpp.Program.subclass[complete]
A pointer to a derived class is accepted where a pointer to its base is expected, in declarations, assignments, arguments, returns, comparisons and the branches of ?:. It is the only conversion between class types, and the other direction is a type error.
\dfrac{D \text{ derives from } B}{D* \approx B*}\;\textsf{(Subsumption)}
Lean code for Definition6.3.1●3 definitions
Associated Lean declarations
-
CoreCpp.Typing.compat[complete]
-
CoreCpp.Typing.related[complete]
-
CoreCpp.Program.subclass[complete]
-
CoreCpp.Typing.compat[complete] -
CoreCpp.Typing.related[complete] -
CoreCpp.Program.subclass[complete]
-
defdefined in CoreCpp/Typing.leancomplete
def CoreCpp.Typing.compat (p : CoreCpp.Program) : CoreCpp.Ty → CoreCpp.Ty → Bool
def CoreCpp.Typing.compat (p : CoreCpp.Program) : CoreCpp.Ty → CoreCpp.Ty → Bool
τ ≈ τ', the type τ of a value is accepted where τ' is expected. Equal types, nullptr against a pointer type, or, by subsumption, a pointer to a derived class where a pointer to its base is expected. These and the lambda to `std::function` are the only implicit conversions. ``` D derives from B ──────────────── (Subsumption) D* ≈ B* ``` ``` Γ ⊢ e : D* D derives from B ────────────────────────────── (T-Sub) subsumption where a value is Γ ⊢ e : B* used, wherever ≈ is required ```
-
defdefined in CoreCpp/Syntax.leancomplete
def CoreCpp.Program.subclass (p : CoreCpp.Program) (d c : String) : Bool
def CoreCpp.Program.subclass (p : CoreCpp.Program) (d c : String) : Bool
d is c or derives from c.
-
CoreCpp.Eval.resolve[complete] -
CoreCpp.Program.findMethod[complete] -
CoreCpp.Typing.cls[complete]
A virtual method is chosen by the class tag T of the receiver, the nearest declaration in the chain of T, so a call through a base pointer reaches the override of the derived class. A non virtual method is chosen by the static class S.
A derived class redefines only a method the base declares virtual, and marks it override, so the method reached from S and the one reached from T coincide for every non virtual method.
Redefining a non virtual method, marking override without a virtual method in a base, or changing the signature is a type error.
Some of the implementations are partial, so Lean records opaque constants that carry the type and not the body, and no property of them is proved here.
Lean code for Definition6.3.2●3 definitions
Associated Lean declarations
-
CoreCpp.Eval.resolve[complete]
-
CoreCpp.Program.findMethod[complete]
-
CoreCpp.Typing.cls[complete]
-
CoreCpp.Eval.resolve[complete] -
CoreCpp.Program.findMethod[complete] -
CoreCpp.Typing.cls[complete]
-
defdefined in CoreCpp/Eval.leancomplete
def CoreCpp.Eval.resolve (fs : CoreCpp.FunEnv) (s t m : String) (sig : Option (List CoreCpp.Ty)) : CoreCpp.M (CoreCpp.Method × String)
def CoreCpp.Eval.resolve (fs : CoreCpp.FunEnv) (s t m : String) (sig : Option (List CoreCpp.Ty)) : CoreCpp.M (CoreCpp.Method × String)
The method m of class s with the signature the type checker chose, the nearest in the chain of s, dispatched by the tag t when that method is virtual. The signature picks one member of an overload set, and without it, in an unannotated program, the first of the name serves.
-
defdefined in CoreCpp/Syntax.leancomplete
def CoreCpp.Program.findMethod (p : CoreCpp.Program) (c m : String) : Option (CoreCpp.Method × String)
def CoreCpp.Program.findMethod (p : CoreCpp.Program) (c m : String) : Option (CoreCpp.Method × String)
The method m as seen from class c, the nearest declaration in the chain, with the class that declares it. With m overloaded it is the first of the overload set, and `findMethods` gives them all.
-
defdefined in CoreCpp/Typing.leancomplete
def CoreCpp.Typing.cls (p : CoreCpp.Program) (c : CoreCpp.ClassDecl) : CoreCpp.T Unit
def CoreCpp.Typing.cls (p : CoreCpp.Program) (c : CoreCpp.ClassDecl) : CoreCpp.T Unit
A class is well formed when the conditions below hold. Its base exists and the chain of bases has no cycle. Its fields have types that carry values, are themselves well formed, and repeat no field of a base. Its members have distinct names, and each method redefines only a method the base declares virtual, carrying override and the same signature. The constructor of the base, if the base has one, takes no parameters. Every member body is well typed under `this`. ``` B exists, chain acyclic fields storable, well formed, new in the chain for each method m of C. if some base has m then that m is virtual, m is override and the signatures agree for each override m of C. some base has a virtual m B has no constructor or one with no parameters [this ↦ C*, params] ⊢ body ⊣ Γ' for each member body ──────────────────────────────────────────────────────────────── (T-Class) ⊢ class C : public B { … } ```
For every well typed program, the method a call resolves to by the static class of the receiver and the method it resolves to by the class tag coincide whenever the method is not virtual.
The nearest declaration of a non virtual m from S is also the nearest from T, because no class between T and S redeclares m. There is no Lean proof, the property follows from the rule T-Class by inspection.
-
CoreCpp.Typing.cmd[complete] -
CoreCpp.Eval.cmd[complete] -
CoreCpp.Program.hasVirtualDtor[complete]
The command delete e applies to a pointer to a class or to an object type of the library, whose rule DeleteLib is in Definition 8.1.2.
On an object it runs the destructors of the chain from the tag up to the root, each with this bound to the object, and removes the record and the field locations from \sigma.
A second delete, a delete through a pointer to a base without a virtual destructor in its chain, and any later access are error, the three cases C++17 leaves undefined. delete nullptr does nothing, as in C++.
\dfrac{\Gamma \vdash e : C*}{\Gamma \vdash \mathtt{delete}\ e \dashv \Gamma}\;\textsf{(T-Delete)}
\dfrac{\Gamma \vdash e : L\langle\bar{\tau}\rangle* \qquad L\langle\bar{\tau}\rangle \text{ an object type} \qquad \Gamma \vdash_L \mathtt{delete} : \to \mathsf{void}}{\Gamma \vdash \mathtt{delete}\ e \dashv \Gamma}\;\textsf{(T-DeleteLib)}
\dfrac{\begin{array}{c} \rho, \sigma \vdash e \Rightarrow \mathsf{loc}\,\ell, \sigma_0\qquad \sigma_0(\ell) = \mathsf{obj}\,T\,[f_1 \mapsto \ell_1, \ldots, f_n \mapsto \ell_n] \\ S \text{ the static class of } e\qquad S = T \text{ or the chain of } S \text{ has a virtual destructor} \\ \text{the destructors of the chain of } T \text{ run from } T \text{ up, giving } \sigma_1 \end{array}}{\rho, \sigma \vdash \mathtt{delete}\ e \Rightarrow \mathsf{normal}, \rho, \sigma_1 \setminus \{\ell, \ell_1, \ldots, \ell_n\}}\;\textsf{(Delete)}
\dfrac{\rho, \sigma \vdash e \Rightarrow \mathsf{null}, \sigma_0}{\rho, \sigma \vdash \mathtt{delete}\ e \Rightarrow \mathsf{normal}, \rho, \sigma_0}\;\textsf{(DeleteNull)}
Some of the implementations are partial, so Lean records opaque constants that carry the type and not the body, and no property of them is proved here.
Lean code for Definition6.3.4●3 definitions
Associated Lean declarations
-
CoreCpp.Typing.cmd[complete]
-
CoreCpp.Eval.cmd[complete]
-
CoreCpp.Program.hasVirtualDtor[complete]
-
CoreCpp.Typing.cmd[complete] -
CoreCpp.Eval.cmd[complete] -
CoreCpp.Program.hasVirtualDtor[complete]
-
opaquedefined in CoreCpp/Typing.leancomplete
opaque CoreCpp.Typing.cmd (p : CoreCpp.Program) (τᵣ : CoreCpp.Ty) (Γ : CoreCpp.TEnv) : CoreCpp.Cmd → CoreCpp.T CoreCpp.TEnv
opaque CoreCpp.Typing.cmd (p : CoreCpp.Program) (τᵣ : CoreCpp.Ty) (Γ : CoreCpp.TEnv) : CoreCpp.Cmd → CoreCpp.T CoreCpp.TEnv
Γ ⊢ c ⊣ Γ', under the return type τᵣ of the enclosing function.
-
opaquedefined in CoreCpp/Eval.leancomplete
opaque CoreCpp.Eval.cmd (fs : CoreCpp.FunEnv) (ρ : CoreCpp.Env) (σ : CoreCpp.Store) (c : CoreCpp.Cmd) : CoreCpp.M (CoreCpp.Ctrl × CoreCpp.Env × CoreCpp.Store)
opaque CoreCpp.Eval.cmd (fs : CoreCpp.FunEnv) (ρ : CoreCpp.Env) (σ : CoreCpp.Store) (c : CoreCpp.Cmd) : CoreCpp.M (CoreCpp.Ctrl × CoreCpp.Env × CoreCpp.Store)
ρ, σ ⊢ c ⇒ r, ρ', σ'
-
defdefined in CoreCpp/Syntax.leancomplete
def CoreCpp.Program.hasVirtualDtor (p : CoreCpp.Program) (c : String) : Bool
def CoreCpp.Program.hasVirtualDtor (p : CoreCpp.Program) (c : String) : Bool
Some class in the chain of c declares a virtual destructor, so `delete` through a pointer to c reaches the destructor of the tag.