类是对一组具有共同属性特征和行为特征的对象的抽象,它可将相关数据和这些数据的操作(函数)组合在一起。
类定义格式:
class 类名
{
public:
数据成员或成员函数
protected:
数据成员或成员函数
private:
数据成员或成员函数
};
类名:
class是声明类的关键字,类名是标识符,且在其作用域内必须是唯一的。
注:C++规定,标识符以字母(大小写均可,但区分大小写)或下划线开头,后面跟0或多个有字母、数字字符或下划线组成的字符串。
成员说明
类包括两类成员:一类是代表对象属性的数据成员;另一类是实现对象行为的成员函数。成员函数的定义不仅仅可以与声明同时在类内完成,也可以在类外完成。若在类外完成,则需用作用域‘::“符号。
访问权符
访问权符也成为访问权限或访问控制符,它规定类中说明成员的访问属性。
c++共提供三种不同的访问权符:public、protected、private。
public(共有类型):声明该成员为公有成员。表示该成员哭可以被和该类对象处在同一作用域内的任何函数使用。一般将成员函数声明为共有的访问控制。
protected(保护类型):声明该成员为保护成员。表示该成员只能被所在类中的成员函数及该类的友元函数使用。
private(私有类型):声明该成员为私有成员。表示该成员只能被所在类中的成员函数和该类的友元函数使用。
声明一个图书类:
class Book{
public://访问权限,共有成员
void inpub();//行为,成员函数的原型声明
void print();//行为,成员函数的原型声明
private://访问权限,私有成员
char title[12];//属性,数据成员
char author[10];
char publish[30];
float price;
};
【注】:
为了实现对象的行为,将一些相关的语句组织在一起,并给他们注明相应的名称,从而形成一些相对独立且方便管理和阅读的小块程序,每个小块程序都能描述一个完整的行为,这个小块程序就构成了成员函数。
成员函数的定义有两种形式:第一种是对于代码较少的成员函数,可以直接在类中定义;第二种是对于代码较多的成员函数,通常只在类中进行函数原型声明,在类外对函数进行定义,这个成员函数的定义格式如下:
返回类型 类名::函数名(参数表){//函数体}
例如上面的成员函数的定义:
void Book::inpub() {
cin >> title >> author >> publish >> price;
}
void Book::print() {
cout << title << " " << author << " " << publish << " " << price << endl;
}
在C++中声明类表示定义了一种新的数据类型,只有定义了类的对象,才真正创建了这种数据类型的物理实体。对象是封装了数据结构及可以施加在这些数据结构上操作的封装体。对象是类的实际变量,一个具体的对象是类的一个实例。
有两种方法可以定义对象:
在声明类的同时,直接定义对象。
class Book{
public://访问权限,共有成员
void input();//行为,成员函数的原型声明
void print();//行为,成员函数的原型声明
private://访问权限,私有成员
char title[12];//属性,数据成员
char author[10];
char publish[30];
float price;
}b1;//定义b1是类Book的对象
先声明类,然后使用时在定义对象,定义格式于一般变量定义格式相同:类名 对象名列表;
使用对象就是像对象发送信息,请求执行其某个方法,从而向外界提供要求的服务,格式:
对象名.成员函数名(实参表);
Book b1;
b1.input();//通过b1执行输入操作
b1.print();//通过b1执行输出操作
同类型的变量可以利用赋值运算符”=“进行赋值,对于同类型的对象也同样适用。这种赋值默认通过成员复制进行。当对象进行赋值时,对象的每个成员逐一复制给另一个对象的同一个成员。
例如平面上点的赋值。
#include "iostream"
#include "iomanip"
using namespace std;
class Point{
public:
void SetPoint(int a, int b);
void Print(){
cout << "x=" << x << setw(5) << "y=" << y << endl;
}
private:
int x, y;
};
void Point::SetPoint(int a, int b) {
x = a;
y = b;
}
int main(){
Point p1, p2;
p1.SetPoint(1, 2);
cout << "p1:" << endl;
p1.Print();
cout << "p2:" << endl;
p2.Print();
p2 = p1;
cout << "p2=p1:" << endl;
p2.Print();
return 0;
}
运行结果:
p1:
x=1 y=2
p2:
x=-873984000 y=32759
p2=p1:
x=1 y=2
【注】:
对对象进行初始化的一种方法就是编写初始化函数,然而很多用户在解决问题时,往往会忽略这些函数,以至于给朝鲜带来了隐患。为了方便对象的初始化工作,C++提供了两个特殊的成员函数,即构造函数和析构函数。构造函数的功能时在创建对象时,给数据成员赋初值,即对象的初始化。析构函数的功能时释放一个对象,在对象删除之前,用它来做一些内存释放等清理工作,它的功能于构造函数正好相反。
在类的定义中不能直接对数据成员进行初始化,要想对对象中的数据成员进行初始化,一种方法是手动调用成员函数来完成初始化,但这会给程序员带来很大的负担。另一种就是使用构造函数。它是一种特殊的成员函数,是为对象分配空间、初始化,并且在对象创建时会被系统自动执行。
定义构造函数原型的格式:类名(形参列表);
在类外定义构造函数的格式:类名::类名(形参列表){//函数语句;}
构造函数特点如下:
例如平面上点的赋值
#include "iostream"
#include "iomanip"
using namespace std;
class Point{
public:
Point(int a, int b){
x = a;
y = b;
}
void Print(){
cout << "x=" << x << setw(5) << "y=" << y << endl;
}
private:
int x, y;
};
int main(){
Point p1(1,2);
cout << "p1:" << endl;
p1.Print();
return 0;
}
【注】:
构造函数不能不带参数,例如:
class Point{
public:
Point(){x=0;y=0}
//...
private:
int x, y;
}
构造函数也可以采用构造初始化表对数据成员进行初始化,例如
class Point{
public:
Point(int a, int b):x(a),y(b){}
//构造函数初始化表对数据成员进行初始化
//...
private:
int x, y;
}
若数据成员时数组,则应该在构造函数种使用相关语句进行初始化,例如:
class Point{
public:
Point(char a[], int b):y(b){strcpy(x, strlen(a) + 1, a);}
//...
private:
char x[10];
int y;
}
析构函数时一种特殊的成员函数,当删除对象时就会被调用。也就是说,在对象的生命周期即将结束时,由系统自动调用,其目的是在系统回收对象内存之前执行结束清理工作,以便内存可被重新用于保存新对象。
定义析构函数的格式为:~类名();
析构函数的特点为:
【注】:
用户存储区空间分为三部分:程序区(代码区)、静态存储区(数据区)和动态存储区(栈区和堆区)。代码区存放程序代码,程序有奴性前就可以分配存储空间。数据区存放常量、静态变量、全局变量等。栈区存放局部变量、函数参数、函数返回值和临时变量等。堆区是程序空间种存在的一些空闲存储单元。在堆中创建的数据对象称为堆对象。当创建对象时,堆中的一些存储单元从未分配状态变为已分配状态;当删除所创建的堆对象时,这些存储单元从已分配状态又变为未分配状态。当堆对象不再使用时,应给予删除,回收所占用的动态内存。C++中使用new和delete来实现在堆内存中进行数据的动态分配和释放。
new功能时实现内存的动态分配。在程序运行过程中申请和释放的存储单元称为堆对象。申请和释放的过程称为建立和删除堆对象。
new的使用格式:
指针变量=new T;//T表示数据类型名
指针变量=new T(初值列表);
指针变量=new T[元素个数];
用new创建堆对象的格式:类名 *指针名 = new 类名([构造函数参数]);
【注】:
delete用来释放动态变量或动态数组所占的内存空间,其格式为:
delete 指针变量名;
delete []指针变量名;
动态创建类Point的对象:
#include "iostream"
using namespace std;
class Point{
public:
Point(int a, int b){
x = a;
y = b;
cout << "inside constructor" << endl;
}
~Point(){
cout << "inside destructor" << endl;
}
private:
int x, y;
};
int main(){
Point *p = new Point(1, 2);
delete p;
return 0;
}
数组的元素既可以时基本数据类型的数据,也可以是用户自定义数据类型的数据。对象数组是指每个数组元素都是对象的数组。对象数组的元素是对象,它不仅具有数据成员,而且还有成员函数。
声明对象数组的格式为:类名 数组名[下标表达式];
与基本类型的数组一样,在使用对象数组时也只能引用单个数组元素,通过对象可以方位其公有成员。对象数组的引用格式为:数组名[下标].成员函数
例如类Point
#include "iostream"
using namespace std;
class Point{
public:
Point(int a, int b){
x = a;
y = b;
}
void Print(){
cout << "(" << x << "," << y << ")" << endl;
}
private:
int x, y;
};
int main(){
Point ob[3] = {Point(1,2),Point(3,4), Point(5, 6)};
for(int i = 0; i < 3; i++){
cout << "第 " << i + 1 << " 个点的坐标为:";
ob[i].Print();
}
return 0;
}
运行结果:
第 1 个点的坐标为:(1,2)
第 2 个点的坐标为:(3,4)
第 3 个点的坐标为:(5,6)
访问一个对象既可以通过对象名访问,也可以通过对象地址访问。对象指针就是用于存放对象地址的变量,它遵循一般变量指针的各种规则,对象指针的格式为:类名 *对象指针名;
与用对象名来访问对象成员一样,使用对象指针也可以访问对象的成员,格式:对象指针名 − > -> −>成员名
例如,类Point
#include "iostream"
using namespace std;
class Point{
public:
Point(int a, int b){
x = a;
y = b;
}
void Print(){
cout << "(" << x << "," << y << ")" << endl;
}
private:
int x, y;
};
int main(){
Point ob[3] = {Point(1,2),Point(3,4), Point(5, 6)};
Point *p =ob;
for(int i = 0; p < ob + 3; p++, i++){
cout << "第 " << i + 1 << " 个点的坐标为:";
p->Print();
}
return 0;
}
运行结果:
第 1 个点的坐标为:(1,2)
第 2 个点的坐标为:(3,4)
第 3 个点的坐标为:(5,6)
this指针,即自引用指针,每当对象调用成员函数时,系统就将该对象的地址赋给this指针,这是编译器将根据this指针所指向的对象来确定应该引用哪个对象的数据成员。通常this指针在系统中时隐含地存在。
使用this指针应该注意: