对象 object
|--属性 attribute
|--行为 behaviour
调用对象中的函数就是向该对象传送一个消息 message
封装性 encapsulation
|--一是将有关数据和操作代码封装在一个对象中,形成一个基本单位,各个对象之间相对独立,互不干扰
|--二是将对象中某些部分对外隐藏,即隐藏其内部细节,只留下少量接口,以便与外界联系,接受外界的消息,即信息隐藏 information hiding
抽象 abstraction
抽象的作用是表示同一类事物的本质。 类
继承与重用
软件重用 software reusability
多态性 polymorphism
面向过程:程序 = 数据结构 + 算法
面向对象:程序 = 对象s + 消息
—————————————————————————————————————
类class
类是对象的抽象,对象是类的具体实例(instance)
类头 class head
类体 class body
成员列表 class member list
类中成员默认是private
struct成员默认是public
class 类名
{
private:
私有数据和成员函数
public:
公用数据和成员函数
};
成员访问限定符 member access specifier
|--私有的 private 只能本类和友元类访问
|--共有的 public 开放访问
|--受保护的 protected 包括private属性和派生类访问
定义对象的方法:
类名 对象名;
Student stud1,stud2;此时为对象分配存储空间(Java中此语句的作用不同)
——————————————————————————————————————
类的成员函数
工具函数 utility function :只被本类中的成员函数调用,private
在类外定义成员函数
:: 作用域限定符,指明此函数属于哪个类
———————————————————————————————————————
对象成员的引用
三种方式:
|--成员运算符
对象名.成员名
|--指针
Time t, *p; p=&t; p->hour;
|--引用
Time t1;
Time &t2 = t1;
t2.hour;
默认参数:函数声明的默认参数覆盖定义时的默认参数
——————————————————————————————————————
类的封装性和信息隐藏
公用接口 public interface
私有实现 private implementatioon
类的公用接口与私有实现的分离 称为 信息隐藏
软件工程的一个基本原则:接口与实现相分离
当接口与实现分离时,只要类的接口没有改变,对私有实现的修改不会影响程序的其他部分
类声明和成员函数定义的分离
实际工作中,将若干个常用的功能相近的类声明集中在一起,形成类库。
类库的组成:
|--类声明头文件
|--已经编译过的成员函数的定义,它是目标文件
类库有两种:
|--标准类库
|--自定义类库
类声明头文件成为用户使用类库的有效方法和公用接口
包含成员函数定义的文件就是类的实现
类声明和函数定义分别放在两个文件中
stud.display();
stud 对象
display() 方法
stud.display(); 消息
——————————————————————————————————————
类的数据成员不能在声明类时初始化
构造函数 constructor 处理对象的初始化
建立对象是自动调用构造函数
带参数的构造函数
构造函数名(类型1 形参1, 类型2 形参2,...)
类名 对象名(实参1,实参2,...)
参数初始化表
在函数首部实现初始化,可以在类体中定义构造函数
Box::Box(int h, int w, int len):hight(h),width(w),length(len){ }
构造函数的重载
无参构造函数称为默认构造函数(default constructor) /缺省构造函数
一个类只能有一个默认构造函数
Box box1; //调用无参构造函数
Box box1(); //声明一个函数,无参,返回类型为Box
默认构造函数
在声明构造函数时指定默认值,此时形参可以省略
Box(int=10; int=10; int=10);
此时提供0 1 2 3个参数均可行,此时与函数重载矛盾
不能同时使用 构造函数的重载 和 有默认参数的构造函数。
——————————————————————————————————————
析构函数 destructor
对象生命周期结束时自动执行析构函数 在类名前加一个~
作用不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用
析构函数不能重载
作用:
|--释放资源
|--执行最后一次使用对象之后欲执行的任何操作
先构造后析构 后构造先析构 栈 针对同一存储类别
—————————————————————————————————————
对象数组
Box a[3] = {
Box(10,12,15),
Box(15,18,20),
Box(16,20,26),
};
———————————————————————————————————————
指向对象成员函数的指针
数据类型名(类名::*指针变量名)(参数列表)
指针变量名=&类名::成员函数名
void (Time::*p)(); //声明指针
p=&Time::get_time; //指针赋值 void (Time::*p) = &Time::get_time;
(t1.*p)(); //函数调用
———————————————————————————————————————
this指针
每个成员函数都包含this指针,指向本类对象
其值是当前被调用的成员函数所在的对象的起始地址
this指针是隐式使用的,作为参数被传递给成员函数
——————————————————————————————————————
公用数据的保护:
|--常对象 Time const t1(12, 34, 46);
|--常对象成员
|--常数据成员 const int hour;
|--常成员函数 void get_time( ) const; void Time::get_time( ){ }
|--指向对象的常指针 Time * const p = &t;
|--指向常对象的指针 const Time *p = &t;
|--对象的常引用 const Time &t = t1;
常对象
const 类名 对象名(形参列表)
const Time t1(10,15,36);
作用:将所有数据成员变为const
限制:所有数据成员的值不能修改
不能调用非const型的成员函数
mutable int count; //被mutable修饰的数据成员可以用声明为const的成员函数修改
常对象成员
|--常数据成员:
只能通过构造函数的参数初始化表对常数据成员进行初始化,其值不能改变
|--常成员函数:
只能引用本类中的数据成员,而不能修改它们
声明和定义后面都加const,调用时不加
常成员函数不能调用另一个非const成员函数
指向对象的常指针
类名 * const 指针变量名 = 对象地址;
指向始终不变 必须在定义时初始化
用常指针作为函数的形参,使其在函数执行过程中指针始终指向不变对象。
指向常变量的指针
const 类型名 * 指针变量
常变量只能被指向常变量指针指向
普通变量既可以被普通指针指向,也可以被指向常变量指针指向(此时其值不能修改)
普通指针 指向常变量指针
普通变量 1 1
常变量 0 1
指向常对象的指针
const 类名 * 指针变量
普通指针 指向常对象指针
普通对象 1 1
常对象 0 1
指向常对象的指针最常用于函数的形参,目的在于保护形参指针所指向的对象在函数执行过程中不被修改
当希望在调用函数时对象的值不被修改,则把形参定义为指向常对象的指针;
如果希望对象的值在程序执行过程中不被修改,则把其定义为常对象。
对象的常引用
const Time &t;//不能修改t所引用的对象
经常用常指针和常引用作为函数参数
1、数据不能被修改
2、不必建立实参拷贝
———————————————————————————————————————
对象的动态建立和释放
通过指针操作
Box * pt;
pt = new Box(12,15,18);
pt->height; //动态对象通过指针访问,主要用于动态数据结构,如链表
delete pt; //调用析构函数,释放内存
——————————————————————————————————————
对象的赋值和复制
对象的赋值:
对象1 = 对象2;//二者属于同一个类 = 运算符重载
//实现:成员复制 memberwise copy
//只针对数据成员,不能有动态分配的数据
对象的复制
Box box2(box1),//用已有对象box1去克隆出一个新对象box2
原理:复制构造函数 copy constructor 系统默认提供
Box::Box(const Box &b)
{
height=b.height;
width=b.width;
lenth=b.length;
}
另一种形式:
类名 对象名1 = 对象名2;
Box box2 = box1;
Box box2 = box1, box3 = box2;//用box1创建新的box2,用box2创建新的box3
需要对象复制的情况:
需要用一个已经存在的对象,建立一个新的对象
函数的参数为类的对象
函数返回值是类的对象
————————————————————————————————————
静态成员 在同类的多个对象之间实现数据共享
静态数据成员
以关键字static开头
静态数据成员在内存中只占一份空间
静态数据成员在所有对象之外单独开辟空间
静态数据成员属于类,可以通过类名::引用
编译时分配,程序结束后释放
静态数据成员的初始化只能在类体外进行初始化
int Box::height = 10;
数据类型 类名::静态数据成员 = 初值;
如未赋初值,自动赋值为0
静态成员函数
和普通函数本质区别:没有this指针
目的:处理静态数据成员
——————————————————————————————————————
友元 关键字friend
目的:访问类的私有成员
友元可以访问与其有好友关系的类中的私有成员
种类:
|--友元函数
|--普通函数
|--友元成员函数
|--友元类
有一函数,在类体中用friend对该函数进行声明,此函数就称为本类的友元函数
普通友元函数:
class Time
{
public:
friend void display(Time &); //进行友元函数声明
}
void display (Time &t)
{对t进行访问}
友元成员函数 步骤不能乱
class Date; //对Date类的提前引用声明
class Time
{
public:
void display(Date &); //此函数欲访问Date的私有成员
}
class Date
{
public:
friend void Time::display(Date &); //声明Time类中的display函数为本类的友元成员函数
}
void Time::display(Date &d)
{对d进行访问}
提前引用声明:在正式声明一个类之前,先声明一个类名,表示此类将在稍后声明。
提前引用声明之后,可以定义指针和引用
正式声明之后,才可以定义对象
一个函数(包括普通函数和成员函数)可以被多个类声明为“朋友”,这样就可以引用多个类中的私有数据
友元类
B类是A类的友元类:B类的函数都是A类的友元函数
一般形式:
friend 类名;
特点:
单向
不传递
弊:对封装原则的小破坏
利:数据共享,提高程序效率
关键:数据共享 与 信息隐藏 之间选择平衡
———————————————————————————————————————
类模板 template
可定义多个虚拟的类型参数
template<class 类型参数名>
template<class numtype>
class Compare
{ }; //类模板的定义 参数化的类
Compare <int> com(4,7); //对象的定义
类是对象的抽象
类模板是类的抽象
类模板外定义成员函数的形式:
template<class 虚拟函数类型>
函数类型 类模板名<虚拟类型参数>::成员函数名(函数形参列表){...}
—————————————————————————————————————
运算符重载
重载 overloading
函数重载:对一个已有的函数赋予新的含义,使之实现新的功能
一名多用
运算符重载 operator overloading
运算符重载的方法:
定义一个重载运算符的函数
运算符重载实质上是函数的重载
格式:
函数类型 operator 运算符名称 (形参列表)
{ 对运算符的重载处理 }
Complex operator+(Complex &c1, Complex &c2);
operator是关键字
operator运算符 相当于 函数名
函数 operator+ 重载了运算符 +
重载运算符的规则:
1、只能对已有的C++运算符进行重载;
2、5个不能重载的运算符:
. 成员访问运算符
.* 成员指针访问运算符
:: 域运算符
sizeof 长度运算符
?: 条件运算符
3、不能改变操作数的个数
4、不能改变优先级
5、不能改变结合性
6、不能有默认的参数
7、参数至少有一个用户自定义类对象或其引用
8、 = & 用于类对象时不必重载
9、重载运算符的功能应类似于该运算符作用于标准类型数据时所实现的功能
10、运算符重载函数可以是类的成员函数、类的友元函数、普通函数(get方法,效率低)
重载单目运算符:成员函数
重载双目运算符:友元函数
重载双目运算符:
友元函数
先搭框架,逐步扩充,由简到繁,最后完善
边编程,边调试,边扩充
重载单目运算符:
成员函数
对于自增自减运算符:如果在运算符重载函数中,增加一个int型形参,就是后置自增自减运算符函数,
此int形参仅起到标志作用
重载流插入运算符
istream& operator >> (istream&,自定义类&);
istream& operator << (ostream&,自定义类&);
只能将重载 >> 和 << 的函数作为友元函数或普通函数,不能将它们定义为成员函数
引用 reference 的重要性
1、函数形参是引用:减少时间和空间的开销
2、返回对象是引用:可以成为左值 left value,可以连续输入输出
——————————————————————————————————————
不同数据类型之间的转换
标准数据类型的转换
|--隐式转换
|--显示转换 int(9.8) C++ (int)9.8 C
构造函数
|--默认构造函数Complex()
|--初始化构造函数 Complex(double r, double i)
|--复制构造函数Complex(Complex &)
|--转换构造函数Complex(double r) //double 转为 Complex
转换构造函数只有一个形参
应用:类名(指定类型的数据)
类型转换函数 type conversion function
作用:将一个类对象转换成另一个类型的数据
应用: operator 类型名()
{实现转换的语句}
//函数名不能有返回类型,不能有参数,只能作为成员函数(否则无法自动调用)
//函数名是 operator 类型名
当需要的时候,编译系统自动调用 转换构造函数、类型转换函数(隐式调用)
类型转换函数 转换构造函数 的同时出现可能导致程序的二义性
c1 + 2.5 的两种解释
double(c1) + 2.5 返回传统数据类型 类型转换函数
c1 + Complex(2.5) 返回自定义类对象 转换构造函数 + 运算符重载
故二者不能同时出现
来源:oschina
链接:https://my.oschina.net/u/2669173/blog/645685