第二章、类和对象的特性

第二章、类和对象的特性

一、面向对象程序设计特点/思想

1、面向对象程序设计思想

面向对象程序设计模拟自然界认识和处理事物的方法,将数据和对数据的操作封装为一个相对独立的整体—对象,同类对象还可抽象出共性,形成类。一个类中的数据通常只能通过本类提供的方法进行处理,这些方法成为该类与外部的接口, 对象之间通过消息进行通信;

2、面向对象程序设计特点

(1)封装

可以对一个对象进行封装处理,把它的一部分属性和功能对外界屏蔽,把对象的内部实现和外部行为分隔开来。

(2)抽象

抽象的作用是表示同一类事物的本质。类是对象的抽象,而对象则是类的特例

(3)继承

允许在保持原有类特性的基础上,进行更具体、更详细的说明

(4)多态

由继承而产生的相关的不同的类,其对象对同一消息会做出不同的响应,增加程序的灵活性

二、类和对象

1、类和对象的定义:

类是具有相同属性和行为的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性和行为两个主要部分;

类是包含函数的自定义数据类型,它不占内存,是一个抽象的“虚”体

使用已定义的类建立对象

对象建立后占据内存,变成了一个“实”体

2、对象的建立与使用

​ 类名 对象名;

​ 对象名.属性;

​ 对象名.成员函数(参数);

3、成员的存取控制

(1)public(公有):公有成员可被与该类对象处在同一作用域内的任何函数访问。
(2)private(私有):私有成员只能被类中的成员函数及该类的友元函数访问。
(3)protected(保护):保护成员只能被类中成员或其派生类的成员函数或该类的友元函数访问。

class Stash{
	int size;
	int next;
	int *a;
protected:
	void inflate(int increase);
public:
	void initialize();
}
Stash s;
int len=s.size;//错误
s.inflate(100);//错误
s.initialize();//正确

三、构造函数和析构函数

1、构造函数——初始化

1、构造函数:
(1)系统自动调用的初始化函数
(2)函数名与类名相同
(3)无返回值
(4)公有函数
(5)可以带形参,可以被重载
calss Time{
private:
	int hour,minutesec;
public:
	Time(){
		hour=0;minute=0;sec=0;
	}
	Time(int,int,int);//声明带参数的构造函数函数;
}
Time::Time(int x,int y,int z){
	hour=x;minute=y;sec=z;
}//在类外定义带参数的构造函数
构造函数的参数初始化表:
Time::Time(int x,int y,int z):hour(x),minute(y),sec(z){}
2、委托构造
委托其他函数完成初始化

2、析构函数——对象消失时的清理工作(如释放内存)

1、析构函数:
(1)在对象消失时由系统自动调用
(2)函数名为~+类名
(3)无返回值
(4)公有函数
(5)没有任何参数,不能被重载

3、拷贝构造函数

在建立新的对象时将已存在对象的数据成员依次拷贝给新对象中对应的数据成员
拷贝构造函数的形参时本类的对象的引用
类名(类名 &对象名){
};
在对于需要动态分配内存的场合,默认的拷贝构造函数会出错
(1)浅拷贝
ch_stack::ch_stack(ch_stack &sobj){
	size=sobj.size;
	tp=sobj.tp;
	s=sobj.s;
}
(2)深拷贝
ch_stack::ch_stack(ch_stack &sobj){
	size=sobj.size;
	tp=sobj.tp;
	s=NULL;//s是一个指针
    if(size!=0){
        s=(char*)malloc(size);
        for(int i=0;i<=tp;i++){
            s[i]=sobj.s[i];
        }
    }
}

4、构造函数和析构函数的调用顺序

(1)最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用
(2)组合构造函数调用顺序:先调用内嵌对象的构造函数(按内嵌时的声明顺序,先声明者先构造)。然后调用本类的构造函数。(析构函数的调用顺序相反)

四、对象指针和对象引用

1、对象指针

对象指针指向对象存放的地址
定义与使用:
	类名 *对象指针名;
	对象指针名->数据成员;
	对象指针名->数据函数;

2、对象引用

对象引用与被引用对象共享地址空间
定义与使用:
	类名 &对象名;
	对象名.数据成员;
	对象名.数据函数;

3、动态对象

class Test{
public:
	Test(int aa){
		a = aa;
		cout<<"构造函数执行" <<endl;
	}
    ~Test(){
        cout<<"析构函数执行" <<endl;
    }
private:
    int a;
 };
int main(){
    Test *p=new Test(10);
    deete p;
    Test *p1=new Test[100];
    delete[] p1;
}

五、this指针

1、this

系统预定义指针,指向当前对象(即当前对象地址)
利用this指针明确成员函数当前操作的数据成员是属于哪个对象
this关键字是一个指向对象自己的一个常量指针,不能给this赋值
只有成员函数才有this指针,友元函数不是类的成员函数,没有this指针
this指针作用域在类成员函数内部,在类外也无法获取
this指针保证每个对象拥有自己的数据成员,但共享处理这些数据的代码

六、类之间的关系

1、类之间的关系

(1)组合
整体和部分的关系,同时存在,同时销毁
(2)聚合
包含关系,共享成员,组合的泛化
(3)关联
消息传递链,聚合的泛化
(4)依赖
短时使用关系,非永久关系

2、组合对象

(1)组合类:类中含有其他类的对象作为成员
(2)组合类的定义:先定义成员类,再定义组合类

七、友元函数

1、基本概念:

非成员函数/外部函数访问私有成员(保护成员),友元不是类的成员,但是能访问类中被隐蔽的信息,破坏了类的封装性和隐藏性

2、定义:

class CPoint2D{
private:
	float x,y;
public:
	CPoint2D(){
		x=0;y=0;
	}
	CPoint2D(float x,float y){
		this->x=x;
		this->y=y;
	}
	friend float distance(CPoint2D,CPoint2D);
}
float distance(CPoint2D p1,CPoint2D p2){
	float dx=p1.x-p2.x;
	float dy=p1.y-p2.y;
	return sqrt(dx*dx+dy*dy);
}
int main(){
	CPoint2D v0(1,1),v1(4,5);
	cout<<distance(v0,v1)<<endl;//友元函数调用时无需通过对象,即v0.diztance(v0,v1);
}

把类B的成员函数说明为类A的友元函数

3、注意点

(1)友元函数不能直接访问成员变量,但可以通过参数传递操作对象中的私有成员

(2)友元函数在类中声明,但在类外定义时无需域操作符(friend)

(3)友元函数调用时无需通过对象

4、友元类

如果A类声明为B类的友元,则将A类称为B类的友元类
若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数
class B{
	……
	friend class A;
}
(1)友元关系是非传递的:Y是X的友元,Z是Y的友元,但Z不一定是X的友元
(2)友元关系是单向的:若Y是X的友元,则Y的成员函数可以访问X的私有和保护成员,反之则不然

八、常对象和常成员函数

1、常对象

可以在定义时加关键词const,指定对象为常对象;
常对象必须要有初值;
类名 const 对象名[(实参表)];
=const 类名 对象名[(实参表)];
【例】Time const t1(12,34,46);
说明:
(1)如果一个对象被声明为常对象,则通过该对象只能调用它的常成员函数,而不能调用该对象的普通成员函数(除了由系统自动调用的隐式的构造函数和析构函数)。常对象函数是常对象唯一的对外接口。
(2)常成员函数可以访问常对象中的数据成员,但不允许修改常对象中数据成员的值。
(3)若一定要修改常对象中的数据成员,可对该数据成员声明为mutable,如mutable int c;

2、常对象成员

(1)常数据成员
常对象的数据成员都是常数据成员;
只能通过构造函数的参数初始化表对常数据成员进行初始化,任何其他函数都不能对常数据成员赋值。
const int hour;
【错误】
Time::Time(int h){
hour=h;
}
【正确】
Time::Time(int h):hour(h){} 
(2)常成员函数
常成员函数只能引用本类中的数据成员而不能修改他们。
声明/定义常成员函数:
类型名 函数名(参数表) const;

九、静态成员

(1)静态数据成员

静态数据成员的值对每个对象都是一样的
静态数据成员在内存中只占一份空间,而不是每个对象都分别为它保留一个空间。
class Box{
	public:
    	int volume();
    private:
    	static int height;//把height定义为静态数据成员
    	int width;
}
静态数据成员可以初始化,但是只能在类体外进行初始化
int Box::height=10;
数据类型 类名::静态数据成员名=初值;
静态数据成员的使用:
Box a(15,20);
(1)a.height
(2)Box::height

(2)静态成员函数

static int volume();
调用静态成员函数:
    Box::volume();
	a.volume();
静态成员函数是类的一部分而不是对象的一部分
静态成员函数没有this指针-->静态成员函数不能访问本类中的非静态成员
静态成员函数主要用来访问静态数据成员

十、对象的内存分布

(1)类只是一个类型,除静态数据成员外,在没有实例化成对象前不占任何内存
(2)对象的存储:
	数据段:全局对象,静态对象
	代码段:成员函数,静态函数等
	栈:局部对象,参数传递时的临时对象
	堆:动态内存分配
(3)类的不同对象的数据成员拥有各自独立的内存空间

十一、补充

1、建立对象指针、对象引用均没有建立对象,不调用构造函数

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值