Полезная информация


  ______________________________________________________________________

  10   Derived classes                                   [class.derived]

  ______________________________________________________________________

1 A list of base classes can be specified in a  class  definition  using
  the notation:
          base-clause:
                  : base-specifier-list
          base-specifier-list:
                  base-specifier
                  base-specifier-list , base-specifier
          base-specifier:
                  ::opt nested-name-specifieropt class-name
                  virtual access-specifieropt ::opt nested-name-specifieropt class-name
                  access-specifier virtualopt ::opt nested-name-specifieropt class-name
          access-specifier:
                  private
                  protected
                  public
  The  class-name  in  a  base-specifier  shall  not  be an incompletely
  defined class (_class_); this class is called a direct base class  for
  the  class  being declared.  During the look up for a base class name,
  non-type names are ignored (_basic.scope.hiding_).  If the name  found
  is  not  a class-name, the program is ill-formed.  A class B is a base
  class of a class D if it is a direct base class of D or a direct  base
  class  of  one of D's base classes.  A class is an indirect base class
  of another if it is a base class but not a direct base class.  A class
  is  said  to  be  (directly or indirectly) derived from its (direct or
  indirect) base classes.  [Note: for the  meaning  of  access-specifier
  see  _class.access_.  ] Unless redefined in the derived class, members
  of a base class are also considered  to  be  members  of  the  derived
  class.  The base class members are said to be inherited by the derived
  class.  Inherited members can be referred to  in  expressions  in  the
  same  manner as other members of the derived class, unless their names
  are hidden or ambiguous  (_class.member.lookup_).   [Note:  the  scope
  resolution  operator :: (_expr.prim_) can be used to refer to a direct
  or indirect base member explicitly.  This allows access to a name that
  has  been  redefined 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_).  ]

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

          class Base {
          public:
              int a, b, c;
          };
          class Derived : public Base {
          public:
              int b;
          };
          class Derived2 : public Derived {
          public:
              int c;
          };
  Here, an object of class Derived2 will  have  a  sub-object  of  class
  Derived which in turn will have a sub-object of class Base.  ]

3 The order in which the base class subobjects are allocated in the most
  derived object (_intro.object_)  is  unspecified.   [Note:  a  derived
  class  and its base class sub-objects can be represented by a directed
  acyclic graph (DAG) where an arrow means "directly derived  from."   A
  DAG of sub-objects is often referred to as a "sub-object lattice."
                                   Base
                                     |
                                     |
                                  Derived
                                     |
                                 Derived2

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

4 [Note:  initialization  of  objects  representing  base classes can be
  specified in constructors; see _class.base.init_.  ]

5 [Note: A base class subobject might have a layout  (_basic.stc_)  dif-
  ferent  from  the layout of a most derived object of the same type.  A
  base class subobject might have a polymorphic behavior (_class.cdtor_)
  different  from  the  polymorphic behavior of a most derived object of
  the same type.  A base class subobject may be of zero size  (_class_);
  however,  two subobjects that have the same class type and that belong
  to the same most derived object must not  be  allocated  at  the  same
  address (_expr.eq_).  ]

  10.1  Multiple base classes                                 [class.mi]

1 A  class  can  be derived from any number of base classes.  [Note: the
  use of more than one direct base class is often called multiple inher-
  itance.  ] [Example:
          class A { /* ... */ };
          class B { /* ... */ };
          class C { /* ... */ };
          class D : public A, public B, public C { /* ... */ };
   --end example]

2 [Note:  the order of derivation is not significant except as specified
  by the semantics of initialization by constructor (_class.base.init_),

  cleanup    (_class.dtor_),    and    storage    layout   (_class.mem_,
  _class.access.spec_).  ]

3 A class shall not be specified as a direct base  class  of  a  derived
  class  more  than  once.  [Note: a class can be an indirect base class
  more than once and can be a direct and  an  indirect  base  class.   ]
  [Example:
          class X { /* ... */ };
          class Y : public X, public X { /* ... */ };  // ill-formed
          class L { public: int next;  /* ... */ };
          class A : public L { /* ... */ };
          class B : public L { /* ... */ };
          class C : public A, public B { void f(); /* ... */ };   // well-formed
          class D : public A, public L { void f(); /* ... */ };   // well-formed
   --end example]

4 A  base  class  specifier  that  does not contain the keyword virtual,
  specifies a nonvirtual base class.  A base class specifier  that  con-
  tains  the  keyword virtual, specifies a virtual base class.  For each
  distinct occurrence of a nonvirtual base class in the class lattice of
  the most derived class, the most derived object (_intro.object_) shall
  contain a corresponding distinct base class subobject  of  that  type.
  For  each  distinct  base  class  that  is specified virtual, the most
  derived object shall contain a single base  class  subobject  of  that
  type.   [Example:  for an object of class type C, each distinct occur-
  rence of a (non-virtual) base class L in the class lattice of C corre-
  sponds  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 sub-objects of class L as shown below.
                               L          L
                               |           |
                               |           |
                               A          B

                                    C

  In  such lattices, explicit qualification can be used to specify which
  subobject is meant.  The body of function C::f could refer to the mem-
  ber next of each L subobject:
          void C::f() { A::next = B::next; }   // well-formed
  Without  the A:: or B:: qualifiers, the definition of C::f above would
  be ill-formed because of ambiguity (_class.member.lookup_).

5 For another example,
          class V { /* ... */ };
          class A : virtual public V { /* ... */ };
          class B : virtual public V { /* ... */ };
          class C : public A, public B { /* ... */ };
  for an object c of class type C, a  single  subobject  of  type  V  is
  shared by every base subobject of c that is declared to have a virtual
  base class of type V.  Given the class C defined above, an  object  of
  class C will have one subobject of class V, as shown below.

                                    V

                               A          B

                                    C

6 A  class  can have both virtual and nonvirtual 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 dis-
  tinct B subobject within the object of type AA.  Given  the  class  AA
  defined  above, class AA has two sub-objects of class B: Z's B and the
  virtual B shared by X and Y, as shown below.
                                 B           B
                                              |
                                              |
                            X          Y     Z

                                 AA

   --end example]

  10.2  Member name lookup                         [class.member.lookup]

1 Member name lookup determines the meaning of a name id-expression)  in
  a  class  scope  (_basic.scope.class_).   Name lookup can result in an
  ambiguity, in which case the program is ill-formed.  For an id-expres-
  sion,  name lookup begins in the class scope of this; for a qualified-
  id, name lookup begins in  the  scope  of  the  nested-name-specifier.
  Name   lookup  takes  place  before  access  control  (_basic.lookup_,
  _class.access_).

2 The following steps define the result of name lookup in a class scope,
  C.   First, every declaration for the name in the class and in each of
  its base class sub-objects is considered.  A member name f in one sub-
  object  B hides a member name f in a sub-object A if A is a base class
  sub-object of B.  Any declarations that are so hidden  are  eliminated
  from consideration.  Each of these declarations that was introduced by
  a using-declaration is considered to be from each sub-object of C that
  is   of   the  type  containing  the  declaration  designated  by  the
  using-declaration.1)  If the resulting set of declarations are not all
  _________________________
  1) Note that using-declarations cannot be used  to  resolve  inherited
  member ambiguities; see _namespace.udecl_.

  from sub-objects of the same type, or the set has a  nonstatic  member
  and  includes members from distinct sub-objects, there is an ambiguity
  and the program is ill-formed.  Otherwise that set is  the  result  of
  the lookup.

3 [Example:
          class A {
          public:
              int a;
              int (*b)();
              int f();
              int f(int);
              int g();
          };
          class B {
              int a;
              int b();
          public:
              int f();
              int g;
              int h();
              int h(int);
          };
          class C : public A, public B {};
          void g(C* pc)
          {
              pc->a = 1;  // error: ambiguous: A::a or B::a
              pc->b();    // error: ambiguous: A::b or B::b
              pc->f();    // error: ambiguous: A::f or B::f
              pc->f(1);   // error: ambiguous: A::f or B::f
              pc->g();    // error: ambiguous: A::g or B::g
              pc->g = 1;  // error: ambiguous: A::g or B::g
              pc->h();    // ok
              pc->h(1);   // ok
          }
   --end example] [Example:
          struct U { static int i; };
          struct V : U { };
          struct W : U { using U::i; };
          struct X : V, W { void foo(); };
          void X::foo() {
                  i;      // finds U::i in two ways: as W::i and U::i in V
                          // no ambiguity because U::i is static
          }
   --end example]

4 If  the  name  of an overloaded function is unambiguously found, over-
  loading resolution (_over.match_) also takes place before access  con-
  trol.  Ambiguities can often be resolved by qualifying a name with its
  class name.  [Example:
          class A {
          public:
              int f();
          };

          class B {
          public:
              int f();
          };
          class C : public A, public B {
              int f() { return A::f() + B::f(); }
          };
   --end example]

5 A static member, a nested type or an  enumerator  defined  in  a  base
  class T can unambiguously be found even if an object has more than one
  base class subobject of type T.  Two base class subobjects  share  the
  nonstatic  member  subobjects  of  their  common virtual base classes.
  [Example:
          class V { public: int v; };
          class A {
          public:
              int a;
              static int   s;
              enum { e };
          };
          class B : public A, public virtual V {};
          class C : public A, public virtual V {};
          class D : public B, public C { };

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

6 When virtual base classes  are  used,  a  hidden  declaration  can  be
  reached along a path through the sub-object lattice that does not pass
  through the hiding declaration.  This is not an ambiguity.  The  iden-
  tical  use  with nonvirtual base classes is an ambiguity; in that case
  there is no unique instance of the name that  hides  all  the  others.
  [Example:
          class V { public: int f();  int x; };
          class W { public: int g();  int y; };
          class B : public virtual V, public W
          {
          public:
              int f();  int x;
              int g();  int y;
          };
          class C : public virtual V, public W { };
          class D : public B, public C { void glorp(); };

                         W          V           W

                              B           C

                                    D

  The  names  defined in V and the left hand instance of W are hidden by
  those in B, but the names defined in the right hand instance of W  are
  not hidden at all.
          void D::glorp()
          {
              x++;        // ok: B::x hides V::x
              f();        // ok: B::f() hides V::f()
              y++;        // error: B::y and C's W::y
              g();        // error: B::g() and C's W::g()
          }
   --end example]

7 An explicit or implicit conversion from a pointer to or an lvalue of a
  derived class to a pointer or reference to one  of  its  base  classes
  shall  unambiguously  refer  to  a unique object representing the base
  class.  [Example:
          class V { };
          class A { };
          class B : public A, public virtual V { };
          class C : public A, public virtual V { };
          class D : public B, public C { };
          void g()
          {
              D d;
              B* pb = &d;
              A* pa = &d;  // error, ambiguous: C's A or B's A ?
              V* pv = &d;  // fine: only one V sub-object
          }
   --end example]

  10.3  Virtual functions                                [class.virtual]

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

2 If a virtual member function vf is declared in a class Base and  in  a
  class  Derived,  derived  directly  or  indirectly from Base, a member
  function vf with the same name and same parameter list as Base::vf  is
  declared,  then  Derived::vf  is also virtual (whether or not it is so
  declared)  and  it  overrides2) Base::vf.  For convenience we say that
  _________________________
  2) A function with the  same  name  but  a  different  parameter  list
  (_over_) as a virtual function is not necessarily virtual and does not
  override.  The use of the virtual specifier in the declaration  of  an
  overriding function is legal but redundant (has empty semantics).  Ac-
  cess control (_class.access_) is not considered in  determining  over-

  any virtual function overrides itself.  Then in any well-formed class,
  for  each virtual function declared in that class or any of its direct
  or indirect base classes there is a unique final overrider that  over-
  rides  that  function and every other overrider of that function.  The
  rules for member lookup (_class.member.lookup_) are used to  determine
  the  final  overrider for a virtual function in the scope of a derived
  class but ignoring names introduced by using-declarations.  [Example:
          struct A {
                  virtual void f();
          };
          struct B : virtual A {
                  virtual void f();
          };
          struct C : B , virtual A {
                  using A::f;
          };
          void foo() {
                  C c;
                  c.f();    // calls B::f, the final overrider
                  c.c::f(); // calls A::f because of the using-declaration
          }
   --end example]

3 [Note: a virtual member function does not have to  be  visible  to  be
  overridden, for example,
          struct B {
                  virtual void f();
          };
          struct D : B {
                  void f(int);
          };
          struct D2 : D {
                  void f();
          };
  the  function  f(int) in class D hides the virtual function f() in its
  base class B; D::f(int) is  not  a  virtual  function.   However,  f()
  declared  in class D2 has the same name and the same parameter list as
  B::f(), and therefore is a virtual function that overrides  the  func-
  tion B::f() even though B::f() is not visible in class D2.  ]

4 Even  though  destructors are not inherited, a destructor in a derived
  class  overrides  a  base  class  destructor  declared  virtual;   see
  _class.dtor_ and _class.free_.

5 The return type of an overriding function shall be either identical to
  the return type of the  overridden  function  or  covariant  with  the
  classes  of  the  functions.   If a function D::f overrides a function
  B::f, the return types of the functions are covariant if they  satisfy
  the following criteria:

  --both are pointers to classes or references to classes3)
  _________________________
  riding.
  3) Multi-level pointers to classes or references to multi-level point-

  --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 direct or indirect
    base class of the class in the return type of D::f and is accessible
    in D

  --both  pointers  or references have the same cv-qualification and the
    class type in the return type of D::f has the same  cv-qualification
    as  or  less cv-qualification than the class type in the return type
    of B::f.

  If the return type of D::f differs from the return type of  B::f,  the
  class  type  in the return type of D::f shall be complete at the point
  of declaration of D::f or shall be the class type D.  When  the  over-
  riding  function  is  called  as the final overrider of the overridden
  function, its result is converted to the type returned by the  (stati-
  cally chosen) overridden function (_expr.call_).  [Example:
          class B {};
          class D : private B { friend class Derived; };
          struct Base {
              virtual void vf1();
              virtual void vf2();
              virtual void vf3();
              virtual B*   vf4();
              virtual B*   vf5();
              void f();
          };
          struct No_good : public Base {
              D*  vf4();        // error: B (base class of D) inaccessible
          };
          class A;
          struct Derived : public Base {
              void vf1();       // virtual and overrides Base::vf1()
              void vf2(int);    // not virtual, hides Base::vf2()
              char vf3();       // error: invalid difference in return type only
              D*  vf4();        // okay: returns pointer to derived class
              A*  vf5();        // error: returns pointer to incomplete class
              void f();
          };

  _________________________
  ers to classes are not allowed.

          void g()
          {
              Derived d;
              Base* bp = &d;     // standard conversion:
                                 // Derived* to Base*
              bp->vf1();         // calls Derived::vf1()
              bp->vf2();         // calls Base::vf2()
              bp->f();           // calls Base::f() (not virtual)
              B*  p = bp->vf4(); // calls Derived::pf() and converts the
                                 //  result to B*
              Derived*  dp = &d;
              D*  q = dp->vf4(); // calls Derived::pf() and does not
                                 // convert the result to B*
              dp->vf2();         // ill-formed: argument mismatch
          }
   --end example]

6 [Note: the interpretation of the call of a virtual function depends on
  the type of the object for which it  is  called  (the  dynamic  type),
  whereas  the  interpretation of a call of a nonvirtual member function
  depends only on the type of the pointer  or  reference  denoting  that
  object (the static type) (_expr.call_).  ]

7 [Note: the virtual specifier implies membership, so a virtual function
  cannot be a nonmember (_dcl.fct.spec_) function.  Nor  can  a  virtual
  function be a static member, since a virtual function call relies on a
  specific object for determining which function to invoke.   A  virtual
  function  declared  in  one  class can be declared a friend in another
  class.  ]

8 A virtual function declared in a class shall be defined,  or  declared
  pure  (_class.abstract_)  in that class, or both; but no diagnostic is
  required (_basic.def.odr_).

9 [Example: here are some uses of virtual functions with  multiple  base
  classes:
          struct A {
              virtual void f();
          };
          struct B1 : A {   // note non-virtual derivation
              void f();
          };
          struct B2 : A {
              void f();
          };
          struct D : B1, B2 {  // D has two separate A sub-objects
          };

          void foo()
          {
              D   d;
              // A*  ap = &d; // would be ill-formed: ambiguous
              B1*  b1p = &d;
              A*   ap = b1p;
              D*   dp = &d;
              ap->f();  // calls D::B1::f
              dp->f();  // ill-formed: ambiguous
          }
  In  class  D  above there are two occurrences of class A and hence two
  occurrences of the virtual member function A::f.  The final  overrider
  of B1::A::f is B1::f and the final overrider of B2::A::f is B2::f.

10The  following  example  shows  a function that does not have a unique
  final overrider:
          struct A {
              virtual void f();
          };
          struct VB1 : virtual A {   // note virtual derivation
              void f();
          };
          struct VB2 : virtual A {
              void f();
          };
          struct Error : VB1, VB2 {  // ill-formed
          };
          struct Okay : VB1, VB2 {
              void f();
          };
  Both VB1::f and VB2::f override A::f but there is no overrider of both
  of  them in class Error.  This example is therefore ill-formed.  Class
  Okay is well formed, however, because Okay::f is a final overrider.

11The following example uses the well-formed classes from above.
          struct VB1a : virtual A {  // does not declare f
          };
          struct Da : VB1a, VB2 {
          };
          void foe()
          {
              VB1a*  vb1ap = new Da;
              vb1ap->f();  // calls VB2::f
          }
   --end example]

12Explicit qualification with  the  scope  operator  (_expr.prim_)  sup-
  presses the virtual call mechanism.  [Example:
          class B { public: virtual void f(); };
          class D : public B { public: void f(); };

          void D::f() { /* ... */ B::f(); }
  Here, the function call in D::f really does call B::f and not D::f.  ]

  10.4  Abstract classes                                [class.abstract]

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

2 An abstract class is a class that can be used only as a base class  of
  some  other  class;  no  objects  of  an abstract class can be created
  except as sub-objects of a class derived from it.  A class is abstract
  if  it has at least one pure virtual function.  [Note: such a function
  might be inherited: see below.  ] A virtual function is specified pure
  by using a pure-specifier (_class.mem_) in the function declaration in
  the class declaration.  A pure virtual function need be  defined  only
  if  explicitly  called  with  the  qualified-id  syntax (_expr.prim_).
  [Example:
          class point { /* ... */ };
          class shape {           // abstract class
              point center;
              // ...
          public:
              point where() { return center; }
              void move(point p) { center=p; draw(); }
              virtual void rotate(int) = 0;  // pure virtual
              virtual void draw() = 0;       // pure virtual
              // ...
          };
   --end example] [Note: a function declaration cannot  provide  both  a
  pure-specifier and a definition. For example,
          struct C {
                  virtual void f() { }=0; // ill-formed
          };
   --end note]

3 An abstract class shall not be used as a parameter type, as a function
  return type, or as the type of an explicit conversion.   Pointers  and
  references to an abstract class can be declared.  [Example:
          shape x;           // error: object of abstract class
          shape* p;          // ok
          shape f();         // error
          void g(shape);     // error
          shape& h(shape&);  // ok
   --end example]

4 A  class is abstract if it contains or inherits at least one pure vir-
  tual function for which the final overrider is pure  virtual.   [Exam-
  ple:
          class ab_circle : public shape {
              int radius;
          public:
              void rotate(int) {}
              // ab_circle::draw() is a pure virtual
          };

  Since  shape::draw() is a pure virtual function ab_circle::draw() is a
  pure virtual by default.  The alternative declaration,
          class circle : public shape {
              int radius;
          public:
              void rotate(int) {}
              void draw(); // a definition is required somewhere
          };
  would make class circle nonabstract and a definition of circle::draw()
  must be provided.  ]

5 [Note:  an  abstract  class  can  be  derived from a class that is not
  abstract, and a pure virtual function may override a virtual  function
  which is not pure.  ]

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