类和对象的特性
一、面向对象程序设计方法概述
- C++并不是一种纯粹的面向对象的语言,而是一种基于过程和面向对象的混合型的语言。
- 在基于过程的程序中,函数是构成程序的基本部分,程序面对的是一个个函数;而在面向对象的程序中,除主函数外,其他函数基本上都是出现在“类”中的,只有通过类才能调用类中的函数,程序面对的是一个个的类和对象。
- 凡是以类对象为基本构成单位的程序称为基于对象的程序。
- 面向对象程序设计有4个主要特点:抽象、封装、继承和多态性。C++的类对象体现了抽象和封装的特性,在此基础上再利用继承和多态性,就成为真正的面向对象的程序设计。
1.1 什么是面向对象的程序设计
- 对象:Object,客观世界中的任何一个事物都可以看成一个对象。例如一个班级作为一个对象:
静态特征 | 动态特征(行为或者功能) |
---|---|
所属系和专业、学生人数、所在的教师 | 学习、开会、体育比赛 |
若要控制班级中的学生的活动,可从外部对班级发送信息(比如听到广播声就去上早操等),称为消息(message)。
- 任何一个对象都应具有两个要素,即属性(attribute)和行为(behavior)。对象是由一组属性和一组行为构成的。 比如一个数也是一个对象,它有自己的属性值,它能进行各种计算行为。一个系统中的多哥对象之间通过一定的渠道相互联系,要使某对象实现某一行为,应该向它传送相应的消息。
- 在C++中,每个对象都是由数据和函数(即操作代码)这两部分组成的。
- 封装与信息隐蔽
“封装性”(encapsulation)是面向对象的程序设计方法的一个重要的的特点。 封装两个含义:一是将有关数据和操作代码封装到一个对象里,各个对象互相之间不打扰。二是将对象中某些部分对外隐蔽,隐蔽内部细节,只留下少量接口(即类对象中的函数名),以便于外界联系,接收外界的消息。这称为 “信息隐蔽”,有利于数据安全,防止无关人员了解和修改数据。 - 抽象:作用是表示同一类事物的本质。类就是对象的抽象,而对象则是类的实例,即类的具体表现形式。
- 继承与重用:C++里的继承机制就是“软件重用(software reusability)”的思想,可以利用之前已建立好的类,大大缩短软件的开发周期。
- 多态性(polymorphism):由继承而产生的不同的派生类,向其多个对象发送同一个消息,它们所做出的反应各不相同,分别执行不同的操作。比如两个班级的学生同时听到上课铃声,但进入了不同的班级。增加了程序的灵活性。
1.2 面向对象程序设计的特点
- 把数据和有关操作封装成一个对象。
- 程序设计者的任务:一是设计所需的各种类和对象,即决定把那些数和操作封装在一起;二是考虑怎样向有关对象发送消息,以完成所需的任务。
1.3 类和对象的作用
C++对于C的改进最重要的就是增加了**类**这样一个类型。
基于过程的结构化程序设计 | 基于对象和面向对象的程序设计 |
---|---|
程序 = 算法 + 数据结构 | 对象 = (对象 + 对象 + 对象 +…) + 消息 |
消息的作用就是对对象的控制。
1.4 面向对象的软件开发
主要包括:分析、设计、编程、测试、维护,这5个部分。
二、类的声明和对象的定义
2.1 类和对象的关系
C++中对象的类型称为类(class),类代表了某一批对象的共性和特征。
类是对象的抽象,而对象是类的具体实例(instance)。
类是抽象的,不占用内存,而对象是具体的,占用存储空间。
2.2 声明类类型
结构体声明:
struct Student
{
//定义数据成员
int num;
char name[20];
char sex;
};
Student stud1,stud2;
类声明:
class Student
{
//定义三行数据成员
int num;
char name[20];
char sex;
//定义成员函数
void display()
{
cout<<"num:"<<num<<num<<ensl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl;
}
};
Student stud1,stud2;
注意:如果在类的定义中既不指定private,也不指定public,则系统就默认为是私有的。比如以上的那个class就是。
对类的声明一般形式:
class 类名
{
private:
私有的数据和成员函数;
public:
公用的数据和成员函数;
}
private
和public
称为成员访问限定符。被声明为**私有的(private)成员,只能被本类中的成员函数调用,类外不能调用。被声明为公有的(public)**成员,既可以被本类中的成员函数所引用,也可以被类的作用域外的其他函数引用。
这样声明的display函数就是公用的,可以被外界调用。
class Student
{
private:
int num;
char name[20];
char sex;
public:
void display()
{
cout<<"num:"<<num<<num<<ensl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl;
}
};
Student stud1,stud2;
2.3 定义对象的方法
- 先声明类类型,然后再定义对象两:
//第一种:class 类名 对象名;
class Student stud1,stud2;
//第二种:类名 对象名;
Student stud1,stud2;
- 在声明类的同时定义对象
class Student
{
private:
int num;
char name[20];
char sex;
public:
void display()
{
cout<<"num:"<<num<<num<<ensl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl;
}
}stud1,stud2;
- 不出现类名,直接定义对象(合法,但很少用)
class
{
private:
...
public:
...
}stud1,stud2;
三、类的成员函数
3.2 在类外定义成原函数
除了在类体中可以定义成员函数也可以在类的外面进行函数定义。
"::"是作用域限定符(field qualifier)或称为作用域运算符,用它声明函数是属于哪个类的。
在类的内部对成员函数作声明,而在类体外定义成员函数,这是程序设计的一种良好对的习惯。
class Student
{
private:
int num;
char name[20];
char sex;
public:
void display();
}
void Student::display() // Student::是为了限定外面这个display()函数是属于Student类中的display()函数。
{
cout<<"num:"<<num<<num<<ensl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl;
}
Student stud1,stud2;
3.3 内置成员函数
C++要求对一般的内置函数要用关键字inline
声明,但对于类内定义的成员函数,可以省略inline,因为这些成员函数已经被隐含的指定为内置函数。
如果成员函数不在类内定义,而在类外定义,系统并不把它默认为是内置函数,调用这些函数的过程和调用一般函数的过程是相同的。如果想将这些成员函数指定为内置函数,应当用inline
作显式声明。
如:
class Student
{
private:
int num;
char name[20];
char sex;
public:
inlie void display();
}
inline void Student::display() // Student::是为了限定外面这个display()函数是属于Student类中的display()函数。
{
cout<<"num:"<<num<<num<<ensl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl;
}
3.4 成员函数的存储方式
C++编译器中每个对象的存储空间只是该对象的数据成员所占用的存储空间,而不包括函数代码所占用的存储空间。
比如声明类:
class Time
{
public:
int hour;
int minute;
int sec;
void set():
cin>>a>>b>>c;
};
获取该class占用的字节数:
cout<<sizeof(Time)<<endl;//输出值为12,证明了以上观点。
如果定义了10个对象,这些对象的成员函数对应的应是同一个函数代码段,而不是10个不同的函数代码段。
因此:
- 不论成员函数在类内定义还是在类外定义,成员函数的代码段的存储方式是相同的,都不占用对象的存储空间。
- 不论是否用inline声明,成员函数的代码都不占用对象的存储空间。
四、对象成员的引用
三种
- 通多对象名和成员运算符访问对象中的成员:
对象名.成员名
stud1.num=10000;//调用数据成员
stud1.display();//调用成员函数
display();//当做调用普通函数处理
- 通过指向对象的指针访问对象中的成员
p=&t;//使得p指向对象t
class Time
{
public://公用数据成员
int hour;
int minute;
int sec;
};
Time t,*p;//定义对象t和指针变量p
p=&t;//使得p指向对象t
cout<<p->hour;//输出p指向的对象中的成员hour
- 通过对象的引用来访问对象中的成员
Time t1;
Time &t2=t1;//定义Time类引用t2,并使之初始化为t1【由于t2指向的t1的存储单元,因此t2就是t1】
cout<<t2.hour;
五、类的封装性和隐蔽性
- 类的功能实现对用户是隐蔽的,称为私有实现。这种“类的公共接口与私有实现的分离”形成了信息隐蔽。
- 一个C++程序3个组成部分:类声明头文件
.h
;类实现文件.cpp
;类的使用文件.cpp
,即主文件。 stud
是对象;display()
是方法;stud.display();
是一个发送给对象的消息。- 重点是要掌握应用
六、类和对象的简单应用
- 用类来实现输入和输出时间(时:分:秒)
#include<iostream>
using namespace std;
class Time
{
private:
int hour;
int minute;
int second;
public:
void InputTime();
void OutputTime();
};
void Time::InputTime()
{
cin>>hour>>minute>>second;
}
void Time::OutputTime()
{
cout<<hour<<':'<<minute<<':'<<second<<endl;
}
int main()
{
Time t1;
t1.InputTime();
t1.OutputTime();
return 0;
}
2. 对1的例子定义多个 类对象,并分别输入和输出个对象中的时间
注意:C中要求所有的声明必须都集中写在本模块的开头。但C++中声明可出现在程序的任何行!!
#include <iostream>
using namespace std;
class Time
{
public:
void InputTime();
void OutputTime();
private:
int hour,minute,second;
};
int main()
{
Time t1,t2;
t1.InputTime();
t1.OutputTime();
t2.InputTime();
t2.OutputTime();
return 0;
}
void Time::InputTime()
{
cin>>hour>>minute>>second;
}
void Time::OutputTime()
{
cout<<hour<<':'<<minute<<':'<<second<<endl;
}
- 找出一个整数数组中的元素的最大值
//找出输入整数数据的最大值
#include <iostream>
using namespace std;
#define len 5
class FindMaxValue
{
public:
void InputData();
void FindMax();
void OutputData();
private:
int data[len];
int max;
};
void FindMaxValue::InputData()
{
cout<<"请输入一组整数:"<<endl;
for(int i=0;i<len;i++)
cin>>data[i];
}
void FindMaxValue::FindMax()
{
max=data[0];
for(int i=0;i<len;i++)
{
if (data[i]>max)
max=data[i];
}
}
void FindMaxValue::OutputData()
{
cout<<"这组整数中最大值为:"<<max<<endl;
}
int main()
{
FindMaxValue m;
m.InputData();
m.FindMax();
m.OutputData();
return 0;
}
- 将3中的代码改写成一个多文件程序。
类定义放在arraymax.h
中;成员函数定义放在arraymax.cpp
中;主函数放在ClassPractice.cpp
中。
注意1: 在写头文件时需要注意,在开头和结尾处必须按照如下样式加上预编译语句(如下):
#ifndef CIRCLE_H
#define CIRCLE_H
//你的代码写在这里
#endif
这样做是为了防止重复编译,不这样做就有可能出错。至于CIRCLE_H
这个名字实际上是无所谓的,你叫什么都行,只要符合规范都行。原则上来说,非常建议把它写成这种形式,因为比较容易和头文件的名字对应。建议类的头文件和类的具体实现命名相同。
注意2: 类的具体实现以及主函数里需要引用这个.h文件,引用方法是#include "名字.h"
,要注意这个是双引号引用自定义的.h文件,而不是单尖括号。
具体实现步骤:
文件结构:
arraymax.h
类头文件:
#ifndef ARRAYMAX_H //预编译文件
#define ARRAYMAX_H
#define len 5
//你的代码写在这里
class FindMaxValue
{
public:
void InputData();
void FindMax();
void OutputData();
private:
int data[len];
int max;
};
#endif
arraymax.cpp
类成员定义文件
#include "iostream"
#include "arraymax.h"
using namespace std;
void FindMaxValue::InputData()
{
cout<<"请输入一组整数:"<<endl;
for(int i=0;i<len;i++)
cin>>data[i];
}
void FindMaxValue::FindMax()
{
max=data[0];
for(int i=0;i<len;i++)
{
if (data[i]>max)
max=data[i];
}
}
void FindMaxValue::OutputData()
{
cout<<"这组整数中最大值为:"<<max<<endl;
}
主函数放ClassPractice.cpp
文件内容:
#include <iostream>
#include "arraymax.h"
using namespace std;
//#define len 5
int main()
{
FindMaxValue m;
m.InputData();
m.FindMax();
m.OutputData();
return 0;
}