类与对象(1)
结构体与类
结构体的扩充
C++对结构体进行了扩充,它不仅可以含有不同类型的数据,还可以含有函数,结构体的函数可以像访问结构体中的数据一样进行访问。
类的声明
声明类的方法与声明结构体的方法相似,它是一种用户定义的抽象的数据类型。类是对象的抽象,而对象是类的实例。
C++为了保护类中数据的安全,将类中的成员分为两类,私有成员(private)和公有成员(public)。私有成员只能被类内的成员函数访问,不能被类外的对象访问,公有成员既能被类内的成员函数访问,也能被类外的对象访问。
类声明的一般形式如下:
class 类名
{
[privat:]
私有数据成员和成员函数
[public:]
公有数据成员和成员函数
};
在类的声明中,若不对其成员作private或public声明,系统将其默认为私有的,类声明中还有一种protected,称为保护成员,保护成员能被类内的成员函数访问,也能被本类的派生类的成员函数访问,但不能被类外的对象访问。
类声明中三种关键字都可以按任意次序出现任意次,数据成员可以是任意数据成员,但不能用auto,register或extern进行说明。
成员函数的定义
成员函数的用法与普通函数基本是一样的,只是它属于一个类的成员,可以访问本类中的任何一个成员,其类的声明也与前文一致。
成员函数的有三种定义方式:
(1)在类声明中只给出成员函数的原型,而将成员函数的定义放在类的外部,在类外定义的一般形式是:
返回值类型 类名 ::成员函数名(参数表)
{
函数体
}
(2)将成员函数直接定义在类的内部。
此时C++编译器会将函数作为内联函数执行(隐式定义)。
(3)在类定义中只给出成员函数的原型,而将成员函数的定义放在类的外部,在类内函数原型声明前或在类外定义成员函数前冠以关键字inline(显式定义)。
对象的定义及使用
对象的定义:
(1)声明类的同时,直接定义对象,即在花括号后添加对象名表。
(2)声明类之后,使用时再定义对象,一般形式如下:
类名 对象名1,对象名2......
对象中成员的访问:
(1)通过对象名和对象选择符访问对象中的成员:
一般形式
对象名.数据成员名
对象名.成员函数名[(实参表)]
(2)通过指向对象的指针访问对象中的成员:
对指针应该使用“->”操作符
(3)通过对象的引用来访问:
与对象选择符方法相同
类的作用域和类的访问属性
公有成员不但可以被类中的成员函数访问,还可以在类外通过对象访问。
私有成员只能被类中的成员函数访问。
构造函数和析构函数
对象的初始化和构造函数
类是一种抽象的数据类型,因此不能在声明中为数据成员赋初值。
如果类中的所有成员都是公有的,则可以在定义对象时对数据成员进行初始化,如:
class Complex{
public:
double real;
double imag;
};
Complex c={1.1,2.2};
若类中包含私有或保护的成员,则不能用这种方法进行初始化。可用公有的成员函数对对象中的数据成员赋值,也可以使用构造函数进行赋值。
构造函数是一种特殊的成员函数,主要用于为对象分配空间,进行初始化。构造函数的名字必须与类名相同,不需要用户来调用,而是建立对象时自动执行的。
采用构造函数为对象赋值,主要有以下两种形式:
(1):
类名 对象名[(实参表)];
(2)
类名 *指针变量名 =new 类名 [(实参表)];
如果没有给类定义构造函数,则编译系统自动的生成一个默认的构造函数。该默认构造函数不带任何参数,只能为对象开辟数据成员储存空间,而不能给对象中的数据成员赋初值。
构造函数可以不带参数。
用成员初始化列表对数据成员初始化
一般形式如下:
类名 ::构造函数名([参数名])[:(成员初始化列表)]
{
//构造函数体
}
成员初始化列表一般形式如下:
数据成员名1(初始值1),数据成员名2(初始值2),......
注意:对于使用const修饰的数据成员,或者是引用类型的数据成员,是不允许用赋值语句直接赋值的,因此只能用成员初始化列表对其进行初始化。
数据成员按照它们在类中的声明顺序进行初始化的,与它们在成员初始化列表中列出的顺序无关。
例:
class tmp
{
private:
int a,b;
public:
tmp(int t):b(t),a(b+1){}
void show()
{
cout<<a<<' '<<b<<endl;
}
};
int main()
{
tmp t(1);
t.show();
return 0;
}
结果为:
28 1
构造函数的重载
C++允许构造函数重载。
注意:
(1)说明无参构造函数创建对象时,应使用语句"类名 对象名;",而不是"类名 对象名();"因为该声明表示一个名为对象名的普通函数。
(2)如果类中用户没有定义构造函数,则系统会自动提供一个函数体为空的默认构造函数,但只要定义了一个构造函数,则不会提供默认构造函数。
(3)对于一个对象,建立一个对象只执行其中一个构造函数。
带默认参数的构造函数
C++允许构造函数带默认参数。
注意:
(1)如果构造函数在类的声明中定义,那么默认参数应该在类中声明构造函数原型时指定,而不能在类外构造函数定义时指定,目的是为了让用户知道如何使用默认参数。
(2)如果构造函数的全部参数都指定了默认参数,那此时构造函数也属于默认构造函数,不能再同时声明无参数的默认构造函数,因为会产生二义性。
析构函数
析构函数执行与构造函数相反的任务,通常用于执行一些清理任务。
特点:
(1)函数名与类名相同,但需要在前面加'~'。
(2)不返回任何值,也不能说明类型。
(3)没有参数,因此不能被重载。
(4)撤销对象时,自动调用析构函数。
注意:
(1)每个类必须有一个析构函数,若没有显式定义一个析构函数,则会自动生成一个默认析构函数,它能完成大部分的处理任务。
(2)除了在主函数结束(或调用exit()函数)时,系统会调用析构函数外,以下情况下也会调用:
①对象被定义在函数体中,函数调用结束后,将调用析构函数。
②使用new运算符建立的对象,如用delete运算符释放时,将调用析构函数。
对象数组与对象指针
对象数组
定义对象数组与定义正常的数组的方式相似,建立一个对象数组的格式如下:
类名 数组名[下标表达式]
如果构造函数只有一个参数,则可直接在等号后的花括号中提供实参。
对象数组的元素访问与正常数组的访问方式相似,一般形式是:
数组名[下标].成员名
若构造函数有多个参数,则可通过指定实参的构造函数定义对象数组:
tmp a[3]={
tmp(1,2,3),
tmp(2,3,4),
tmp(3,4,5)
};
对象指针
定义对象指针与定义正常的指针的方式相似,例:
类名 * 对象指针名
可以通过'.'运算符来访问单个对象的成员,也可通过'->'运算符来通过指针访问对象
this指针
因为C++将函数代码储存于对象空间之外,所以C++为成员函数提供一个名为this的指针,称为自引用指针,成员函数引用数据成员时,按照this指针找到对象的数据成员。this指针是隐式使用的,它作为参数传递给成员函数。