1. 结构化程序设计
C {\rm C} C语言使用结构化程序设计,在程序设计中满足:程序 = 数据结构 + 算法。结构化程序设计特点是:程序由全局变量以及众多相互调用的函数组成;算法以函数的形式实现,用于对数据结构进行操作。如图为结构化程序设计的程序模式:
如上图,var
是变量、sub
表示函数、黑色的线表示函数调用、红色的线表示变量调用。由图可知,在结构化程序设计中,首先是主函数调用各函数;然后各函数又调用其他函数;同时众多函数中可能存在诸多全局变量的调用。则很容易得到结构化程序设计的不足:
- 结构化程序设计中,函数和其操作的数据结构没有直观的联系;
- 随着程序规模的增加,程序逐渐难以理解,很难一下子看出来:某个数据结构由哪些程序在对其操作,某个函数在操作哪些数据结构,任何两个函数之间存在怎样的调用关系;
- 结构化程序设计中没有“封装”和“隐藏”的概念,也即是要访问某个变量时就可以直接访问。但当该变量的定义的有改变时,就要把所有访问该变量的语句找出来修改,这对于大型程序来说就会增加相当大的工作量,也不利于程序的维护和扩充;
- 难以查错,当某个数据结构出错时不能立即判断是哪个函数调用导致的;
- 无重用性,在编写程序时,发现需要增加某项功能,而在现有程序中已经实现了相同和类似的功能。但只能重写相关代码;
- 在结构化程序设计中,随着程序规模的增大,由于程序大量函数、变量之间的关系错综复杂,要抽取这部分代码,变得十分困难。
总而言之,在结构化的程序设计中,随着程序规模的不断扩大,程序会变得难以理解、难以扩充、难以查错、难以重用。而下部分介绍的面向对象的程序设计方法,能够很好地解决上述问题。
2. 面向对象程序设计
C + + {\rm C++} C++语言使用面向对象程序设计。面向对象程序设计的特点是:将某类客观事物的共同属性归纳出来,形成一个数据结构;将这类事物所能进行的行为也归纳出来,形成一个个函数,这些函数可以用来操作数据结构;然后,通过某种语法格式,将数据结构和操作该数据结构的函数“捆绑”起来,形成一个类。最后,面向对象程序设计的四个基本特点是:抽象、封装、继承、多态。后面的介绍会一步步体现出面向对象程序设计的各个特点。如图为面向对象程序设计的程序模式:
如上图,在面向对象程序设计中,程序由主函数以及众多的类组成。各类拥有自己的变量和函数,在主函数中通过生成类的对象来调用类的变量和函数。同时类与类之间也存在相互继承。由此得到,在面向对象程序设计中,满足:程序 = 类 + 类 + 类 + … + 类。下面由一个简单的例子说明面向对象程序设计方法:写一个程序,输入矩形的长和宽,输出面积和周长。
首先,用一个类表示矩形就是将矩形这个东西抽象出来。矩形的属性就是长和宽,用两个变量表示,在类中称之为成员变量;矩形的行为就是求面积和求周长,用两个函数表示,在类中称之为成员函数。二者统称为类的成员。下面是
C
+
+
{\rm C++}
C++实现代码:`
class CRectangle {
public:
int w, h;
int Area() {
return w * h;
}
int Preimeter() {
return 2 * (w + h);
}
void Init(int width, int height) {
w = width;
h = height;
}
};
上面定义了一个矩形类CRectangle
,其含有两个成员变量w
和h
分别表示矩形的宽和高;含有三个成员函数Area()
、Preimeter()
、Init()
分别用于求矩形的面积、周长和给成员变量赋值。下面是类的使用方法,根据键盘输入的矩形宽和高,自动计算器其面积和周长。
int main() {
int w, h;
CRectangle r; // 声明类的对象
cin >> w >> h;
r.Init(w, h); // 通过类的对象调用初始化函数
cout << r.Area() << endl << r.Preimeter(); // 通过类的对象调用求面积函数和求周长函数
return 0;
}
3. 使用类的成员
使用类的成员前,首先需要声明类的对象,如上面在main
函数中定义的CRectangle
类的对象r
。使用类的成员即成员变量和成员函数的方式大体分为以下三种:
(1)对象名.成员名
CRectangle r1, r2; // 声明类的对象r1和r2
r1.w = 5; // 使用r1对象给w赋值
r2.Init(5, 4); // 使用r2对象调用初始化函数给w和h赋值
需要注意一点是:Init
函数是作用在r2
上的,即Init
函数执行期间访问的w
和h
属于r2
,这和r1
的w
是相互独立的。
(2)指针→成员名
CRectangle r1, r2;
CRectangle* p1 = & r1; // 定义p1指针指向r1对象
CRectangle* p2 = & r2; // 定义p2指针指向r2对象
p1->w = 5; // 使用p1指针给w赋值
p2->Init(5, 4); // 使用p2指针调用初始化函数给w和h赋值
(3)引用名.成员名
CRectangle r;
CRectangle& rr = r; // 定义rr为对象r的引用
rr.w = 5;
rr.Init(5, 4); // 由于rr定义为r的引用,随着rr的值改变,r的值也改变
此外,类的成员函数和类的定义可以分开写,具体如下,首先定义类:
class CRectangle {
public:
int w, h;
int Area();
int Perimeter();
void Init(int width, int height);
};
然后在类外实现函数,其中CRectangle::*
表明函数不是普通函数,而是类CRectangle
的成员函数。
int CRectangle::Area() {
return w * h;
}
int CRectangle::Perimeter() {
return 2 * (w + h);
}
void CRectangle::Init(int width, int height) {
w = width;
h = height;
}
4. 总结
C
+
+
{\rm C++}
C++语言的类机制是
C
+
+
{\rm C++}
C++与
C
{\rm C}
C的根本区别所在。类机制可以使程序员随心所欲地定义自己的数据类型。类编程的过程更符合人的自然思维,因而成为实质性解决问题的方法。由于在面向对象的程序设计中,设计程序的过程就是设计类的过程。所以,只要将每个类的定义清晰化、各类间的调用条理化,就能写出一个漂亮的程序。
最后,引用一段参考中的话概括类:类是一个十分精巧的机制,为了胜任描述数据类型的全方位的能力,还添置了静态数据成员和静态成员函数,使得记录对象们的整体数据不必随单一对象数据而苟合,也不必随单一对象而捆绑操作。类甚至还添加了友元,给予了不同性质的对象之间的亲密无间性。它存在面向对象编程的争议,仿佛编程世界严密性的外在尊严,也强迫着编程内容的内在尊严:不同类型的对象之间也不应有任何情面可言。好在
C
+
+
{\rm C++}
C++法无定法,关于性能、效率的细节它从来都没有忽略过。
参考
- 北京大学公开课:程序设计与算法(三)C++面向对象程序设计.
- 钱能. C++程序设计教程(第二版)[M]. 北京:清华大学出版社,2005.9.