📄 csdn_文档中心_微软office的源代码样式规范(上) —— 绝对机密文档!!!.htm
字号:
about inheritance as a way to share code. However, one of the
most useful ways to use it is simply as a way to ensure working
polymorphism by inheriting interface only. The classic example
is to have an interface class which is entirely abstract (all
methods are pure virtual), and then one or more implementation
classes that inherit the interface and implement it in different
ways. The OLE COM model is an example of this. A COM
interface is expressed in C++ as an abstract base class, and then a
separate implementation class inherits from the interface class and
implements the interface methods for that object. Here the
inheritance is simply a convenient way to ensure that the object
speaks the exact interface it is supposed to (has the right methods
in the right order in the vtable with the right parameters and the
right return types). This is ensured by having each
implementation class inherit from the same interface class, which is
only declared once in a common header file. Note than when an
interface class implements an inherited pure virtual method, it must
redeclare it because from a language point of view, it is still
considered to 搊verride” the base method. For example:<BR>//
The interface base class provides interface only<BR>class
FooInterface<BR> {<BR>public:<BR> virtual void DoThis() =
0; // pure virtual<BR> virtual void DoThat(int i) =
0; // pure virtual<BR> };</P>
<P>// The implementation class implements the FooInterface
interface<BR>class FooImplementation: public
FooInterface<BR> {<BR>public:<BR> virtual void
DoThis();<BR> virtual void DoThat();<BR> }</P>
<P>void
FooImplementation::DoThis()<BR>{<BR> ...<BR>}<BR>...</P>
<P>The above example shows the case where the entire base class is
interface only. However, inheritance of interface only can
also happen at the level of an individual member function in a base
class which also includes some implementation. This is the
case when any member function is declared pure virtual. An
example of this is shown below with the DrawObj::Draw method.<BR>The
above example does not use inheritance to share code. However,
inheritance can also be used for this, and this is done by providing
implementations of methods in a base class that inherited classes
can use. There are two interesting cases here. If the
base class defines an implementation of a method which can either be
used or overridden, then the base method is defining an interface
with a default implementation. In this case, the method should
be defined as virtual so that any class which overrides the method
will get the right result when polymorphism is used.
Alternately, if the base class method provides an implementation of
a method which is not meant to be overridden (because it does a
standard action on data which is private to the base class), then
the base method is defining an interface and a required
implementation. In this case, the method should not be
declared virtual. The converse of this is that when inheriting
from a class, do not override any non-virtual functions because this
could lead to maintenance problems when the base class is
changed.<BR>In general, the two cases of inheritance of
implementation outlined above as well as the case of inheritance of
interface only can all be combined in a single class by having
different methods do different things. The key is to decide,
for each method, whether the goal of the base method is to provide
interface only, interface plus default implementation, or interface
plus required implementation. For example:<BR>// A base class
for drawing objects<BR>class
DrawObj<BR> {<BR>public:<BR> virtual void Draw() =
0; //
interface only<BR> virtual BOOL FHitTest(POINT pt); //
default implementation<BR> void GetBounds(RECT
*pr); // required
implementation<BR>private:<BR> Rect m_rBounds; // bounding
rectangle<BR> };</P>
<P>BOOL DrawObj::FHitTest()<BR>{<BR> return PtInRect(pt,
m_rBounds);<BR>}</P>
<P>void DrawObj::GetBounds(RECT *pr)<BR>{<BR> *pr =
m_rBounds;<BR>}</P>
<P>In this example, the Draw method is pure virtual because it is
only specifying an interface for polymorphic use. Any derived
class that can be instantiated must define the Draw method.
The FHitTest method is defining interface (for polymorphism) as well
as a default implementation. Any derived classes that don't
need non-rectangular hit-testing can just use the default
implementation (no code or declaration required), but other classes
can simply override this method and do special hit-testing.
The GetBounds method is an example of a required
implementation. The base class requires that "bounds" be
defined in the same way for all objects, and it doesn't make sense
for anyone to change it. In this case, the member does not
need to be virtual (and should not be for clarity and efficiency)
because the base class implementation is always
used.<BR>Summary:<BR> Inheritance of interface can be used for
ensuring a consistent (e.g. polymorphic) interface.<BR> An
implementation class can inherit its interface from an interface
class where the interface class has only pure virtual methods.<BR>
When using inheritance of implementation to share code in a base
class,<BR>  Use pure virtual functions to provide
interface only.<BR>  Use virtual functions to
provide interface and a default
implementation.<BR>  Use non-virtual functions to
provide interface and a required implementation.<BR>2.9.2
Inheritance vs. Containment<BR>The most common misuse of inheritance
is to view inheritance as a way to share code among 搒imilar” objects
and to use it in a context where there is no real 搃s a”
relationship. There are several ways to share code, and the
simpler technique of containment and delegation (one class contains
another and delegates the relevant functionality to it), which we抮e
all used to from traditional structured programming, works fine in
most cases. In this case, the relationship is described as 揾as
a”.<BR>The primary reason to use inheritance instead of containment
is to achieve polymorphism (in conjunction with the use of virtual
functions). The easiest way to test for an 搃s a” relationship
is to think whether polymorphism is what is desired. If so,
then inheritance could be appropriate (assuming any other practical
concerns are met). Another way to test 搃s a” vs. 揾as a” is to
ask yourself if it could make sense to have more than one of the
base class in the derived class. If so, then 揾as a”
(containment) is the right model. For example, if you were
implementing a scrolling window and you already have a scrollbar
class, you would notice that a window could have two scrollbars
(horizontal and vertical) even if you weren抰 planning on that
feature in the first version, so a window should contain (揾as”) a
scrollbar, not inherit from (搃s”) one. <BR>Even when you do
decide to use inheritance from another class, it is often the case
that you should split the original class into a base class and a
derived class and inherit only from the base class. This
allows you to split off only the stuff that is really shared.
For example, say you had a Rectangle drawing object, and now you
want an 揙val” object. You convince yourself that polymorphism
is desired (e.g. drawing and hit-testing code in the caller wants to
treat all objects the same), and that an Oval would never want two
Rectangles. Now you might decide to have the Oval inherit from
the Rectangle, but probably what you really want is to split the
Rectangle class into a base DrawingObject class and a separated
derived Rectangle class, and then Oval would inherit from
DrawingObject, not Rectangle. This allows later changes to the
Rectangle object that are specific only to it, even if this isn抰
needed now. As in the example from the previous section, the
DrawingObject base class will probably have a combination of pure
virtual methods to enforce the polymorphic interface, virtual
methods to provide a standard interface as well as a default
implementation for all 搒imple objects”, and non-virtual methods to
provide required implementation of stuff that is common to all
objects and assumed to be constant in the common code.<BR>Note that
containment forces you to use the contained object抯 public
interface, whereas inheritance allows use of protected members
also. This is another way of saying that containment is more
encapsulated than inheritance. In fact, it is often said that
inheritance breaks encapsulation because it can create dependencies
on the implementation of the base class. This is particularly
true in the case of overridden functions, where a change to the base
class might not have the right effect on all derived
classes.<BR>Summary:<BR> Be careful with inheritance vs.
containment. When in doubt, use containment.<BR> Inheritance
is an 搃s a” relationship, whereas containment is a 揾as a”
relationship.<BR> Test for 搃s a” by seeing if polymorphism is
desired or makes sense.<BR> Test for 揾as a” by asking yourself if
one class could ever use more than one of the other class.<BR>2.9.3
Multiple Inheritance<BR>We will avoid multiple inheritance
altogether. Multiple inheritance has a number of problems
including resolution of name conflicts, efficiency concerns of some
operations (functionality is hidden from you), maintenance problems,
and general confusion about what the heck is going on.<BR>If you are
building a large and complex inheritance hierarchy (to be avoided as
noted above), you might find yourself wanting multiple inheritance
to share code from two different places. In the case of literally
sharing code from two different places, this is the most dangerous
form of multiple inheritance because it leads to the trickiest
dependencies. There are other forms of multiple inheritance,
though. The safest is multiple inheritance of only interfaces
(no code from any base class), but even this has problems with
things like name conflicts. So, we will avoid it altogether.
<BR>Every time you think you need multiple inheritance, you should
consider that maybe you are over-using inheritance and you should
switch to containment in some cases. Inheritance is a silver
bullet that you have only one of. Once you抳e used it for a
given class, you need to use containment to get anything else.
Note that you can use containment as much as you want within a given
class with no problems.<BR>Summary:<BR> Don抰 use multiple
inheritance.<BR> Given only single inheritance, inheritance is a
搒ilver bullet” which you have only one of, so use it sparingly and
judiciously.<BR>3. Other C++ Features<BR>The following sections
comment on various new features of C++ that aren抰 directly related
to classes.<BR>3.1 Constants and Enumerations<BR>C++ adds the
concept of true constants to C. In C, you had the choice of
using a #define or declaring a "const" global variable.
However, the #define will not be type safe, and the const variable
takes up real memory and isn't optimized. For example:<BR>// C
alternatives:<BR>#define dxMin 0 // not type
safe<BR>const DX dxMin = 0; // just a real global variable</P>
<P>In C++, the const syntax declares a real constant of the
specified type that the compiler will type-check, and then
substitute the actual value in-line and optimize (fold constants,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -