第六章 类和对象
class 类名
{
public:
公有数据成员和成员函数;
protected:
保护数据成员和成员函数;
private:
};
- 类的成员可以是其他类的对象,但不能以类自身的对象作为本类的成员,而类自身的指针和引用可以作为类的成员。
- 类的定义必须以分号“;”结束。
- 类与结构体的区别:没有明确指定类成员的访问权限时,c++结构体的成员是公有的,而类的成员是私有的。
访问控制
类的访问属性有:
public
protected
private
各种访问方式的功能如下表
访问控制 | 含义 | 属性 |
public | 公有成员 | 类的外部接口 |
protected | 保护成员 | 仅允许本类成员函数及派生类成员函数访问 |
private | 私有成员 | 仅允许本类成员函数访问 |
成员函数
类的成员函数是实现类的行为属性的成员。
一般将成员函数声明为函数原型,在类外具体实现成员函数。
成员函数的定义
返回值类型 类名::成员函数名(参数表)
{
函数体
}
对象
« 对象是类的实例或实体。
« 类与对象的关系,如同C++基本数据类型和该类型的变量之间的关系。
对象的定义
格式:
类名 对象名1,对象名2,...,对象名n;
定义对象是应该注意: 必须在定义了类之后,才可以定义类的对象(也即先定义类,才能定义类的对象)
class Point
{
public:
void InitPoint(float PointA_x,float PointA_y);
void Move(float New_x,float New_y);
float GetPointx();
float GetPointy();
private:
float P1_x,P1_y;
};
int main()
{
Point p1,p2;//p1,p2就是对象
}
对象成员的访问包括:
« 圆点访问形式: 对象名.公有成员
clclass CRectangle
{
public://类的访问属性
int w,h;
int Area()
{
return w*h;
}
int Perimeter()
{
return 2*(w+h);
}
void lnit(int w_,int h_)
{
w=w_;
h=h_;
}
};//必须要以分号";"结束类的定义
int main()
{
int w,h;
CRectangle r;//r是一个对象
cin>>w>>h;
r.lnit(w,h);
cout<<r.Area()<<endl<<r.Perimeter();
return 0;
}
类定义和使用时应注意:
1. 在类的定义中不能对数据成员进行初始化.
2. 类的任何成员都必须是指定访问属性,一般将数据成员定义为私有成员或保护成员,将成员函数定义为公有成员.
3. 类中的数据成员可以是C++语法规定的任意数据类型.
4. 类的成员可以是其他类的对象,称为类的组合,但不能以类自身的对象作为本类的成员.
5. 类定义完后,必须要以分号";"结束.
6. class与struct的不同:
l class中,成员缺省情况是private.
内联函数的介绍:
内联函数作用是减少频繁调用小程序的运行的时间开销
内联函数的机制 编译器在编译时,将内联函数的调用以相应代码代替
内联函数的声明 inline 函数原型
注: 内联函数仅在函数原型作一次声明
成员函数的重载问题:
成员函数可以重载
函数名相同,但参数不同,(类型不同,或者个数不同)的一组函数叫作函数重载
编译器根据不同参数的类型和个数产生调用匹配
构造函数是用于创建对象的特殊成员函数(当创建对象时,系统自动调用构造函数)
构造函数的作用是:
1. 为对象分配空间
2. 对数据成员赋初值
3. 请求其他资源
« 构造函数名与定义的类名相同
« 构造函数可以重载
« 构造函数可以有任意类型的参数,但没有返回类型
析构函数是用于取消对象的成员函数(当一个对象作用域结束时,系统自动调用析构函数)
析构函数的作用是进行对象消亡时的清理工作
没有用户定义析构函数时,系统提供缺省版本的析构函数
析构函数名为:~类名
构造函数和析构函数的原型是:
类名::类名(参数表);
类名::~类名()
默认构造函数:如果类中没有定义构造函数,系统将自动生成一个默认形式的构造函数,用于创建对象,默认构造函数形式:
类名::类名(){}
默认构造函数是一个空函数
利用构造函数创建对象有以下两种方法:
1. 利用构造函数直接创建对象,其一般形式为: 类名 对象名[(实参表)];这里的"类名"与构造函数名相同,"实参表"是为构造函数提供的实际参数.
2. 利用构造函数创建对象时,通过指针和new来实现. 其一般语法形式为: 类名*指针变量=new类名[(实参表)]; 例如: Date*date=newDate(1998,4,28); 就创建了对象(*date 1).
构造函数初始化列表(数据成员的初始化)
构造函数初始化成员有两种方法
1) 使用构造函数的函数体进行初始化
2) 使用构造函数的初始化列表进行初始化
必须使用参数初始化列表对数据成员进行初始化的几种情况
« 数据成员为常量
« 数据成员为引用类型
« 数据成员为没有无参构造函数的类的对象
类成员的初始化的顺序: 按照数据成员在类中的声明顺序进行初始化,与初始化成员列表中出现的顺序无关
构造函数的调用: 在生成对象时调用构造函数
this 指针
用类去定义对象时,系统会为每一个对象分配存储空间。如果一个类包括了数据和函数,要分别为数据和函数的代码分配存储空间。按理说,如果用同一个类定义了10个对象,那么就需要分别为10个对象的数据和函数代码分配存储单元
类的成员函数如何区分不同的实例对象的数据成员呢?
l C++为此专门设立了一个名为this的指针,用来指向不同的对象
l 一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果
需要显式引用this指针的三种情况
1. 在类的非静态成员函数中返回类对象本身或对象的引用的时候,直接使用return *this,返回本对象的地址时,return this
2. 当参数与成员变量名相同时,如this–>=x,不能写成x=x.
3. 避免对同一对象进行赋值操作,判断两个对象是否相同时,使用this指针
复制构造函数用一个已有同类对象创建新对象进行数据初始化
C++为类提供默认版本的复制构造函数,程序员可以定义用户版本的复制构造函数
语法形式
类名::类名(const 类名&引用名,…);
复制构造函数的特点:
a) 复制构造函数名与类名相同,并且也没有返回值类型
b) 复制构造函数可写在类中,也可以写在类外
c) 复制构造函数要求有一个类类型的引用参数
d) 如果没有显示定义复制构造函数,系统自动生成一个默认形式的复制构造函数
复制构造函数的调用(以下三种情况下由编译系统自动调用)
1. 声明语句中用类的一个已知对象初始化该类的另一个对象时
2. 当对象作为一个函数实参传递给函数的形参时,需要将实参对象去初始化形参对象时,需要调用复制构造函数
3. 当对象是函数的返回值时,由于需要生成一个临时对象作为函数返回结果,系统需要将临时对象的值初始化另一个对象,需要调用复制构造函数
浅复制与深复制
浅复制: 1 .在用一个对象初始化另一个对象时,只复制了数据成员,而没有复制资源,使两个对象同时指向了同一资源的复制方式称为浅复制(即:对于复杂类型的数据成员只复制了存储地址而没有复制存储内容)
2 .默认复制构造函数所进行的是简单数据复制,即浅复制
深复制: 1 .通过一个对象初始化另一个对象时,不仅复制了数据成员,也复制了资源的复制方式称为深复制
2 .自定义复制构造函数所进行的复制是浅复制
深复制构造函数必须显式定义
深复制构造函数的特点:
1 . 定义: 类名::类名([const]类名&对象名);
2 . 成员变量的处理: 对复杂类型的成员变量,使用new操作符进行空间的申请,然后进行相关的复制操作
除了类的数据成员、成员函数,还有其他函数,比如常成员和静态成员。
常成员
常数据成员是指数据成员在实例化被初始化后,其值不能改变.
在类的成员函数说明后面可以加const关键字,则该成员函数成为常量成员函数
常对象的说明形式如下:
类名 const 对象名[(参数表)];
或者 const 类名 对象名[(参数表)];(在定义常对象时必须进行初始化,而且不能被更新)
说明:
1) C++不允许直接或间接更改常对象的数据成员.
2) C++规定常对象只能调用它的常成员函数、静态成员函数、构造函数(具有公有访问权限).
常成员函数
在类中使用关键字const说明的函数为常成员函数,常成员函数的说明格式如下:
类型说明符 函数名(参数表) const;
const是函数类型的一个组成部分,因此在函数的实现部分也要带关键字const.(常成员函数不能更新对象的数据,也不能调用非const修饰的成员函数(静态成员函数、构造函数除外))
静态成员
l 类成员冠以static声明时,称为静态成员
l 静态数据成员为同类对象共享
l 静态成员函数与静态数据成员协同操作
l 静态成员不属于某一个单独的对象,而是为类的所有对象所共有
l 静态成员函数的作用不是为了对象之间的沟通,而是为了能处理静态数据成员:保证在不依赖于某个对象的情况下,访问静态数据成员(静态数据成员在定义或说明时前面加关键字static)
定义静态成员函数的格式如下:
static返回类型 静态成员函数名(实参表);
与静态数据成员类似,调用公有静态成员函数的一般格式有如下几种:
类名::静态成员函数名(实参表)
对象.静态成员函数名(实参表)
对象指针–>静态成员函数名(实参表)
一个类不但有静态数据成员,还可以有静态成员函数.
静态函数仅可以访问静态成员,或者是静态成员函数或者是静态数据成员。
友元函数
如果在本类中(类A)以外的其他地方定义了一个函数(函数B),这个函数B可以是不属于任何类的非成员函数,也可以是其他类的成员函数,在类体中用friend对其(函数B)进行声明,此函数就称为类A的友元函数。
友元函数(函数B)可以访问这个类(类A)中的私有成员
Class A
{
Private:
Int I;
friend void FriendFun(A*,int);
public:
void MemberFun(int);
};
…
Void FriendFun(A*ptr,int x)
{
Ptr->i=x;
};
Void A::MemberFun(int x)
{
i=x;
}
学会了该怎么去写程序是远远不够的,在学会写程序的同时,我们还应该养成认真仔细的好习惯,就比如定义类时,要以分号";" 作为类的定义的结束;在写系统程序时,定义一个类就调试一个类,不要等到最后把所有的程序都写完了才去调试. 一个一个的调试时,我们可以清晰方便地找到错误;一下子调试所有程序时,如果有很多错误,你可能都不知道错误之处在哪,那你怎么去调程序,所以我认为在我们学习的同时,还要养成细心,认真,做事有条理的好习惯.