align=center></P>- Q0 O- p. g1 m/ b8 S6 S2 ]
><B>4 </B><B>抽象</B>(Abstraction)<B></B></P>
> </P>
>除了在表述计算过程和分配对象等方面拥有方便、高效的机制以外,我们还需要一些能把握程序复杂性的设施。这即是说,我们还需要一些用于创建型别的语言机制,使得被创建的型别比低级的内建特性更能符合我们人类在解决问题时的思维方式。</P>! K5 a% q1 Y' L
> </P>, D# {1 p+ G6 y% o
><B>4</B><B>.</B><B>1 </B><B>具象型别</B>(Concrete Types)</P>
>在许多实际应用中一些“小的”抽象机制都被频繁使用。这些抽象包括字符、整形数、浮点数、复数、点、指针、坐标、数学变换、(指针,偏移量)配对、日期、时间、范围、链接、关联、结点、(数值,域)配对、盘址(disc location)、源代码地址、BCD字符、流量、线、四边形、定点数、集合数、字符串、向量以及数组等。每一个应用总会用到其中的几个,但很少会频繁使用其全部。一个典型的应用仅直接使用其中极少的几个,而会通过程序库间接的使用其中很大一部分。</P>) \* s4 M! ?( N, x% Z
>通用目的的程序设计语言的设计者不可能预见到每一个应用在细节方面的所有需求。因此,这种语言必须提供一些机制,使得用户可以自己定义像上述那样一些“小的”具象型别。设计C++的一个明确目标就是要能很好的支持对这种用户自定义数据型别的定义和有效使用。这种特性被认为是真正优雅的程序设计之基础。从实际的角度来看,简单并普适的东西总比复杂繁琐的东西好得多。</P>$ B5 s M0 A0 b
>许多具象型别都被频繁使用,但确实也有限制。因此,支持这些具象型别之构造的语言设施,是以它们的可适应性和它们在时间、空间上没有额外损耗为设计重点的。当需要更便易、更高级或者更安全的型别时,可以将其建立在那些简单、高效的具象型别之上。而反过来——在较为复杂的“高级”型别之基础上建立没有额外性能损耗的型别——却是不可能实现的。由此,那些不提供设施以支持高效的自定义具象型别的语言就需要通过特别的语言规则来提供更多的内建型别,如表、串和向量等。</P>
>关于具象型别的一个经典范例就是复数型别:</P>& i6 s+ P) t" w7 @- C2 v
>class complex{</P>
>public: // 接口</P>$ w: @. O7 i6 @1 ~! X
> // 构造函数</P>: {7 G5 y2 K, H4 E& w* p* a" F) n+ P9 g
> complex(double r, double i) { re = r; im = i; } // 由两个标量构造复数</P>( ]& S1 t' Z5 s; i: B
> complex(double r) { re = r; im = 0; } // 由一个标量构造复数</P>
> complex() { re = im = 0; } //缺省的复数:complex(0,0)</P>9 S% P3 E0 J" v! B. n+ }* K- z J
> // 用以访问复数的函数</P>0 z* _& W: i8 u9 j/ i, N. B( T
> friend complex operator + (complex, complex);</P>) l! d3 A4 ^' O/ a. O3 ]( o
> friend complex operator - (complex, complex); // 二元运算符“减”</P>
> friend complex operator - (complex); // 一元运算符“负”</P>
> friend complex operator * (complex, complex);</P>
> friend complex operator / (complex, complex);</P>2 r9 ^ Y# S7 }- H) z
> // …</P>, F" Z1 n) ?# m7 X, m
>private:</P>) {' G' j0 a1 Z
> double re, im; // 对复数概念的表述</P>
>};</P>; q! u i4 D2 t3 C* R
>这段代码定义了一个简单的复数型别。与Simula一样,C++中使用class关键字表示用户自定义型别。这里的complex类表达了复数的结构以及可以施于其上的操作集合。实现复数结构的是private(私有的)部分;这即是说,re和im只能被complex类中声明的函数访问。像这样把“对型别之表述的访问权限”限制在一个特定的函数集合之内,可以简化概念,减轻调试和测试工作的负担,并使我们可以更容易的按照需要来对型别进行其它方式的实现。</P>
>与类的名称同名的成员函数叫做构造函数。对于大部分用户自定义型别来说,构造函数是相当重要的。构造函数负责初始化对象,即建立基本的不变量(invariant),以便使成员函数可以基于此来对型别的具体表述施以适当的操作。上面例子中的complex类提供了三个构造函数:其中一个利用一个双精度浮点数(即double型别的对象)来创建复数;第二个利用两个双精度浮点数来进行创建;第三个则利用自己的缺省值来进行创建。例如:</P>" [- A+ D |* ~5 @4 D
>complex a = complex(1, 2);</P>
>complex b = 3; // 通过complex(3,0)进行初始化</P># }" h% s) K8 Q% H, O| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) | Powered by Discuz! X2.5 |