Стандарт C++ 98 (1119566), страница 50
Текст из файла (страница 50)
]7[Note: the virtual specifier implies membership, so a virtual function cannot be a nonmember (7.1.2)function. Nor can a virtual function be a static member, since a virtual function call relies on a specificobject for determining which function to invoke. A virtual function declared in one class can be declared afriend in another class. ]8A virtual function declared in a class shall be defined, or declared pure (10.4) in that class, or both; but nodiagnostic is required (3.2).9[Example: here are some uses of virtual functions with multiple base classes:struct A {virtual void f();};170© ISO/IECISO/IEC 14882:1998(E)10 Derived classesstruct B1 : A {void f();};10.3 Virtual functions// note non-virtual derivationstruct B2 : A {void f();};struct D : B1, B2 {};void foo(){Dd;// A* ap = &d;B1* b1p = &d;A*ap = b1p;D*dp = &d;ap->f();dp->f();}// D has two separate A sub-objects// would be ill-formed: ambiguous// calls D::B1::f// ill-formed: ambiguousIn class D above there are two occurrences of class A and hence two occurrences of the virtual memberfunction A::f.
The final overrider of B1::A::f is B1::f and the final overrider of B2::A::f isB2::f.10The following example shows a function that does not have a unique final overrider:struct A {virtual void f();};struct VB1 : virtual A {void f();};// note virtual derivationstruct VB2 : virtual A {void f();};struct Error : VB1, VB2 {};// ill-formedstruct 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.
Thisexample 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 fstruct Da : VB1a, VB2 {};171ISO/IEC 14882:1998(E)© ISO/IEC10.3 Virtual functionsvoid foe(){VB1a* vb1ap = new Da;vb1ap->f();}10 Derived classes// calls VB2::f—end example]12Explicit qualification with the scope operator (5.1) suppresses 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]1The abstract class mechanism supports the notion of a general concept, such as a shape, of which onlymore concrete variants, such as circle and square, can actually be used. An abstract class can also beused to define an interface for which derived classes provide a variety of implementations.2An abstract class is a class that can be used only as a base class of some other class; no objects of anabstract class can be created except as sub-objects of a class derived from it.
A class is abstract if it has atleast one pure virtual function. [Note: such a function might be inherited: see below. ] A virtual function isspecified pure by using a pure-specifier (9.2) in the function declaration in the class declaration. A purevirtual function need be defined only if explicitly called with the qualified-id syntax (5.1). [Example:class point { /* ... */ };class shape {// abstract classpoint center;// ...public:point where() { return center; }void move(point p) { center=p; draw(); }virtual void rotate(int) = 0;// pure virtualvirtual void draw() = 0;// pure virtual// ...};—end example] [Note: a function declaration cannot provide both a pure-specifier and a definition—end note] [Example:struct C {virtual void f() { }=0;};// ill-formed—end example]3An abstract class shall not be used as a parameter type, as a function return type, or as the type of anexplicit conversion.
Pointers and references to an abstract class can be declared. [Example:shape x;shape* p;shape f();void g(shape);shape& h(shape&);// error: object of abstract class// OK// error// error// OK—end example]4A class is abstract if it contains or inherits at least one pure virtual function for which the final overrider ispure virtual. [Example:172© ISO/IECISO/IEC 14882:1998(E)10 Derived classes10.4 Abstract classesclass 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 somewherewould 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 mayoverride a virtual function which is not pure. ]6Member functions can be called from a constructor (or destructor) of an abstract class; the effect of makinga virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (ordestroyed) from such a constructor (or destructor) is undefined.173ISO/IEC 14882:1998(E)©(Blank page)174ISO/IEC© ISO/IECISO/IEC 14882:1998(E)11 Member access control11 Member access control11 Member access control1[class.access]A member of a class can be— private; that is, its name can be used only by members and friends of the class in which it isdeclared.— protected; that is, its name can be used only by members and friends of the class in which it isdeclared, and by members and friends of classes derived from this class (see 11.5).— public; that is, its name can be used anywhere without access restriction.2Members of a class defined with the keyword class are private by default.
Members of a classdefined with the keywords struct or union are public by default. [Example:class X {int a;};// X::a is private by defaultstruct S {int a;};// S::a is public by default—end example]3Access control is applied uniformly to all names, whether the names are referred to from declarations orexpressions. [Note: access control applies to names nominated by friend declarations (11.4) and usingdeclarations (7.3.3). ] In the case of overloaded function names, access control is applied to the functionselected by overload resolution. [Note: because access control applies to names, if access control is appliedto a typedef name, only the accessibility of the typedef name itself is considered. The accessibility of theentity referred to by the typedef is not considered.
For example,class A{class B { };public:typedef B BB;};void f(){A::BB x;A::B y;}// OK, typedef name A::BB is public// access error, A::B is private—end note]4It should be noted that it is access to members and base classes that is controlled, not their visibility.Names of members are still visible, and implicit conversions to base classes are still considered, when thosemembers and base classes are inaccessible. The interpretation of a given construct is established withoutregard to access control. If the interpretation established makes use of inaccessible member names or baseclasses, the construct is ill-formed.5All access controls in clause 11 affect the ability to access a class member name from a particular scope.The access control for names used in the definition of a class member that appears outside of the member’sclass definition is done as if the entire member definition appeared in the scope of the member’s class.
Inparticular, access controls apply as usual to member names accessed as part of a function return type, eventhough it is not possible to determine the access privileges of that use without first parsing the rest of thefunction declarator. Similarly, access control for implicit calls to the constructors, the conversion175ISO/IEC 14882:1998(E)© ISO/IEC11 Member access control11 Member access controlfunctions, or the destructor called to create and destroy a static data member is performed as if these callsappeared in the scope of the member’s class.
[Example:class A {typedef int I;I f();friend I g(I);static I x;};A::IA::IA::IA::IA::f()g(A::Ig(A::IA::x =// private member{ return 0; }p = A::x);p) { return 0; }0;Here, all the uses of A::I are well-formed because A::f and A::x are members of class A and g is afriend of class A. This implies, for example, that access checking on the first use of A::I must be deferreduntil it is determined that this use of A::I is as the return type of a member of class A.
]6In the definition of a member of a nested class that appears outside of its class definition, the name of themember may be qualified by the names of enclosing classes of the member’s class even if these names areprivate members of their enclosing classes. [Example:class D {class E {static int m;};};int D::E::m = 1;// OK, no access error on private E—end example]7The names in a default argument expression (8.3.6) are bound at the point of declaration, and access ischecked at that point rather than at any points of use of the default argument expression.
Access checkingfor default arguments in function templates and in member functions of class templates are performed asdescribed in 14.7.1.11.1 Access specifiers1[class.access.spec]Member declarations can be labeled by an access-specifier (clause 10):access-specifier : member-specificationoptAn access-specifier specifies the access rules for members following it until the end of the class or untilanother access-specifier is encountered. [Example:class Xintpublic:intint};{a;// X::a is private by default: class usedb;c;// X::b is public// X::c is public—end example] Any number of access specifiers is allowed and no particular order is required. [Example:struct S {int a;protected:int b;private:int c;public:int d;};176// S::a is public by default: struct used// S::b is protected// S::c is private// S::d is public© ISO/IECISO/IEC 14882:1998(E)11 Member access control11.1 Access specifiers—end example]2The order of allocation of data members with separate access-specifier labels is unspecified (9.2).3When a member is redeclared within its class definition, the access specified at its redeclaration shall be thesame as at its initial declaration.