base-clause: : base-specifier-list
base-specifier-list: base-specifier ... base-specifier-list , base-specifier ...
base-specifier: attribute-specifier-seq class-or-decltype attribute-specifier-seq virtual access-specifier class-or-decltype attribute-specifier-seq access-specifier virtual class-or-decltype
class-or-decltype: nested-name-specifier class-name nested-name-specifier template simple-template-id decltype-specifier
access-specifier: private protected public
class A { /* ... */ };
class B { /* ... */ };
class C { /* ... */ };
class D : public A, public B, public C { /* ... */ }; — end 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
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]).
class V { /* ... */ };
class A : virtual public V { /* ... */ };
class B : virtual public V { /* ... */ };
class C : public A, public B { /* ... */ };
class B { /* ... */ };
class X : virtual public B { /* ... */ };
class Y : virtual public B { /* ... */ };
class Z : public B { /* ... */ };
class AA : public X, public Y, public Z { /* ... */ }; 
struct A { int x; };                    // S(x,A) = { { A::x }, { A } }
struct B { float x; };                  // S(x,B) = { { B::x }, { B } }
struct C: public A, public B { };       // S(x,C) = { invalid, { A in C, B in C } }
struct D: public virtual C { };         // S(x,D) = S(x,C)
struct E: public virtual C { char x; }; // S(x,E) = { { E::x }, { E } }
struct F: public D, public E { };       // S(x,F) = S(x,E)
int main() {
  F f;
  f.x = 0;                              // OK, lookup finds E::x
}
struct A {
  int f();
}; 
struct B {
  int f();
}; 
struct C : A, B {
  int f() { return A::f() + B::f(); }
}; — end example
struct V {
  int v;
};
struct A {
  int a;
  static int   s;
  enum { e };
};
struct B : A, virtual V { };
struct C : A, virtual V { };
struct D : B, 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 as in D
} — end example
struct V { int f();  int x; };
struct W { int g();  int y; };
struct B : virtual V, W {
  int f();  int x;
  int g();  int y;
};
struct C : virtual V, W { };
struct D : B, C { void glorp(); };
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
struct V { };
struct A { };
struct B : A, virtual V { };
struct C : A, virtual V { };
struct D : B, C { };
void g() {
  D d;
  B* pb = &d;
  A* pa = &d;       // error, ambiguous: C's A or B's A?
  V* pv = &d;       // OK: only one V subobject
} — end example
struct B1 {
  void f();
  static void f(int);
  int i;
};
struct B2 {
  void f(double);
};
struct I1: B1 { };
struct I2: B1 { };
struct D: I1, I2, B2 {
  using B1::f;
  using B2::f;
  void g() {
    f();                        // Ambiguous conversion of this
    f(0);                       // Unambiguous (static)
    f(0.0);                     // Unambiguous (only one B2)
    int B1::* mpB1 = &D::i;     // Unambiguous
    int D::* mpD = &D::i;       // Ambiguous conversion
  }
}; — end 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
struct A { virtual void f(); };
struct B : A { };
struct C : A { void f(); };
struct D : B, C { };  // OK: A::f and C::f are the final overriders
                      // for the B and C subobjects, respectively
 — end example
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.
struct B {
  virtual void f() const final;
};
struct D : B {
  void f() const;     // error: D::f attempts to override final B::f
}; — end example
struct B {
  virtual void f(int);
};
struct D : B {
  virtual void f(long) override;  // error: wrong signature overriding B::f
  virtual void f(int) override;   // OK
}; — end 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();     // OK: returns pointer to derived class
    A*   vf5();     // error: returns pointer to incomplete class
    void f();
};
void g() {
  Derived d;
  Base* bp = &d;                // standard conversion:
                                // Derived* to Base*
  bp->vf1();                    // calls Derived::vf1()
  bp->vf2();                    // calls Base::vf2()
  bp->f();                      // calls Base::f() (not virtual)
  B*  p = bp->vf4();            // calls Derived::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
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 subobjects
};
void foo() {
  D   d;
//   A*  ap = &d;                  // would be ill-formed: ambiguous
  B1*  b1p = &d;
  A*   ap = b1p;
  D*   dp = &d;
  ap->f();                      // calls D::B1::f
  dp->f();                      // 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.
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.
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 exampleshape x; // error: object of abstract class shape* p; // OK shape f(); // error void g(shape); // error shape& h(shape&); // OK— end example
class ab_circle : public shape {
  int radius;
public:
  void rotate(int) { }
  // ab_circle::draw() is a pure virtual
}; 
class circle : public shape {
  int radius;
public:
  void rotate(int) { }
  void draw();                  // a definition is required somewhere
};
would make class circle non-abstract and a definition of
circle::draw() must be provided.