第二章类及其对象的封装性
2.1类的定义
class 类名
{
private:
//私有类型数据成员和成员函数
public:
//公有类型数据成员和成员函数
protected:
//保护类型数据成员和成员函数
}
private:只允许本类的成员函数来访问,不能在类的作用域外访问。当私有成员处于类声明中的第一部分时,关键字private可以省略。
public:是类与外部的接口,任何外部函数都可以访问公有成员。
protected:保护类型成员,用于类的继承和派生。只允许本类的成员函数和派生类的成员函数来访问。
2.2类的成员函数
2.2.1成员函数的定义
返回值类型 类名::成员函数名(参数表)
{
函数体
}
例如:
class CArea
{
int x,y,area;
public:
void square(int vx,int vy);
};
void CArea::square(int vx,int vy)
{
x = vx;
y = vy;
area = vx*vy;
};
2.2.2内置成员函数
(1)隐式声明
class CArea
{
int x,y,area;
public:
void aquarea(int vx,int vy);
{
x=vx;y=vy;
area=x*y;
}
};//类的最后是有分号的
//内置函数(内联函数),
内联函数的作用:类的每项操作都是根据成员函数来实现的,在编译的时候将函数体全部替换到调用它的位置,为了保证调用完成后还能回到主函数需要消耗一些内存资源来记录调用时的状态信息,当频繁调用小的语句简单的成员函数时,为了减小开销,引入内联函数。因为它将该成员函数的代码插入在函数的每个调用处,作为函数体的内部扩展,用来避免函数调用机制所带来的开销。
虽然这种方法能够提高效率,但是如果内联函数的函数体过长,也会导致不良后果。
(2)显式声明
使用inline关键字声明成员函数
inline void CArea::square(int vc,int vy)
{
x = vx; y = vy;
area = x*y;
}
2.3对象的定义
class CDate
{
函数体
}对象名;//这跟C中的在结构体定义时声明变量一样
类名 对象名表;
例如:CDate myBirthday, *p;
使用类中的成员函数,跟C中结构体使用其中元素一样,用"."和"->"
2.4构造函数和析构函数
2.4.1构造函数
要求:(1)构造函数的函数名必须与类名相同。
(2)构造函数一般声明为public,没有返回值,因此无须定义返回类型
特点:(1)构造函数不能被继承
(2)构造函数自动调用,且只能调用一次
(3)可以重载
例如
#include<time.h>
#include<iostream.h>
class CDate
{
char datebuf[9];
char timebuf[11];
public:
CDate();
}
CDate::CDate()
{
_strdate(datebuf);//函数原型为:char * _strdate(char *),将系统日期复制到datebuf数组中
_strtime(timebuf);//将系统时间复制到timebuf数组中,系统时间的形式为:mm/dd/yy,其中 mm 是表示月
//份的两位数,dd 是表示日的两个数字,因此, yy 是年的两个数字
//例如:12/05/14代表的是2014年12月5号
}
类中的各种构造函数
class CArea
{
....
public:
CArea(){x=0;y=0;}//声明带无参数的构造函数
CArea(int rx,int ry=0)//声明带缺省参数的构造函数
CArea(float rr){r=rr;}
CArea(float rr, char *ra);
};
注意:定义多个构造函数之间,在参数的个数或类型上必须存有差异,否则会出现二义性。当出现带缺省值的构造函数时,有时参数个数不同也可能出现二义性。
例如:如果有一个构造函数为:CArea(int x),则会与CArea(int rx, int ry=0)出现二义性,如果这时系统定义对象CArea Y(2);//就无法确定调用哪个构造函数。
拷贝构造函数:
是一种特殊的构造函数,具有一般构造函数的所有特性。它的功能是将参数代表的对象逐域拷贝到新创建的对象中。通俗的说,就是可以用一个对象构造同类的另一个对象。
方法有两种:
1>缺省的拷贝构造函数(用户在定义类的时候没有提供类的拷贝构造函数)
例如:在主函数中
void main()
{
CArea s1(3,20);
CArea s2(s1);//定义s2时自动调用了缺省的拷贝构造函数
}
2>自定义拷贝构造函数
类名::类名 (const 类名 &对象名);
这里涉及深拷贝,浅拷贝的问题点击打开链接(这篇博文有讲)
2.4.2析构函数
用于释放被分配的内存空间。
特点:(1)析构函数名与类名相同,并要在前面加“~”符号;
(2)不能接受任何参数,也没有任何返回类型说明
(3)一个类只有一个析构函数,如果没有则系统会自动生成,此函数不做任何事
(4)不能重载
例如:
class String
{ //...
public:
//...
~String();//析构函数声明
};
String::~String()
{
cout<<"调用析构函数 撤销对象"<<endl;
delete str;
}
比较一下成员函数,构造函数,析构函数,
不同点:
(1)成员函数是有返回类型声明的,构造函数和析构函数是没有的
(2)构造函数可以重载,析构函数不能重载
(3)构造函数只能调用一次,析构函数可以调用多次
(4)构造函数可以有或者没有参数,析构函数没有参数
(5)形式不一样,构造函数: 类名::类名(参数/无参数){}
析构函数: 类名::~类名(){}
相同点:
(1)一般都是声明为public
2.4.3动态存储
用new来动态分配存储空间。
格式为:new <类型名> (初值列表)
特点:(1)new能自动计算要分配的类型的大小
(2)new返回的是与类型名相同类型的指针
(3)申请成功返回一个指向新分配内存区的首地址,如果失败,返回空指针
(4)new可以为普通变量、类对象、数组类型的对象申请内存空间。
例如:
new int;//根据整型变量来申请一个内存单元(int类型是4字节),返回指向这个内存单元的指针
new int(10);//返回指向4字节内存单元的指针,并且初始化为10
new int[10];//返回含有10个int类型元素的数组首地址
用delete来动态释放存储空间。
格式为:delete 指针名
例如:
char *p=new char[10];//分配空间的同时进行初始化
delete p;//释放被占用的一部分空间
delete [ ]p;//释放整个数组所占空间
(delete p和 delete [ ]p的区别使用可以看点击打开链接这篇文章,文中最后总结“一个简单的使用原则就是:new 和 delete、new[] 和 delete[] 对应使用。”)