C++基于对象的程序设计
类和对象的特性
面向对象程序设计方法概述
基于过程的程序:函数是构造程序的主要部分,除了主函数只能被操作系统调用外,各函数可以互相调用。
基于对象的程序:程序的基本构成单位是类,程序面对的是一个个的类和对象。
4个主要特点:抽象、封装、继承和多态性。
对象
对象是构成系统的基本单位。
任何一个对象都应当具有两个要素:属性和行为。对象是由一种属性和一组行为构成的。
在C++中,每个对象都是由数据和函数组成,数据体现了“属性”,函数是用来对数据进行操作的,以便实现某些功能,也称之为方法。
封装和信息隐藏
可以对一个对象进行封装处理,把它的一部分属性和功能对外界屏蔽,也就是从外界是看不到的、甚至是不可知的。也就是把对象的内部实现和外部行为分割开来。
封装性:一是将有关的数据和操作代码封装在一个对象中,形成一个基本单位,各个对象之间相互独立,互不干扰。二是将对象中某些部分对外隐藏,即隐蔽其内部细节,只留下少量接口,以便和外界联系,接受外界的消息。这种对外界隐蔽的方法称为信息隐蔽。有利于数据安全,防止无关的人了解和修改数据。
抽象
抽象的过程是将有关事务的共性归纳、集中的过程。抽象的作用是表示同一类事物的本质。类是对象的抽象,而对象则是类的特例,即类的具体表现形式。
继承与重用
可以很方便的利用一个已有的类建立一个新的类。
多态性
由继承而产生的不同派生类,其对象对同一消息会作出不同的相应。多态性是面向对象程序设计的一个重要特征,能增加程序的灵活性。
特点
程序设计者的任务包括两个方面:一是设计所需的各种类和对象,即决定把哪些数据和操作封装在一起;二是考虑怎样向有关对象发送消息,以完成所需的任务。
在基于过程的结构化程序设计中:程序=算法+数据结构
在基于对象和面向对象的程序设计中:对象=算法+数据结构;程序=(对象+对象+对象+…)+ 消息
消息的作用就是对对象的控制。程序设计的关键是设计好每一个对象以及确定向这些对象发出的命令,使各对象完成相应的操作。
面向对象的软件开发步骤
- 面向对象分析
- 面向对象设计
- 面向对象编程
- 面向对象测试
- 面向对象维护
类的声明和对象的定义
类是对象的抽象,而对象是类的具体实例。
类是抽象的,不占用内存,而对象是具体的,占用存储空间。
class Student
{
int num;;
char name[20];
char sex;
void display()
{
cout<<"num:"<<num<<endl;
cout<<"name:"<<name<endl;
count<<"sex"<<sex<<endl;
}
};
Student stud1,stud2; // 定义了两个Student类的对象stud1和stud2.
但一般是把数据隐藏起来,而把成员函数作为对外界的接口。(上述声明未指定是private还是public,默认私有)
class Student
{
private:
int num;;
char name[20];
char sex;
public:
void display()
{
cout<<"num:"<<num<<endl;
cout<<"name:"<<name<endl;
count<<"sex"<<sex<<endl;
}
};
Student stud1,stud2; // 定义了两个Student类的对象stud1和stud2.
这样外界就可以调用display函数了。
private和public称为成员访问限定符。被声明为私有的成员,只能被本类中的成员函数引用,类外不能调用。被声明为公用的成员,既可以被本类中的成员函数所引用,也可以被类的作用域内的其他函数引用。
此外还有一个成员访问限定符protected(受保护的),被其声明的成员不能被类外访问,但可以被派生类的成员函数访问。
注意C++编译系统向用户提供的类库不属于C++语言的组成部分。
定义对象的方法
- 先声明类类型,然后再定义对象
- class 类名 对象名
- 类名 对象名
- 在声明类的同时定义对象
- 不出现类名,直接定义对象
类的成员函数
要注意成员函数的权限和作用域。成员函数可以访问本类对象中任何成员(包括私有的和公有的),可以引用在本作用域中有效的数据。一般是将需要被外界调用的函数指定为public,其他工具类函数指定为private,用户不能调用这些私有的工具函数。
在类外定义成员函数
class Student
{
public:
void display();
private:
int num;
string name;
char sex;
};
void Student ::display()
{
cout<<"num:"<<num<<endl;
cout<<"name:"<<name<endl;
count<<"sex"<<sex<<endl;
}
Student stud1,stud2;
"::"是作用域限定符(作用域运算符),用它声明函数是属于哪个类的。“Student ::”表示定义的display函数是Student中的display函数。
如果在作用域运算符::的前面没有类名,或者函数名前面既无类名又无作用域运算符::,如::display()或display()则表示display函数不属于任何类,这个函数不是成员函数,而是全局函数。
类函数必须先在类体中作原型声明,然后再类外定义,也就是说类体的位置应在函数定义之前,否则编译时会出错。
内置成员函数
为了减少时间开销,如果在类体中定义的成员函数中不包括循环等控制结构,C++系统自动地对它们作为内置函数来处理。也就是把函数代码嵌入程序的调用点。
C++要求对一般的内置函数要用关键字声明,但对类内定义的成员函数,可以省略inline,因为这些成员函数已被隐含的指定为内置函数。
注意:在函数的声明时或函数的定义时作inline声明均可,但如果在类体外定义inline函数,则必须将类定义和成员函数的定义都放在同一个头文件中(或写在同一个源文件中),否则编译时无法进行置换。
成员函数的存储方式
同一类的不同对象中的数据成员的值一般是不相同的,而不同对象的函数的代码是相同的,不论调用哪一个对象的函数的代码,其实调用的都是同样内容的代码。
在C++中,每个对象所占用的存储空间只是该对象的数据成员所占用的存储空间,而不包括函数代码所占用的存储空间。
需要说明:
-
不论成员函数在类内定义还是在类外定义,成员函数的代码段的存储方式是相同的,都不占用对象的存储空间。
-
不要将成员函数的这种存储方式和inline函数的概念混淆
不论是否用inline声明,成员函数的代码段都不占用对象的存储空间。inline函数只影响函数的执行效率,而与成员函数是否占用对象的存款空间无关。
-
虽然成员函数并没有放在对象的存储空间中,但从逻辑的角度,成员函数是和数据一起封装在一个对象中的,只允许本对象中成员的函数访问同一对象中的私有属性。
对象成员的引用
通过对象名和成员运算符访问对象中的成员
一般形式:对象名.成员名
不仅可以调用类外引用对象的公用数据成员,还可以调用对象的公共成员函数,但必须指出对象名。
注意在类外只能访问public成员,也只能调用公用的成员。在一个类中应当至少有一个公用的成员函数,作为对外的接口,否则就无法对对象进行任何操作。
通过指向对象的指针访问对象中的成员
class Time
{
public:
int hour;
int minute;
};
Time t,*p; //定义对象t和指针变量p
p=&t; //使p指向对象t
cout<<p->hourl //输出p指向的对象成员hour
通过对象的引用来访问对象中的成员
Time t1;
Time &t2=t1;
cout<<t2.hour;
类的封装性和信息隐藏
当接口与实现分离时,只要类的接口没有改变,对私有实现的修改不会引起程序的其他部分的修改。
在面向对象的程序设计中,往往把类的声明(其中包含成员函数的声明)放在指定的头文件中,用户如果想使用该类,只需要把有关的头文件包含进来即可。因此可以认为类声明头文件使用户使用类库的公用接口。
包含成员函数定义的文件就是类的实现,注意,类声明和函数定义使分别放在两个文件中的。
事实上,一个C++程序是由3个部分组成:
- 类声明头文件(.h)
- 类实现文件(.cpp),包括类成员函数的定义
- 类的使用文件(.cpp),即主文件
怎样使用类和对象
利用构造函数对类对象进行初始化
注意:不能在类声明中对数据成员初始化。因为类并不是一个实体,而是一种抽象类型,并不占存储空间。
如果一个类中的所有成员都是公用的,则可以在定义对象时对数据成员进行初始化。
C++提供了构造函数来处理对象的初始化。构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。
构造函数的名字必须与类名同名,而且不能任意命名,以便编译系统能够识别它,并把它作为构造函数处理。它不具有任何类型,不返回任何值。
带参构造:
demo:用构造函数为对象的数据成员赋初值。
include<iostream>
using namespace std;
class Time //声明Time类
{Public:
Time() //定义构造成员函数,函数名与类名相同
{hour=0; //利用构造函数对对象中的数据成员赋初值
minute=0;
sec=0;
}
void set_time();
void show_time();
private:
int hour;
int minute;
int sec;
};
void Time::set_time() //定义成员函数,向数据成员赋值
{cin>>hour;
cin>>minute;
cin>>sec;
}
void Time::show_time() //定义成员函数,删除数据成员的值
{
cout<<hour<<":"<<minute<<":"<<sec<<endl;
}
int main()
{
Time t1;
t1.set_time();
t1.show_time();
Time t2;
t2.set_time();
t2.show_time();
return 0;
}
有关构造函数的说明:
-
什么时候调用构造函数?在建立类对象时会自动调用构造函数。
-
构造函数没有返回值,它的作用只是对对象进行初始化。
-
构造函数不需用户调用,也不能被用户调用。
-
可以用一个类对象初始化另一个类对象。
-
在构造函数的函数体中不仅可以对数据成员赋初值,而且可以包含其他语句,例如cout语句。
-
如果用户自己没有定义构造函数,则C++系统会自动生成一个构造函数
无参构造:
希望不同的对象赋予不同的初值。这样在调用不同对象的构造函数时,从外面将不同的数据传递给构造函数,以实现不同的初始化。
demo:有两个长方柱,其高、宽、长分别为(1)12,20,25;(2)10,14,20.求它们的体积。编一个基于对象的程序,在类中用带参数的构造函数对数据成员初始化。
#include<iostream>
using namespace std;
class Box
{
Public:
Box(int, int, int);
int volume();
private:
int height;
int width;
int length;
};
Box::Box(int h,int w,int len)
{
height=h;
width=w;
length=len;
}
int Box::volume()
{
return(height*width*length);
}
int main()
{
Box box1(12,20,25);
cout<<"The volume of bo