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 publicThe optional attribute-specifier-seq appertains to the base-specifier.
class A { /* ... */ }; class B { /* ... */ }; class C { /* ... */ }; class D : public A, public B, public C { /* ... */ };
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
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(); } };
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 }
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() }
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 }
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 } };
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 }
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
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
};
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 };
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 }
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 };
shape x; // error: object of abstract class shape* p; // OK shape f(); // error void g(shape); // error shape& h(shape&); // OK
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.