2020-10-12

C++语言程序设计复习(二)

四、类与对象

抽象

面向对象方法中的抽象,是指对具体问题(对象)进行概括,抽出一类对象的公共性质并加以描述的过程。
抽象包括两个方面:数据抽象和行为抽象。
举例一:抽象后的时钟属性描述如下:

// 对时钟进行抽象
// 数据抽象
int hour,int minute,int second
// 功能抽象
showTime(),setTime()

举例二:抽象后的人的属性描述如下:

// 对人进行抽象
// 共同的属性:姓名、性别、年龄等用变量来表示
string name,string sex,int age
// 共同的行为:吃饭、行走等生物性行为,以及工作、学习等社会性行为
eat(),walk(),work(),study()

封装

封装就是将抽象得到的数据和行为相结合,形成一个有机的整体,也就是将数据与操作数据的函数代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
举例一:在抽象的基础上,将时钟的数据和功能封装起来构成一个时钟类

// 时钟类的定义
class Clock		//class关键字 类名
{				//边界
public:			//外部接口
	void setTime(int newH, int newM, int newS);	//行为,代码成员
	void showTime();	//行为,代码成员
private//特定的访问权限
	int hour, minute, second;	//属性,数据成员
};	//边界

继承

C++中提供了类的继承机制,允许程序员在保持原有类特性的基础上,进行更详细、更具体的说明。(例如:人按照职业划分,人又分为学生、教师、工程师、医生等,每一类人又有各自的特殊属性和行为。详细的说,学生具有专业、年级等特殊属性和升级、毕业等特殊行为。)

多态

多态性是指一段程序能够处理多种类型对象的能力。在C++语言中,这种多态性可以通过强制多态、重载多态、类型参数化多态、包含多态4种形式来实现。(详见后章,在此处出现只是为了保持知识体系的完整性。)

类与对象

在面向对象程序设计过程中,程序模块是由类构成的。类是对逻辑上相关的函数与数据的封装,它是对问题的抽象描述。

// 类的定义
class 类名称
{
public:
	外部接口
protected:
	保护型成员
private:
	私有成员
};
类成员的访问控制

访问控制属性可以有以下三种:公有类型(public)、私有类型(private)和保护类型(protect)。
公有类型成员定义了类的外部接口。
私有成员只能被本类的成员函数访问,来自类外部的任何访问都是非法的。
【习惯】:一般情况下,一个类的数据成员都应该声明为私有成员,这样,内部数据结构就不会对该类以外的其余部分造成影响,程序模块之间的相互作用就被降低到最小。
保护类型成员的性质和私有成员的性质相似,其差别在于继承过程中对产生的新类影响不同。
在类的定义中,具有不同属性的成员,可以按任意顺序出现。修饰访问属性的关键字也可以多次出现。但是一个成员只能具有一种访问属性。
【习惯】:在书写时通常习惯将公有类型放在最前面,这样便于阅读,因为他们是外部访问时所要了解的。

对象

声明一个对象和声明一个一般变量相同,采用以下的方式:
类名 对象名

Clock myclock;

就声明了一个时钟类型的对象myclock.

【注意】:对象所占据的内存空间只是用于存放数据成员,函数成员不在每一个对象种存储副本,每个函数的代码在内存中只占据一份空间。

定义了类及类的对象,就可以访问对象的成员,例如设置和显示对象myclock的时间值。这种访问采用的是操作符“.”。

访问数据成员的一般形式是:
对象名.数据成员名

调用函数成员的一般形式是:
对象名.函数成员名(参数表)

例如:访问类Clock的对象myclock的函数成员showTime()的方式如下:

myclock.showTime()
类的成员函数

1.成员函数的实现
函数的原型声明要写在类体中,原型说明了函数的参数表和返回值类型。而函数的具体实现是写在类定义之外的。与普通函数不同的是,实现成员函数时要指明类的名称,具体形式为:

返回值类型 类名::函数成员名(参数表)
{
函数体
}
例如:

void Clock::setTime(int newH, int mewM, int newS){
	hour = newH;
	minute = newM;
	second = newS;
}
void Clock::showTime(){
	cout<<hour<<":"<<minute<<":"<<second<<endl;
}

2.成员函数调用中的目的对象
调用一个成员函数与调用普通函数的差异在于,需要使用“.”操作符指出调用所针对的对象,这一对象在本次调用中称为目的对象。

3.带默认形参值的成员函数
类成员函数的默认值,一定要写在类定义中,而不能写在类定义之外的函数实现中。
例如:

class Clock{
public:
	void setTime(int newH=0, int newM = 0, int newS = 0);
	...
}

4.内联函数成员
内联函数的声明有两种方式:隐式声明和显式声明。
将函数体直接放在类体内,这种方法称之为隐式声明。比如,将时钟类的showTime()函数声明为内联函数,可以写作:

class Clock{
public:
	void showTime(){
		cout<<hour<<":"<<minute<<":"<<second<<endl;
	}
private:
	int hour, int minute, int second;
};

为了保证类定义的简洁,可以采用关键字inline显式声明的方式,可以写作:

inline void Clock::showTime(){
	cout<<hour<<":"<<minute<<":"<<second<<endl;
}
程序实例
//4_1.cpp
# include<iostream>
using namespace std;

class Clock{
public:
	void setTime(int newH=0, int newM=0, int newS=0);
	void showTime();
private:
	int hour, minute, second;
};

void Clock::setTime(int newH, int newM, int newS){
	hour = newH;
	minute = newM;
	second = newS;
}

inline void showTime(){
	cout<<hour<<":"<<minute<<":"<<second<<endl;
}

//主函数
int main(){
	Clock myclock;
	cout<<"First time set and output:"<<endl;
	myclock.setTime();
	myclock.showTime();
	cout<<"Second time set and output:"<<endl;
	myclock.setTime(8,30,30);
	myclock.showTime();
	return 0;
}

构造函数与析构函数

在定义对象的时候进行的数据成员设置,称为对象的初始化。C++程序中的初始化和清理工作,分别由两个特殊的成员函数来完成,他们就是构造函数和析构函数。

构造函数

构造函数的作用就是在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态。
构造函数也是一个类的成员函数,除了具有一般成员函数的特征之外,还有以下特殊的性质:
1.构造函数的函数名与类名相同。
2.没有返回值
其通常被声明为公有函数。
只要类中有构造函数,编译器就会在建立新对象的地方自动插入对构造函数调用的代码,即构造函数在对象被创建的时候将被自动调用。

class Clock{
public:
	Clock(){} /*编译系统生成的隐含的默认构造函数*/
	...
};

【提示】:虽然本例中编译系统生成的隐含的构造函数不做任何事情,但有时函数体为空的构造函数并非不做任何事情,因为他还要负责基类的构造和成员对象的构造。

class Clock{
public:
	Clock(int newH, int newM, int newS); //构造函数
	void showTime();
	void setTime(int newH, int newM, int newS);
private:
	int newH, int newM, int newS;
};

//构造函数的实现
Clock::Clock(int newH, int newM, int newS){
	hour = newH;
	minute = newM;
	second = newS;
}

//主函数
int main(){
	Clock c(0,0,0);
	c.showTime();
	c.setTime(8,30,30);
	return 0;
}

这时,以下写法出错:(无形参)

Clock c2;

构造函数可以是内联函数,可以带有参数表,可以带默认的形参值,也可以重载。重载并内联的情况如下:

class Clock{
public:
	Clock(int newH, int newM, int newS){
		hour = newH;
		minute = newM;
		second = newS;
	} //构造函数
	Clock(){
		hour = 0;
		minute = 0;
		second = 0;
	} //构造函数重载
	void showTime();
	void setTime(int newH, int newM, int newS);
private:
	int newH, int newM, int newS;
};

//主函数
int main(){
	Clock c(0,0,0);
	Clock c2;
	c2.showTime();
	c.setTime(8,30,30);
	return 0;
}
复制构造函数

复制构造函数是一种特殊的构造函数,具有一般构造函数的所有特性,其形参是本类对象的引用。其作用是使用一个已经存在的对象(由复制构造函数的参数指定),去初始化同类的一个新对象。
系统自动生成的隐含的复制构造函数的功能是,把初始值对象的每个数据成员的值都复制到新建立的对象中。
复制构造函数的声明和实现的一般方法如下:

class 类名
{
public:
	类名(形参表);
	类名(类名&对象名);
	...
};
类名::类名(类名&对象名){
{
	函数体
}

举例如下:
通过水平和垂直两个方向的坐标值X和Y来确定屏幕上的一个点。点(Point)类定义如下:

class Point{
public:
	Point(int xx=0, int yy=0){ //构造函数
		x=xx;
		y=yy;
	}
	Point(Point &p); //复制构造函数
	int getX(){return x;}
	int getY(){return y;}
private:
	int x,y;
};

Point::Point(Point &p){
	x = p.getX();
	y = p.getY();
	cout<<"Calling the copy constructor"<<endl;
}

//(1)当用类的一个对象去初始化该类的另一个对象时。
int main(){
	Point a(1,2);
	Point b(a);
	Point c=a;	//与上式均能调用复制构造函数
	cout<<b.getX()<<endl;
	return 0;
}

//(2)如果函数的形参是类的对象,调用函数时,进行形参和实参结合时。
void f(Point p){
	cout<<p.getX()<<endl;
}
int main(){
	Point a(1,2);
	f(a);
	return 0;
}
//只有把对象用值传递时,才会调用复制构造函数。
//(3)如果函数的返回值是类的对象,函数执行完成返回调用者时。
Point g(){
	Point a(1,2);
	return a;
}
int main(){
	Point b;
	b = g();
	return 0;
}
析构函数

析构函数用来完成对象被删除前的一些清理工作。析构函数是在对象生存期即将结束时的时刻被自动调用的。
析构函数通常也是类的一个公有函数成员,它的名称是由类名前面加“~”构成,没有返回值,且不接收任何参数。
举例如下:

class Clock{
public:
	Clock();
	void setTime(int newH, int newM, int newS);
	void showTime();
	~Clock(){}
private:
	int hour, minute, second;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值