导图社区 【 Cxx程序设计教程】第五章 类与对象
这是一篇关于【 Cxx程序设计教程】第五章 类与对象的思维导图,主要内容有面向对象的基本概念、类与对象、构造函数与析构函数、对象数组和对象指针等。
编辑于2022-12-25 17:20:31 广东Ch5 类与对象
面向对象的基本概念
面向过程的程序设计
特点
按步骤处理问题
一切编程的基础
缺点
不适合处理“无序”的问题
不适合处理大型复杂的问题
不适合软件的重用
面向对象的基本特点
抽象
对具体问题概括,提炼出公共性质的过程
对一个问题的抽象 (两个方面)
代码(行为)抽象
对象的属性或状态
数据抽象
对象的行为特征或功能
eg:对钟表的抽象
数据抽象
int Hour; //时 int Minute; //分 int Second; //秒
数据抽象
SetTime(); //显示时间 ShowTime(); //设定时间
封装
将抽象出的数据成员、代码成员相结合,将它们视为一个整体
优点
简化编程,不必了解实现细节,而只需要通过外部接口使用类的成员
增强安全性
关键字
class
继承(Ch 6)
提供了创建新类的方法
对已有类修改或扩充创建新类
新类共享被继承类的属性和行为,同时还可以扩充新的行为和数据,使之具有更具体、更完善的功能
多态(Ch 7)
事物有多种状态
不同对象(父类、子类等)对接收到同一消息的反应不同
“同一接口,多种方法”
提高程序设计的灵活性,减轻记忆负担
类与对象
类
基本概念
类相当于用户自定义的数据类型
与基本数据类型的不同之处:类还包含了对数据处理的方法
类的实例化
类→对象
对象相当于定义该类的变量
定义
说明部分 + 实现部分
说明部分:数据成员和函数成员
class 类名 { private: //私有成员(安全性最高) 成员表1; protected: //保护成员 成员表2; public: //公有成员,外部接口 成员表3; }; //分号表示类的定义结束
成员表
数据说明或函数说明
由类型说明符和变量(或函数)名称组成
类定义的关键字
class
标识符(符合标识符的命名规则)
(private、protected、public)类成员的访问控制属性顺序没有限制
实现部分:函数成员的实现
类型 类名::成员函数名(参数表) { 函数体; }
eg:定义一个类来描述时钟
类的说明
class Clock { private: int hour,minute,second; public: void setTime( int h, int m, int s); void showTime(); };
类的实现
void Clock:: setTime( int h, int m, int s) { hour=h; minute=m; second=s; } void Clock:: showTime() { cout<<hour<<”.”<<minute<<”.”<<second<<endl; }
说明
类体内的数据成员可以是基本数据类型,或构造数据类型,或其他类的对象或指向对象的指针
类体内的函数成员的定义部分一般放在类体外,函数体比较短小时可放在类体内
在类体内不能对数据成员赋初值
类成员的访问控制 (三种)
public——公有
类的公有成员允许被类之外的函数访问
定义了类的外部接口,任何一个外部的访问都必须通过这个外部接口进行
protected——保护
访问控制的程度介于private和public之间
private——私有
私有成员限定只能在类内使用
写在类体的最前面时,可以省略
默认类的成员的访问权限为私有
成员函数
定义
函数体特别短小时,可以在类体里定义
在类外定义
类型 类名::函数成员名(参数表) { 函数体 }
“::”称为作用域运算符,它指出函数成员是属于哪个类的
带默认形参值的成员函数
调用规则与普通函数相同
eg: void Clock:: setTime( int h=0, int m=0, int s=0) { hour=h; minute=m; second=s; }
setTime() 把时钟设置到午夜零点
内联成员函数
两种声明方式
隐式声明
将函数体放在类的声明中
class Clock { public : void setTime( int h, int m, int s); void showTime(){ cout<<hour<<”.”<<minute<<”.”<<second<<endl; } private: int hour,minute,second; }
显示声明
使用inline关键字
class Clock { public : void setTime( int h, int m, int s); void showTime(); private: int hour,minute,second; } inline void Clock::showTime(){ cout<<hour<<”.”<<minute<<”.”<<second<<endl; }
对象
定义
类名 对象名1,对象名2,…,对象名n ;
PS:对象所占据的内存空间只是用于存放数据成员,函数成员不在每个对象中存储副本(对象对应的函数功能是相同的),每个函数的代码在内存中只占据一份空间(被对象共享)
使用
只能直接访问公有成员
一般对象
对象名.公有数据成员名(公有成员函数名/参数表)
指向对象的指针
对象指针名->公有数据成员名(公有成员函数名/参数表)
(*对象指针名).公有数据成员名(公有成员函数名/参数表)
构造函数与析构函数
构造函数
在对象被创建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态(使之具有区别于其他对象的特征)
不能设置为常成员函数、静态成员函数、私有成员函数
只能一次性地影响对象数据成员的初值
在定义时由系统调用,其他任何函数都无法再次调用它
在对象创建时由系统自动调用
如果程序中未声明,则系统自动产生出一个默认形式的构造函数(是一个空架子,不做任何事情)
基本格式
class 类名 { public: 类名(参数表) //构造函数 { 函数体 } … };
构造函数是特殊的公有成员函数,访问权限设置为public
构造函数与类同名,且没有返回值类型,连void也不能写
构造函数可以是内联函数、重载函数、带默认形参值
实现(可写在类体外)
类名::类名(参数表) { 函数体 }
在主函数中隐含调用构造函数,将初始值作为实参
拷贝(复制)构造函数
是一种特殊的构造函数,其形参为本类的对象引用
声明
class 类名 { public : 类名(形参); //构造函数 类名(类名 &对象名); //复制构造函数 ... };
实现
类名:: 类名(类名 &对象名) { 函数体 //复制构造函数体 }
调用
用类的一个对象去初始化该类的另一个对象
Clock a(1,2,3); Clock b(a); //用对象a初始化对象b,复制构造函数被调用 Clock c=a; //用对象a初始化对象c,复制构造函数被调用
函数的形参是类的对象,调用函数时,进行形参和实参结合
void f(Clock c) { c.showTime(); } void main() { Clock a(1,2,3); f(a); //a为原本创建c }
函数的返回值是类的对象,函数执行完成返回调用者
Clock g() { Clock a(1,2,3); return a; //返回函数值时,调用复制构造函数 }
析构函数
作用
在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间
完成对象被删除前的一些清理工作
如果程序中未声明析构函数,编译器将自动产生一个默认的析构函数
也没有返回值,不能指定为void类型
类型单一只有一种
定义格式
类名:: ~类名() { 函数体; }
类名前面加上~
#include<iostream.h> class A { int a; public: A() {a=0; cout<<"无参构造\n";} A(int x) {a=x; cout<<"带参构造\n";} ~A() {cout<<"析构\n";} }; void main() { A x, y(3), t[2], *p=&x; }
输出结果: (Ax调用A()构造函数)→无参构造 (Ay(x)调用A(int(x))构造函数)→带参构造 【t[2]包含两个对象t[0]、t[1]】 (t[0])→无参构造 (t[1])→无参构造 *p=&x【只是创建指针并没有创建对象故不发生构造函数地调用】 析构→t[1] 析构→t[0] 析构→y 析构→x
构造与析构地顺序相反
对象数组和对象指针
对象数组
对象数组的每一个元素都是同一个类的对象
定义和使用
定义一维对象数组
类名 数组名[下标表达式];
使用对象数组成员的一般格式
数组名[下标].成员名
初始化
分别为每一个数组元素对象调用构造函数的过程
对象指针
用于存放对象地的变量,遵循一般的变量指针的各种规则
声明对象指针的形式
类名 * 对象指针名;
访问其成员方式
对象指针名->公有成员数据成员成员函数名(参数表)
(*对象指针名).公有()数据成员函数名(参数表)
this指针
类的对象的数据成员(静态数据成员除外)各不相同,而对象的成员函数是唯一的
this指针,用来指向不同的对象。当调用对象p的成员函数时,this指针就指向p
每个成员函数隐含一个this指针的参数
int GetX() { return x;}
声明函数 GetX() 相当于 GetX(Point * this); 调用函数 p1.GetX(); 相当于p1.GetX(&p1); 函数体中的return x; 相当于 return this->x;
系统将一个指向p1对象的指针作为函数的第一个参数传递给函数
故而成员函数的实际参数比看起来的参数多一个
静态成员
同类对象之间的数据共享
用途
同类中不同对象间的数据共享
例:总数、平均分
静态成员不属于某个对象,是为某个类的所有对象所共有
即静态成员是属于类的
两种
静态数据成员
把数据成员的存储类型说明为静态存储类型时,该类所产生的所有对象都可以共享为静态数据所分配的存储空间
在说明对象时,系统并不为静态类型道德数据成员分配存储空间
描述静态数据成员的两个步骤
在类里用关键字static声明
eg:static int count;
在类外定义和初始化
指明所属的类,初始化时前面不加static
eg:int Point::count=0;
不属于任何一个对象
只能通过类名进行访问
类名::静态成员标类
静态成员函数
无this指针
定义
static 返回类型 函数名(参数表) { 函数体}
调用
类名::静态成员函数名(参数表)
对象.静态成员函数名(参数表)
用法
类外代码可以使用类名和作用域操作符来调用静态成员函数
要遵循访问权限控制要求
静态成员函数只能引用属于该类的静态数据成员或静态成员函数
访问非静态数据成员,必须通过参数传递方式得到对象名,然后通过对象名来访问
用于访问静态成员数据 不依赖于具体对象,在没有创建对象之前就可以调用静态成员函数
友元
不同类或对象的成员函数之间、类的成员函数与一般函数之间的数据共享机制
基本概念
破坏数据封装和隐藏的机制
可以直接访问类的私有成员
尽量少使用友元
通过将Y模块声明为X模块的友元,那么Y模块能够引用到X模块中本是被隐藏的信息
分类(2种)
友元函数
在类声明中由关键字friend修饰说明的非成员函数
在它的函数体中能够通过对象访问所有成员
定义(函数f为类C的友元函数)
class C { …… friend 返回值类型 f(参数表) ; …… };
位置可以是在private或public中
参数表中的参数应该是与类的对象有关
友元类
若B类为A类的友元,则B类的所有成员都能访问A类的成员(公有、私有、保护)
定义
class A { ... ... friend class B ; … ... };
友元关系的特点 1.友元关系是单向的(A是B的友元≠B是A的友元) 2.友元关系不能传递(A是B的友元,B是C是的友元≠A是B的友元) 3.友元关系不能被继承
常类型
用const把有关数据定义为常量
使数据在一定范围共享,又保证它不被修改
常对象
定义
类名 const 对象名
const 类名 对象名
必须进行初始化,不能被更新
其数据成员在对象的整个生存期不能被改变 只能调用常成员函数
用const修饰的对象成员
常数据成员——使用const修饰的数据成员
格式
const 数据类型 成员名;
只能通过初始化列表来获得初值
常成员函数——使用const修饰的函数成员
说明格式
类型说明符 函数名(参数表)const;
const是函数类型的一个组成部分,因此在实现部分也要带const关键字
常成员函数不能更改对象的数据成员
在常成员函数调用期间,目的对象都被视为常对象
常成员函数只能读(访问)普通数据成员(输出)不能修改
const可作为重载函数的区分
若仅以const区分对成员函数道德重载,则以非const的对象调用该函数,两个重载函数都可以与之匹配,此时编译器选择最近的重载函数
#include<iostream.h> class R { public: R(int r1, int r2){R1=r1;R2=r2;} void print(); void print() const; private: int R1,R2; };
void R::print() { cout<<R1<<","<<R2<<endl; } void R::print() const { cout<<R1<<","<<R2<<endl; } void main() { R a(5,4); //a为普通的对象 a.print(); //调用void print()[调用最近的重载函数] const R b(20,52); //b为常对象 b.print(); //调用void print() const[常对象只能调用常成员函数] }
常数据成员与静态数据成员的初始化
#include<iostream> using namespace std; class A {public: A(int i); void print(); private: const int a; //常数据成员 static int b; //静态数据成员 };
int A::b=1; // 静态数据成员在类外定义和初始化 A::A(int i) :a(i) {} //常成员数据通过初始化列表来获得初值 注意:{a=i;}错! void A::print() { cout<<a<<‘\t’<<b<<endl; } void main() { A a1(2), a2(3); a1.print(); //输出结果:2 1 a2.print(); //输出结果:3 1 }