11 Classes [class]

11.4 Class members [class.mem]

11.4.1 General [class.mem.general]

virt-specifier:
override
final
In the absence of a virt-specifier-seq, the token sequence = 0 is treated as a pure-specifier if the type of the declarator-id ([dcl.meaning.general]) is a function type, and is otherwise treated as a brace-or-equal-initializer.
[Note 1: 
If the member declaration acquires a function type through template instantiation, the program is ill-formed; see [temp.spec.general].
— end note]
The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere.
A direct member of a class X is a member of X that was first declared within the member-specification of X, including anonymous union members ([class.union.anon]) and direct members thereof.
Members of a class are data members, member functions ([class.mfct]), nested types, enumerators, and member templates ([temp.mem]) and specializations thereof.
[Note 2: 
A specialization of a static data member template is a static data member.
A specialization of a member function template is a member function.
A specialization of a member class template is a nested class.
— end note]
For any other member-declaration, each declared entity that is not an unnamed bit-field is a member of the class, and each such member-declaration shall either declare at least one member name of the class or declare at least one unnamed bit-field.
A data member is a non-function member introduced by a member-declarator.
A member function is a member that is a function.
Nested types are classes ([class.name], [class.nest]) and enumerations ([dcl.enum]) declared in the class and arbitrary types declared as members by use of a typedef declaration ([dcl.typedef]) or alias-declaration.
The enumerators of an unscoped enumeration defined in the class are members of the class.
A data member or member function may be declared static in its member-declaration, in which case it is a static member (see [class.static]) (a static data member ([class.static.data]) or static member function ([class.static.mfct]), respectively) of the class.
Any other data member or member function is a non-static member (a non-static data member or non-static member function ([class.mfct.non.static]), respectively).
[Note 3: 
A non-static data member of non-reference type is a member subobject of a class object.
— end note]
A member shall not be declared twice in the member-specification, except that
[Note 4: 
A single name can denote several member functions provided their types are sufficiently different ([basic.scope.scope]).
— end note]
A redeclaration of a class member outside its class definition shall be a definition, an explicit specialization, or an explicit instantiation ([temp.expl.spec], [temp.explicit]).
The member shall not be a non-static data member.
A complete-class context of a class (template) is a within the member-specification of the class or class template.
[Note 5: 
A complete-class context of a nested class is also a complete-class context of any enclosing class, if the nested class is defined within the member-specification of the enclosing class.
— end note]
A class C is complete at a program point P if the definition of C is reachable from P ([module.reach]) or if P is in a complete-class context of C.
Otherwise, C is incomplete at P.
If a member-declaration matches the syntactic requirements of friend-type-declaration, it is a friend-type-declaration.
In a member-declarator, an = immediately following the declarator is interpreted as introducing a pure-specifier if the declarator-id has function type, otherwise it is interpreted as introducing a brace-or-equal-initializer.
[Example 1: struct S { using T = void(); T * p = 0; // OK, brace-or-equal-initializer virtual T f = 0; // OK, pure-specifier }; — end example]
In a member-declarator for a bit-field, the constant-expression is parsed as the longest sequence of tokens that could syntactically form a constant-expression.
[Example 2: int a; const int b = 0; struct S { int x1 : 8 = 42; // OK, "= 42" is brace-or-equal-initializer int x2 : 8 { 42 }; // OK, "{ 42 }" is brace-or-equal-initializer int y1 : true ? 8 : a = 42; // OK, brace-or-equal-initializer is absent int y2 : true ? 8 : b = 42; // error: cannot assign to const int int y3 : (true ? 8 : b) = 42; // OK, "= 42" is brace-or-equal-initializer int z : 1 || new int { 0 }; // OK, brace-or-equal-initializer is absent }; — end example]
A brace-or-equal-initializer shall appear only in the declaration of a data member.
(For static data members, see [class.static.data]; for non-static data members, see [class.base.init] and [dcl.init.aggr]).
A brace-or-equal-initializer for a non-static data member specifies a default member initializer for the member, and shall not directly or indirectly cause the implicit definition of a defaulted default constructor for the enclosing class or the exception specification of that constructor.
An immediate invocation ([expr.const]) that is a potentially-evaluated subexpression ([intro.execution]) of a default member initializer is neither evaluated nor checked for whether it is a constant expression at the point where the subexpression appears.
A member shall not be declared with the extern storage-class-specifier.
Within a class definition, a member shall not be declared with the thread_local storage-class-specifier unless also declared static.
The decl-specifier-seq may be omitted in constructor, destructor, and conversion function declarations only; when declaring another kind of member the decl-specifier-seq shall contain a type-specifier that is not a cv-qualifier.
The member-declarator-list can be omitted only after a class-specifier or an enum-specifier or in a friend declaration.
A pure-specifier shall be used only in the declaration of a virtual function that is not a friend declaration.
The optional attribute-specifier-seq in a member-declaration appertains to each of the entities declared by the member-declarators; it shall not appear if the optional member-declarator-list is omitted.
A virt-specifier-seq shall contain at most one of each virt-specifier.
A virt-specifier-seq shall appear only in the first declaration of a virtual member function ([class.virtual]).
The type of a non-static data member shall not be an incomplete type ([basic.types.general]), an abstract class type ([class.abstract]), or a (possibly multidimensional) array thereof.
[Note 6: 
In particular, a class C cannot contain a non-static member of class C, but it can contain a pointer or reference to an object of class C.
— end note]
[Note 7: 
See [expr.prim.id] for restrictions on the use of non-static data members and non-static member functions.
— end note]
[Note 8: 
The type of a non-static member function is an ordinary function type, and the type of a non-static data member is an ordinary object type.
There are no special member function types or data member types.
— end note]
[Example 3: 
A simple example of a class definition is struct tnode { char tword[20]; int count; tnode* left; tnode* right; }; which contains an array of twenty characters, an integer, and two pointers to objects of the same type.
Once this definition has been given, the declaration tnode s, *sp; declares s to be a tnode and sp to be a pointer to a tnode.
With these declarations, sp->count refers to the count member of the object to which sp points; s.left refers to the left subtree pointer of the object s; and s.right->tword[0] refers to the initial character of the tword member of the right subtree of s.
— end example]
[Note 9: 
Non-variant non-static data members of non-zero size ([intro.object]) are allocated so that later members have higher addresses within a class object ([expr.rel]).
Implementation alignment requirements can cause two adjacent members not to be allocated immediately after each other; so can requirements for space for managing virtual functions ([class.virtual]) and virtual base classes ([class.mi]).
— end note]
If T is the name of a class, then each of the following shall have a name different from T:
  • every static data member of class T;
  • every member function of class T;
    [Note 10: 
    This restriction does not apply to constructors, which do not have names ([class.ctor]).
    — end note]
  • every member of class T that is itself a type;
  • every member template of class T;
  • every enumerator of every member of class T that is an unscoped enumeration type; and
  • every member of every anonymous union that is a member of class T.
In addition, if class T has a user-declared constructor, every non-static data member of class T shall have a name different from T.
The common initial sequence of two standard-layout struct ([class.prop]) types is the longest sequence of non-static data members and bit-fields in declaration order, starting with the first such entity in each of the structs, such that
[Example 4: struct A { int a; char b; }; struct B { const int b1; volatile char b2; }; struct C { int c; unsigned : 0; char b; }; struct D { int d; char b : 4; }; struct E { unsigned int e; char b; };
The common initial sequence of A and B comprises all members of either class.
The common initial sequence of A and C and of A and D comprises the first member in each case.
The common initial sequence of A and E is empty.
— end example]
Two standard-layout struct ([class.prop]) types are layout-compatible classes if their common initial sequence comprises all members and bit-fields of both classes ([basic.types]).
Two standard-layout unions are layout-compatible if they have the same number of non-static data members and corresponding non-static data members (in any order) have layout-compatible types ([basic.types.general]).
In a standard-layout union with an active member of struct type T1, it is permitted to read a non-static data member m of another union member of struct type T2 provided m is part of the common initial sequence of T1 and T2; the behavior is as if the corresponding member of T1 were nominated.
[Example 5: struct T1 { int a, b; }; struct T2 { int c; double d; }; union U { T1 t1; T2 t2; }; int f() { U u = { { 1, 2 } }; // active member is t1 return u.t2.c; // OK, as if u.t1.a were nominated } — end example]
[Note 11: 
Reading a volatile object through a glvalue of non-volatile type has undefined behavior ([dcl.type.cv]).
— end note]
If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member if that member is not a bit-field.
Its address is also the same as the address of each of its base class subobjects.
[Note 12: 
There can therefore be unnamed padding within a standard-layout struct object inserted by an implementation, but not at its beginning, as necessary to achieve appropriate alignment.
— end note]
[Note 13: 
The object and its first subobject are pointer-interconvertible ([basic.compound], [expr.static.cast]).
— end note]

11.4.2 Member functions [class.mfct]

If a member function is attached to the global module and is defined ([dcl.fct.def]) in its class definition, it is inline ([dcl.inline]).
[Note 1: 
A member function is also inline if it is declared inline, constexpr, or consteval.
— end note]
[Example 1: struct X { typedef int T; static T count; void f(T); }; void X::f(T t = count) { }
The definition of the member function f of class X inhabits the global scope; the notation X​::​f indicates that the function f is a member of class X and in the scope of class X.
In the function definition, the parameter type T refers to the typedef member T declared in class X and the default argument count refers to the static data member count declared in class X.
— end example]
Member functions of a local class shall be defined inline in their class definition, if they are defined at all.
[Note 2: 
A member function can be declared (but not defined) using a typedef for a function type.
The resulting member function has exactly the same type as it would have if the function declarator were provided explicitly, see [dcl.fct] and [temp.arg].
[Example 2: typedef void fv(); typedef void fvc() const; struct S { fv memfunc1; // equivalent to: void memfunc1(); void memfunc2(); fvc memfunc3; // equivalent to: void memfunc3() const; }; fv S::* pmfv1 = &S::memfunc1; fv S::* pmfv2 = &S::memfunc2; fvc S::* pmfv3 = &S::memfunc3; — end example]
— end note]

11.4.3 Non-static member functions [class.mfct.non.static]

A non-static member function may be called for an object of its class type, or for an object of a class derived ([class.derived]) from its class type, using the class member access syntax ([expr.ref], [over.match.call]).
A non-static member function may also be called directly using the function call syntax ([expr.call], [over.match.call]) from within its class or a class derived from its class, or a member thereof, as described below.
[Note 1: 
An implicit object member function can be declared with cv-qualifiers, which affect the type of the this pointer ([expr.prim.this]), and/or a ref-qualifier ([dcl.fct]); both affect overload resolution ([over.match.funcs]).
— end note]
An implicit object member function may be declared virtual ([class.virtual]) or pure virtual ([class.abstract]).

11.4.4 Special member functions [special]

Default constructors ([class.default.ctor]), copy constructors, move constructors ([class.copy.ctor]), copy assignment operators, move assignment operators ([class.copy.assign]), and prospective destructors ([class.dtor]) are special member functions.
[Note 1: 
The implementation will implicitly declare these member functions for some class types when the program does not explicitly declare them.
The implementation will implicitly define them as needed ([dcl.fct.def.default]).
— end note]
An implicitly-declared special member function is declared at the closing } of the class-specifier.
Programs shall not define implicitly-declared special member functions.
Programs may explicitly refer to implicitly-declared special member functions.
[Example 1: 
A program may explicitly call or form a pointer to member to an implicitly-declared special member function.
struct A { }; // implicitly declared A​::​operator= struct B : A { B& operator=(const B &); }; B& B::operator=(const B& s) { this->A::operator=(s); // well-formed return *this; } — end example]
[Note 2: 
The special member functions affect the way objects of class type are created, copied, moved, and destroyed, and how values can be converted to values of other types.
Often such special member functions are called implicitly.
— end note]
Special member functions obey the usual access rules ([class.access]).
[Example 2: 
Declaring a constructor protected ensures that only derived classes and friends can create objects using it.
— end example]
Two special member functions are of the same kind if
  • they are both default constructors,
  • they are both copy or move constructors with the same first parameter type, or
  • they are both copy or move assignment operators with the same first parameter type and the same cv-qualifiers and ref-qualifier, if any.
An eligible special member function is a special member function for which:
  • the function is not deleted,
  • the associated constraints ([temp.constr]), if any, are satisfied, and
  • no special member function of the same kind whose associated constraints, if any, are satisfied is more constrained ([temp.constr.order]).
For a class, its non-static data members, its non-virtual direct base classes, and, if the class is not abstract ([class.abstract]), its virtual base classes are called its potentially constructed subobjects.

11.4.5 Constructors [class.ctor]

11.4.5.1 General [class.ctor.general]

A declarator declares a constructor if it is a function declarator ([dcl.fct]) of the form where the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:
Constructors do not have names.
In a constructor declaration, each decl-specifier in the optional decl-specifier-seq shall be friend, inline, constexpr, consteval, or an explicit-specifier.
[Example 1: struct S { S(); // declares the constructor }; S::S() { } // defines the constructor — end example]
A constructor is used to initialize objects of its class type.
[Note 1: 
Because constructors do not have names, they are never found during unqualified name lookup; however an explicit type conversion using the functional notation ([expr.type.conv]) will cause a constructor to be called to initialize an object.
The syntax looks like an explicit call of the constructor.
— end note]
[Example 2: complex zz = complex(1,2.3); cprint( complex(7.8,1.2) ); — end example]
[Note 2: 
For initialization of objects of class type see [class.init].
— end note]
An object created in this way is unnamed.
[Note 3: 
[class.temporary] describes the lifetime of temporary objects.
— end note]
[Note 4: 
Explicit constructor calls do not yield lvalues, see [basic.lval].
— end note]
[Note 5: 
Some language constructs have special semantics when used during construction; see [class.base.init] and [class.cdtor].
— end note]
A constructor can be invoked for a const, volatile or const volatile object.
const and volatile semantics ([dcl.type.cv]) are not applied on an object under construction.
They come into effect when the constructor for the most derived object ([intro.object]) ends.
The address of a constructor shall not be taken.
[Note 6: 
A return statement in the body of a constructor cannot specify a return value ([stmt.return]).
— end note]
A constructor shall not be a coroutine.
A constructor shall not have an explicit object parameter ([dcl.fct]).

11.4.5.2 Default constructors [class.default.ctor]

A default constructor for a class X is a constructor of class X for which each parameter that is not a function parameter pack has a default argument (including the case of a constructor with no parameters).
If there is no user-declared constructor or constructor template for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted ([dcl.fct.def]).
An implicitly-declared default constructor is an inline public member of its class.
A defaulted default constructor for class X is defined as deleted if
  • any non-static data member with no default member initializer ([class.mem]) is of reference type,
  • any non-variant non-static data member of const-qualified type (or possibly multi-dimensional array thereof) with no brace-or-equal-initializer is not const-default-constructible ([dcl.init]),
  • X is a union and all of its variant members are of const-qualified type (or possibly multi-dimensional array thereof),
  • X is a non-union class and all members of any anonymous union member are of const-qualified type (or possibly multi-dimensional array thereof),
  • any potentially constructed subobject, except for a non-static data member with a brace-or-equal-initializer or a variant member of a union where another non-static data member has a brace-or-equal-initializer, has class type M (or possibly multi-dimensional array thereof) and overload resolution ([over.match]) as applied to find M's corresponding constructor either does not result in a usable candidate ([over.match.general]) or, in the case of a variant member, selects a non-trivial function, or
  • any potentially constructed subobject has class type M (or possibly multi-dimensional array thereof) and M has a destructor that is deleted or inaccessible from the defaulted default constructor.
A default constructor is trivial if it is not user-provided and if
  • its class has no virtual functions ([class.virtual]) and no virtual base classes ([class.mi]), and
  • no non-static data member of its class has a default member initializer ([class.mem]), and
  • all the direct base classes of its class have trivial default constructors, and
  • for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.
Otherwise, the default constructor is non-trivial.
An implicitly-defined ([dcl.fct.def.default]) default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no ctor-initializer ([class.base.init]) and an empty compound-statement.
If that user-written default constructor would be ill-formed, the program is ill-formed.
If that user-written default constructor would be constexpr-suitable ([dcl.constexpr]), the implicitly-defined default constructor is constexpr.
Before the defaulted default constructor for a class is implicitly defined, all the non-user-provided default constructors for its base classes and its non-static data members are implicitly defined.
[Note 1: 
An implicitly-declared default constructor has an exception specification ([except.spec]).
An explicitly-defaulted definition might have an implicit exception specification, see [dcl.fct.def].
— end note]
[Note 2: 
A default constructor is implicitly invoked to initialize a class object when no initializer is specified ([dcl.init.general]).
Such a default constructor needs to be accessible ([class.access]).
— end note]
[Note 3: 
[class.base.init] describes the order in which constructors for base classes and non-static data members are called and describes how arguments can be specified for the calls to these constructors.
— end note]

11.4.5.3 Copy/move constructors [class.copy.ctor]

A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments ([dcl.fct.default]).
[Example 1: 
X​::​X(const X&) and X​::​X(X&,int=1) are copy constructors.
struct X { X(int); X(const X&, int = 1); }; X a(1); // calls X(int); X b(a, 0); // calls X(const X&, int); X c = b; // calls X(const X&, int); — end example]
A non-template constructor for class X is a move constructor if its first parameter is of type X&&, const X&&, volatile X&&, or const volatile X&&, and either there are no other parameters or else all other parameters have default arguments ([dcl.fct.default]).
[Example 2: 
Y​::​Y(Y&&) is a move constructor.
struct Y { Y(const Y&); Y(Y&&); }; extern Y f(int); Y d(f(1)); // calls Y(Y&&) Y e = d; // calls Y(const Y&) — end example]
[Note 1: 
All forms of copy/move constructor can be declared for a class.
[Example 3: struct X { X(const X&); X(X&); // OK X(X&&); X(const X&&); // OK, but possibly not sensible }; — end example]
— end note]
[Note 2: 
If a class X only has a copy constructor with a parameter of type X&, an initializer of type const X or volatile X cannot initialize an object of type cv X.
[Example 4: struct X { X(); // default constructor X(X&); // copy constructor with a non-const parameter }; const X cx; X x = cx; // error: X​::​X(X&) cannot copy cx into x — end example]
— end note]
A declaration of a constructor for a class X is ill-formed if its first parameter is of type cv X and either there are no other parameters or else all other parameters have default arguments.
A member function template is never instantiated to produce such a constructor signature.
[Example 5: struct S { template<typename T> S(T); S(); }; S g; void h() { S a(g); // does not instantiate the member template to produce S​::​S<S>(S); // uses the implicitly declared copy constructor } — end example]
If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly.
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defaulted ([dcl.fct.def]).
The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor ([depr.impldec]).
The implicitly-declared copy constructor for a class X will have the form X::X(const X&) if each potentially constructed subobject of a class type M (or array thereof) has a copy constructor whose first parameter is of type const M& or const volatile M&.90
Otherwise, the implicitly-declared copy constructor will have the form X::X(X&)
If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if
  • X does not have a user-declared copy constructor,
  • X does not have a user-declared copy assignment operator,
  • X does not have a user-declared move assignment operator, and
  • X does not have a user-declared destructor.
[Note 3: 
When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor might instead invoke a copy constructor.
— end note]
The implicitly-declared move constructor for class X will have the form X::X(X&&)
An implicitly-declared copy/move constructor is an inline public member of its class.
A defaulted copy/​move constructor for a class X is defined as deleted ([dcl.fct.def.delete]) if X has:
  • a potentially constructed subobject of type M (or possibly multi-dimensional array thereof) for which overload resolution ([over.match]), as applied to find M's corresponding constructor, either does not result in a usable candidate ([over.match.general]) or, in the case of a variant member, selects a non-trivial function,
  • any potentially constructed subobject of class type M (or possibly multi-dimensional array thereof) where M has a destructor that is deleted or inaccessible from the defaulted constructor, or,
  • for the copy constructor, a non-static data member of rvalue reference type.
[Note 4: 
A defaulted move constructor that is defined as deleted is ignored by overload resolution ([over.match], [over.over]).
Such a constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead.
— end note]
A copy/move constructor for class X is trivial if it is not user-provided and if
  • class X has no virtual functions ([class.virtual]) and no virtual base classes ([class.mi]), and
  • the constructor selected to copy/move each direct base class subobject is trivial, and
  • for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;
otherwise the copy/move constructor is non-trivial.
[Note 5: 
The copy/move constructor is implicitly defined even if the implementation elided its odr-use ([basic.def.odr], [class.temporary]).
— end note]
If an implicitly-defined ([dcl.fct.def.default]) constructor would be constexpr-suitable ([dcl.constexpr]), the implicitly-defined constructor is constexpr.
Before the defaulted copy/move constructor for a class is implicitly defined, all non-user-provided copy/move constructors for its potentially constructed subobjects are implicitly defined.
[Note 6: 
An implicitly-declared copy/move constructor has an implied exception specification ([except.spec]).
— end note]
The implicitly-defined copy/move constructor for a non-union class X performs a memberwise copy/move of its bases and members.
[Note 7: 
Default member initializers of non-static data members are ignored.
— end note]
The order of initialization is the same as the order of initialization of bases and members in a user-defined constructor (see [class.base.init]).
Let x be either the parameter of the constructor or, for the move constructor, an xvalue referring to the parameter.
Each base or non-static data member is copied/moved in the manner appropriate to its type:
  • if the member is an array, each element is direct-initialized with the corresponding subobject of x;
  • if a member m has rvalue reference type T&&, it is direct-initialized with static_cast<T&&>(x.m);
  • otherwise, the base or member is direct-initialized with the corresponding base or member of x.
Virtual base class subobjects shall be initialized only once by the implicitly-defined copy/move constructor (see [class.base.init]).
The implicitly-defined copy/move constructor for a union X copies the object representation ([basic.types.general]) of X.
For each object nested within ([intro.object]) the object that is the source of the copy, a corresponding object o nested within the destination is identified (if the object is a subobject) or created (otherwise), and the lifetime of o begins before the copy is performed.
90)90)
This implies that the reference parameter of the implicitly-declared copy constructor cannot bind to a volatile lvalue; see [diff.class].

11.4.6 Copy/move assignment operator [class.copy.assign]

A user-declared copy assignment operator X​::​operator= is a non-static non-template member function of class X with exactly one non-object parameter of type X, X&, const X&, volatile X&, or const volatile X&.91
[Note 1: 
More than one form of copy assignment operator can be declared for a class.
— end note]
[Note 2: 
If a class X only has a copy assignment operator with a non-object parameter of type X&, an expression of type const X cannot be assigned to an object of type X.
[Example 1: struct X { X(); X& operator=(X&); }; const X cx; X x; void f() { x = cx; // error: X​::​operator=(X&) cannot assign cx into x } — end example]
— end note]
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly.
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defaulted ([dcl.fct.def]).
The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor ([depr.impldec]).
The implicitly-declared copy assignment operator for a class X will have the form X& X::operator=(const X&) if
  • each direct base class B of X has a copy assignment operator whose non-object parameter is of type const B&, const volatile B&, or B, and
  • for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy assignment operator whose non-object parameter is of type const M&, const volatile M&, or M.92
Otherwise, the implicitly-declared copy assignment operator will have the form X& X::operator=(X&)
A user-declared move assignment operator X​::​operator= is a non-static non-template member function of class X with exactly one non-object parameter of type X&&, const X&&, volatile X&&, or const volatile X&&.
[Note 3: 
More than one form of move assignment operator can be declared for a class.
— end note]
If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly declared as defaulted if and only if
  • X does not have a user-declared copy constructor,
  • X does not have a user-declared move constructor,
  • X does not have a user-declared copy assignment operator, and
  • X does not have a user-declared destructor.
[Example 2: 
The class definition struct S { int a; S& operator=(const S&) = default; }; will not have a default move assignment operator implicitly declared because the copy assignment operator has been user-declared.
The move assignment operator may be explicitly defaulted.
struct S { int a; S& operator=(const S&) = default; S& operator=(S&&) = default; }; — end example]
The implicitly-declared move assignment operator for a class X will have the form X& X::operator=(X&&)
The implicitly-declared copy/move assignment operator for class X has the return type X&.
An implicitly-declared copy/move assignment operator is an inline public member of its class.
A defaulted copy/move assignment operator for class X is defined as deleted if X has:
  • a non-static data member of const non-class type (or possibly multi-dimensional array thereof), or
  • a non-static data member of reference type, or
  • a direct non-static data member of class type M (or possibly multi-dimensional array thereof) or a direct base class M that cannot be copied/moved because overload resolution ([over.match]), as applied to find M's corresponding assignment operator, either does not result in a usable candidate ([over.match.general]) or, in the case of a variant member, selects a non-trivial function.
[Note 4: 
A defaulted move assignment operator that is defined as deleted is ignored by overload resolution ([over.match], [over.over]).
— end note]
Because a copy/move assignment operator is implicitly declared for a class if not declared by the user, a base class copy/move assignment operator is always hidden by the corresponding assignment operator of a derived class ([over.ass]).
[Note 5: 
A using-declaration in a derived class C that names an assignment operator from a base class never suppresses the implicit declaration of an assignment operator of C, even if the base class assignment operator would be a copy or move assignment operator if declared as a member of C.
— end note]
A copy/move assignment operator for class X is trivial if it is not user-provided and if
  • class X has no virtual functions ([class.virtual]) and no virtual base classes ([class.mi]), and
  • the assignment operator selected to copy/move each direct base class subobject is trivial, and
  • for each non-static data member of X that is of class type (or array thereof), the assignment operator selected to copy/move that member is trivial;
otherwise the copy/move assignment operator is non-trivial.
An implicitly-defined ([dcl.fct.def.default]) copy/move assignment operator is constexpr.
Before the defaulted copy/move assignment operator for a class is implicitly defined, all non-user-provided copy/move assignment operators for its direct base classes and its non-static data members are implicitly defined.
[Note 6: 
An implicitly-declared copy/move assignment operator has an implied exception specification ([except.spec]).
— end note]
The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy/move assignment of its subobjects.
The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition.
Let x be either the parameter of the function or, for the move operator, an xvalue referring to the parameter.
Each subobject is assigned in the manner appropriate to its type:
  • if the subobject is of class type, as if by a call to operator= with the subobject as the object expression and the corresponding subobject of x as a single function argument (as if by explicit qualification; that is, ignoring any possible virtual overriding functions in more derived classes);
  • if the subobject is an array, each element is assigned, in the manner appropriate to the element type;
  • if the subobject is of scalar type, the built-in assignment operator is used.
It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined copy/move assignment operator.
[Example 3: struct V { }; struct A : virtual V { }; struct B : virtual V { }; struct C : B, A { };
It is unspecified whether the virtual base class subobject V is assigned twice by the implicitly-defined copy/move assignment operator for C.
— end example]
The implicitly-defined copy/move assignment operator for a union X copies the object representation ([basic.types.general]) of X.
If the source and destination of the assignment are not the same object, then for each object nested within ([intro.object]) the object that is the source of the copy, a corresponding object o nested within the destination is created, and the lifetime of o begins before the copy is performed.
The implicitly-defined copy/move assignment operator for a class returns the object for which the assignment operator is invoked, that is, the object assigned to.
91)91)
Because a template assignment operator or an assignment operator taking an rvalue reference parameter is never a copy assignment operator, the presence of such an assignment operator does not suppress the implicit declaration of a copy assignment operator.
Such assignment operators participate in overload resolution with other assignment operators, including copy assignment operators, and, if selected, will be used to assign an object.
92)92)
This implies that the reference parameter of the implicitly-declared copy assignment operator cannot bind to a volatile lvalue; see [diff.class].

11.4.7 Destructors [class.dtor]

A declaration whose declarator-id has an unqualified-id that begins with a ~ declares a prospective destructor; its declarator shall be a function declarator ([dcl.fct]) of the form where the ptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:
A prospective destructor shall take no arguments ([dcl.fct]).
Each decl-specifier of the decl-specifier-seq of a prospective destructor declaration (if any) shall be friend, inline, virtual, or constexpr.
If a class has no user-declared prospective destructor, a prospective destructor is implicitly declared as defaulted ([dcl.fct.def]).
An implicitly-declared prospective destructor is an inline public member of its class.
An implicitly-declared prospective destructor for a class X will have the form ~X()
At the end of the definition of a class, overload resolution is performed among the prospective destructors declared in that class with an empty argument list to select the destructor for the class, also known as the selected destructor.
The program is ill-formed if overload resolution fails.
Destructor selection does not constitute a reference to, or odr-use ([basic.def.odr]) of, the selected destructor, and in particular, the selected destructor may be deleted ([dcl.fct.def.delete]).
The address of a destructor shall not be taken.
[Note 1: 
A return statement in the body of a destructor cannot specify a return value ([stmt.return]).
— end note]
A destructor can be invoked for a const, volatile or const volatile object.
const and volatile semantics ([dcl.type.cv]) are not applied on an object under destruction.
They stop being in effect when the destructor for the most derived object ([intro.object]) starts.
[Note 2: 
A declaration of a destructor that does not have a noexcept-specifier has the same exception specification as if it had been implicitly declared ([except.spec]).
— end note]
A defaulted destructor for a class X is defined as deleted if
  • any potentially constructed subobject has class type M (or possibly multi-dimensional array thereof) and M has a destructor that is deleted or is inaccessible from the defaulted destructor or, in the case of a variant member, is non-trivial,
  • or, for a virtual destructor, lookup of the non-array deallocation function results in an ambiguity or in a function that is deleted or inaccessible from the defaulted destructor.
A destructor is trivial if it is not user-provided and if
  • the destructor is not virtual,
  • all of the direct base classes of its class have trivial destructors, and
  • for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
Otherwise, the destructor is non-trivial.
A defaulted destructor is a constexpr destructor if it is constexpr-suitable ([dcl.constexpr]).
Before a defaulted destructor for a class is implicitly defined, all the non-user-provided destructors for its base classes and its non-static data members are implicitly defined.
A prospective destructor can be declared virtual ([class.virtual]) and with a pure-specifier ([class.abstract]).
If the destructor of a class is virtual and any objects of that class or any derived class are created in the program, the destructor shall be defined.
[Note 3: 
Some language constructs have special semantics when used during destruction; see [class.cdtor].
— end note]
After executing the body of the destructor and destroying any objects with automatic storage duration allocated within the body, a destructor for class X calls the destructors for X's direct non-variant non-static data members other than anonymous unions, the destructors for X's non-virtual direct base classes and, if X is the most derived class ([class.base.init]), its destructor calls the destructors for X's virtual base classes.
All destructors are called as if they were referenced with a qualified name, that is, ignoring any possible virtual overriding destructors in more derived classes.
Bases and members are destroyed in the reverse order of the completion of their constructor (see [class.base.init]).
[Note 4: 
A return statement ([stmt.return]) in a destructor might not directly return to the caller; before transferring control to the caller, the destructors for the members and bases are called.
— end note]
Destructors for elements of an array are called in reverse order of their construction (see [class.init]).
A destructor is invoked implicitly
In each case, the context of the invocation is the context of the construction of the object.
A destructor may also be invoked implicitly through use of a delete-expression ([expr.delete]) for a constructed object allocated by a new-expression ([expr.new]); the context of the invocation is the delete-expression.
[Note 5: 
An array of class type contains several subobjects for each of which the destructor is invoked.
— end note]
A destructor can also be invoked explicitly.
A destructor is potentially invoked if it is invoked or as specified in [expr.new], [stmt.return], [dcl.init.aggr], [class.base.init], and [except.throw].
A program is ill-formed if a destructor that is potentially invoked is deleted or not accessible from the context of the invocation.
At the point of definition of a virtual destructor (including an implicit definition), the non-array deallocation function is determined as if for the expression delete this appearing in a non-virtual destructor of the destructor's class (see [expr.delete]).
If the lookup fails or if the deallocation function has a deleted definition ([dcl.fct.def]), the program is ill-formed.
[Note 6: 
This assures that a deallocation function corresponding to the dynamic type of an object is available for the delete-expression ([class.free]).
— end note]
In an explicit destructor call, the destructor is specified by a ~ followed by a type-name or computed-type-specifier that denotes the destructor's class type.
The invocation of a destructor is subject to the usual rules for member functions ([class.mfct]); that is, if the object is not of the destructor's class type and not of a class derived from the destructor's class type (including when the destructor is invoked via a null pointer value), the program has undefined behavior.
[Note 7: 
Invoking delete on a null pointer does not call the destructor; see [expr.delete].
— end note]
[Example 1: struct B { virtual ~B() { } }; struct D : B { ~D() { } }; D D_object; typedef B B_alias; B* B_ptr = &D_object; void f() { D_object.B::~B(); // calls B's destructor B_ptr->~B(); // calls D's destructor B_ptr->~B_alias(); // calls D's destructor B_ptr->B_alias::~B(); // calls B's destructor B_ptr->B_alias::~B_alias(); // calls B's destructor } — end example]
[Note 8: 
An explicit destructor call must always be written using a member access operator ([expr.ref]) or a qualified-id ([expr.prim.id.qual]); in particular, the unary-expression ~X() in a member function is not an explicit destructor call ([expr.unary.op]).
— end note]
[Note 9: 
Explicit calls of destructors are rarely needed.
One use of such calls is for objects placed at specific addresses using a placement new-expression.
Such use of explicit placement and destruction of objects can be necessary to cope with dedicated hardware resources and for writing memory management facilities.
[Example 2: void* operator new(std::size_t, void* p) { return p; } struct X { X(int); ~X(); }; void f(X* p); void g() { // rare, specialized use: char* buf = new char[sizeof(X)]; X* p = new(buf) X(222); // use buf[] and initialize f(p); p->X::~X(); // cleanup } — end example]
— end note]
Once a destructor is invoked for an object, the object's lifetime ends; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended ([basic.life]).
[Example 3: 
If the destructor for an object with automatic storage duration is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined.
— end example]
[Note 10: 
The notation for explicit call of a destructor can be used for any scalar type name ([expr.prim.id.dtor]).
Allowing this makes it possible to write code without having to know if a destructor exists for a given type.
For example: typedef int I; I* p; p->I::~I();
— end note]
A destructor shall not be a coroutine.

11.4.8 Conversions [class.conv]

11.4.8.1 General [class.conv.general]

Type conversions of class objects can be specified by constructors and by conversion functions.
These conversions are called user-defined conversions and are used for implicit type conversions ([conv]), for initialization ([dcl.init]), and for explicit type conversions ([expr.type.conv], [expr.cast], [expr.static.cast]).
User-defined conversions are applied only where they are unambiguous ([class.member.lookup], [class.conv.fct]).
Conversions obey the access control rules ([class.access]).
Access control is applied after ambiguity resolution ([basic.lookup]).
[Note 1: 
See [over.match] for a discussion of the use of conversions in function calls.
— end note]
At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.
[Example 1: struct X { operator int(); }; struct Y { operator X(); }; Y a; int b = a; // error: no viable conversion (a.operator X().operator int() not considered) int c = X(a); // OK, a.operator X().operator int() — end example]

11.4.8.2 Conversion by constructor [class.conv.ctor]

A constructor that is not explicit ([dcl.fct.spec]) specifies a conversion from the types of its parameters (if any) to the type of its class.
Such a constructor is called a converting constructor.
[Example 1: struct X { X(int); X(const char*, int = 0); X(int, int); }; void f(X arg) { X a = 1; // a = X(1) X b = "Jessie"; // b = X("Jessie",0) a = 2; // a = X(2) f(3); // f(X(3)) f({1, 2}); // f(X(1,2)) } — end example]
[Note 1: 
An explicit constructor constructs objects just like non-explicit constructors, but does so only where the direct-initialization syntax ([dcl.init]) or where casts ([expr.static.cast], [expr.cast]) are explicitly used; see also [over.match.copy].
A default constructor can be an explicit constructor; such a constructor will be used to perform default-initialization or value-initialization ([dcl.init]).
[Example 2: struct Z { explicit Z(); explicit Z(int); explicit Z(int, int); }; Z a; // OK, default-initialization performed Z b{}; // OK, direct initialization syntax used Z c = {}; // error: copy-list-initialization Z a1 = 1; // error: no implicit conversion Z a3 = Z(1); // OK, direct initialization syntax used Z a2(1); // OK, direct initialization syntax used Z* p = new Z(1); // OK, direct initialization syntax used Z a4 = (Z)1; // OK, explicit cast used Z a5 = static_cast<Z>(1); // OK, explicit cast used Z a6 = { 3, 4 }; // error: no implicit conversion — end example]
— end note]
A non-explicit copy/move constructor ([class.copy.ctor]) is a converting constructor.
[Note 2: 
An implicitly-declared copy/move constructor is not an explicit constructor; it can be called for implicit type conversions.
— end note]

11.4.8.3 Conversion functions [class.conv.fct]

A declaration whose declarator-id has an unqualified-id that is a conversion-function-id declares a conversion function; its declarator shall be a function declarator ([dcl.fct]) of the form where the noptr-declarator consists solely of an id-expression, an optional attribute-specifier-seq, and optional surrounding parentheses, and the id-expression has one of the following forms:
A conversion function shall have no non-object parameters and shall be a non-static member function of a class or class template X; its declared return type is the conversion-type-id and it specifies a conversion from X to the type specified by the conversion-type-id, interpreted as a type-id ([dcl.name]).
A decl-specifier in the decl-specifier-seq of a conversion function (if any) shall not be a defining-type-specifier.
[Note 1: 
A conversion function is never invoked for implicit or explicit conversions of an object to the same object type (or a reference to it), to a base class of that type (or a reference to it), or to cv void.
Even though never directly called to perform a conversion, such conversion functions can be declared and can potentially be reached through a call to a virtual conversion function in a base class.
— end note]
[Example 1: struct X { operator int(); operator auto() -> short; // error: trailing return type }; void f(X a) { int i = int(a); i = (int)a; i = a; }
In all three cases the value assigned will be converted by X​::​operator int().
— end example]
A conversion function may be explicit ([dcl.fct.spec]), in which case it is only considered as a user-defined conversion for direct-initialization ([dcl.init]).
Otherwise, user-defined conversions are not restricted to use in assignments and initializations.
[Example 2: class Y { }; struct Z { explicit operator Y() const; }; void h(Z z) { Y y1(z); // OK, direct-initialization Y y2 = z; // error: no conversion function candidate for copy-initialization Y y3 = (Y)z; // OK, cast notation } void g(X a, X b) { int i = (a) ? 1+a : 0; int j = (a&&b) ? a+b : i; if (a) { } } — end example]
The conversion-type-id shall not represent a function type nor an array type.
The conversion-type-id in a conversion-function-id is the longest sequence of tokens that could possibly form a conversion-type-id.
[Note 2: 
This prevents ambiguities between the declarator operator * and its expression counterparts.
[Example 3: &ac.operator int*i; // syntax error: // parsed as: &(ac.operator int *)i // not as: &(ac.operator int)*i
The * is the pointer declarator and not the multiplication operator.
— end example]
This rule also prevents ambiguities for attributes.
[Example 4: operator int [[noreturn]] (); // error: noreturn attribute applied to a type — end example]
— end note]
[Note 3: 
A conversion function in a derived class hides only conversion functions in base classes that convert to the same type.
A conversion function template with a dependent return type hides only templates in base classes that correspond to it ([class.member.lookup]); otherwise, it hides and is hidden as a non-template function.
Function overload resolution ([over.match.best]) selects the best conversion function to perform the conversion.
[Example 5: struct X { operator int(); }; struct Y : X { operator char(); }; void f(Y& a) { if (a) { // error: ambiguous between X​::​operator int() and Y​::​operator char() } } — end example]
— end note]
Conversion functions can be virtual.
A conversion function template shall not have a deduced return type ([dcl.spec.auto]).
[Example 6: struct S { operator auto() const { return 10; } // OK template<class T> operator auto() const { return 1.2; } // error: conversion function template }; — end example]

11.4.9 Static members [class.static]

11.4.9.1 General [class.static.general]

A static member s of class X may be referred to using the qualified-id expression X​::​s; it is not necessary to use the class member access syntax ([expr.ref]) to refer to a static member.
A static member may be referred to using the class member access syntax, in which case the object expression is evaluated.
[Example 1: struct process { static void reschedule(); }; process& g(); void f() { process::reschedule(); // OK, no object necessary g().reschedule(); // g() is called } — end example]
Static members obey the usual class member access rules ([class.access]).
When used in the declaration of a class member, the static specifier shall only be used in the member declarations that appear within the member-specification of the class definition.
[Note 1: 
It cannot be specified in member declarations that appear in namespace scope.
— end note]

11.4.9.2 Static member functions [class.static.mfct]

[Note 1: 
The rules described in [class.mfct] apply to static member functions.
— end note]
[Note 2: 
A static member function does not have a this pointer ([expr.prim.this]).
A static member function cannot be qualified with const, volatile, or virtual ([dcl.fct]).
— end note]

11.4.9.3 Static data members [class.static.data]

A static data member is not part of the subobjects of a class.
If a static data member is declared thread_local there is one copy of the member per thread.
If a static data member is not declared thread_local there is one copy of the data member that is shared by all the objects of the class.
A static data member shall not be mutable ([dcl.stc]).
A static data member shall not be a direct member ([class.mem]) of an unnamed ([class.pre]) or local ([class.local]) class or of a (possibly indirectly) nested class ([class.nest]) thereof.
The declaration of a non-inline static data member in its class definition is not a definition and may be of an incomplete type other than cv void.
[Note 1: 
The initializer in the definition of a static data member is in the scope of its class ([basic.scope.class]).
— end note]
[Example 1: class process { static process* run_chain; static process* running; }; process* process::running = get_main(); process* process::run_chain = running;
The definition of the static data member run_chain of class process inhabits the global scope; the notation process​::​run_chain indicates that the member run_chain is a member of class process and in the scope of class process.
In the static data member definition, the initializer expression refers to the static data member running of class process.
— end example]
[Note 2: 
Once the static data member has been defined, it exists even if no objects of its class have been created.
[Example 2: 
In the example above, run_chain and running exist even if no objects of class process are created by the program.
— end example]
The initialization and destruction of static data members is described in [basic.start.static], [basic.start.dynamic], and [basic.start.term].
— end note]
If a non-volatile non-inline const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression ([expr.const]).
The member shall still be defined in a namespace scope if it is odr-used ([basic.def.odr]) in the program and the namespace scope definition shall not contain an initializer.
The declaration of an inline static data member (which is a definition) may specify a brace-or-equal-initializer.
If the member is declared with the constexpr specifier, it may be redeclared in namespace scope with no initializer (this usage is deprecated; see [depr.static.constexpr]).
Declarations of other static data members shall not specify a brace-or-equal-initializer.
[Note 3: 
There is exactly one definition of a static data member that is odr-used ([basic.def.odr]) in a valid program.
— end note]
[Note 4: 
Static data members of a class in namespace scope have the linkage of the name of the class ([basic.link]).
— end note]

11.4.10 Bit-fields [class.bit]

The optional attribute-specifier-seq appertains to the entity being declared.
A bit-field shall not be a static member.
A bit-field shall have integral or (possibly cv-qualified) enumeration type; the bit-field semantic property is not part of the type of the class member.
The constant-expression shall be an integral constant expression with a value greater than or equal to zero and is called the width of the bit-field.
If the width of a bit-field is larger than the width of the bit-field's type (or, in case of an enumeration type, of its underlying type), the extra bits are padding bits ([basic.types.general]).
Allocation of bit-fields within a class object is implementation-defined.
Alignment of bit-fields is implementation-defined.
Bit-fields are packed into some addressable allocation unit.
[Note 1: 
Bit-fields straddle allocation units on some machines and not on others.
Bit-fields are assigned right-to-left on some machines, left-to-right on others.
— end note]
A declaration for a bit-field that omits the identifier declares an unnamed bit-field.
Unnamed bit-fields are not members and cannot be initialized.
An unnamed bit-field shall not be declared with a cv-qualified type.
[Note 2: 
An unnamed bit-field is useful for padding to conform to externally-imposed layouts.
— end note]
As a special case, an unnamed bit-field with a width of zero specifies alignment of the next bit-field at an allocation unit boundary.
Only when declaring an unnamed bit-field may the width be zero.
The address-of operator & shall not be applied to a bit-field, so there are no pointers to bit-fields.
A non-const reference shall not bind to a bit-field ([dcl.init.ref]).
[Note 3: 
If the initializer for a reference of type const T& is an lvalue that refers to a bit-field, the reference is bound to a temporary initialized to hold the value of the bit-field; the reference is not bound to the bit-field directly.
— end note]
If a value of integral type (other than bool) is stored into a bit-field of width N and the value would be representable in a hypothetical signed or unsigned integer type with width N and the same signedness as the bit-field's type, the original value and the value of the bit-field compare equal.
If the value true or false is stored into a bit-field of type bool of any size (including a one bit bit-field), the original bool value and the value of the bit-field compare equal.
If a value of an enumeration type is stored into a bit-field of the same type and the width is large enough to hold all the values of that enumeration type ([dcl.enum]), the original value and the value of the bit-field compare equal.
[Example 1: enum BOOL { FALSE=0, TRUE=1 }; struct A { BOOL b:1; }; A a; void f() { a.b = TRUE; if (a.b == TRUE) // yields true { /* ... */ } } — end example]

11.4.11 Allocation and deallocation functions [class.free]

Any allocation function for a class T is a static member (even if not explicitly declared static).
[Example 1: class Arena; struct B { void* operator new(std::size_t, Arena*); }; struct D1 : B { }; Arena* ap; void foo(int i) { new (ap) D1; // calls B​::​operator new(std​::​size_t, Arena*) new D1[i]; // calls ​::​operator new[](std​::​size_t) new D1; // error: ​::​operator new(std​::​size_t) hidden } — end example]
Any deallocation function for a class X is a static member (even if not explicitly declared static).
[Example 2: class X { void operator delete(void*); void operator delete[](void*, std::size_t); }; class Y { void operator delete(void*, std::size_t); void operator delete[](void*); }; — end example]
Since member allocation and deallocation functions are static they cannot be virtual.
[Note 1: 
However, when the cast-expression of a delete-expression refers to an object of class type with a virtual destructor, because the deallocation function is chosen by the destructor of the dynamic type of the object, the effect is the same in that case.
[Example 3: struct B { virtual ~B(); void operator delete(void*, std::size_t); }; struct D : B { void operator delete(void*); }; struct E : B { void log_deletion(); void operator delete(E *p, std::destroying_delete_t) { p->log_deletion(); p->~E(); ::operator delete(p); } }; void f() { B* bp = new D; delete bp; // 1: uses D​::​operator delete(void*) bp = new E; delete bp; // 2: uses E​::​operator delete(E*, std​::​destroying_delete_t) }
Here, storage for the object of class D is deallocated by D​::​operator delete(), and the object of class E is destroyed and its storage is deallocated by E​::​operator delete(), due to the virtual destructor.
— end example]
— end note]
[Note 2: 
Virtual destructors have no effect on the deallocation function actually called when the cast-expression of a delete-expression refers to an array of objects of class type.
[Example 4: struct B { virtual ~B(); void operator delete[](void*, std::size_t); }; struct D : B { void operator delete[](void*, std::size_t); }; void f(int i) { D* dp = new D[i]; delete [] dp; // uses D​::​operator delete[](void*, std​::​size_t) B* bp = new D[i]; delete[] bp; // undefined behavior } — end example]
— end note]
Access to the deallocation function is checked statically, even if a different one is actually executed.
[Example 5: 
For the call on line “// 1” above, if B​::​operator delete() had been private, the delete expression would have been ill-formed.
— end example]
[Note 3: 
If a deallocation function has no explicit noexcept-specifier, it has a non-throwing exception specification ([except.spec]).
— end note]

11.4.12 Nested class declarations [class.nest]

A class can be declared within another class.
A class declared within another is called a nested class.
[Note 1: 
See [expr.prim.id] for restrictions on the use of non-static data members and non-static member functions.
— end note]
[Example 1: int x; int y; struct enclose { int x; static int s; struct inner { void f(int i) { int a = sizeof(x); // OK, operand of sizeof is an unevaluated operand x = i; // error: assign to enclose​::​x s = i; // OK, assign to enclose​::​s ::x = i; // OK, assign to global x y = i; // OK, assign to global y } void g(enclose* p, int i) { p->x = i; // OK, assign to enclose​::​x } }; }; inner* p = 0; // error: inner not found — end example]
[Note 2: 
Nested classes can be defined either in the enclosing class or in an enclosing namespace; member functions and static data members of a nested class can be defined either in the nested class or in an enclosing namespace scope.
[Example 2: struct enclose { struct inner { static int x; void f(int i); }; }; int enclose::inner::x = 1; void enclose::inner::f(int i) { /* ... */ } class E { class I1; // forward declaration of nested class class I2; class I1 { }; // definition of nested class }; class E::I2 { }; // definition of nested class — end example]
— end note]
A friend function ([class.friend]) defined within a nested class has no special access rights to members of an enclosing class.