构造函数对类的对象进行初始化

用构造函数实现数据成员的初始化

构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户的调用,而是建立对象时自动执行。
例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<iostream>
using namespace std;
class Time{
public:
Time(){ //定义构造成员函数,函数名与类名相同
hour=0; //利用构造函数对对象中的数据成员赋初值
minute=0;
sec=0;
}
void set-time();
void show-time();
private:
int hour;
int minute;
int sec;
};

void Time::set-time(){
cin>>hour;
cin>>minute;
cin>>sec;
}

void Time::show-time(){
cout<<hour<<":"<<minute<<":"<<sec<<endl;
}

int main(){
Time t1;
t1.set-time();
t1.show-time();
Time t2;
t2.show-time();
return 0;
}

运行结果:

1
2
3
17 11 55
17:11:55
0:0:0

带参数的构造函数

构造函数首部的一般格式:

1
构造函数名(类型1 形参1,类型2 形参2,……)

定义对象的一般格式:

1
类名 对象名(实参1,实参2,……)

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>
using namespace std;
class Box{
public:
Box(int ,int ,int );
int volume();
private:
int height;
int width;
int length;
};
Box::Box(int h,int w,int l){
height=h;
width=w;
length=l;
}

int Box::volume(){
return (height*width*length);
}

int main(){
Box box1(12,25,30);
cout<<"volume :"<<box1.volume()<<endl;
Box box2(15,30,21);
cout<<"volume :"<<box2.volume()<<endl;
return 0;
}

运行结果:

1
2
volume:9000
volume:9450

用参数初始化表对数据成员初始化

一般形式:

1
2
3
类名::构造函数([参数表])[:成员初始化表]{
[构造函数体]
}

使用例:

1
2
3
4
5
6
7
8
9
10
class student{
public:
student(int n,char s,nam []):num(n),sex(s){
strcpy(name,nam);
}
private:
int num;
char sex;
char name[20];
};

析构函数进行清理工作

析构函数的作用与构造函数相反,它的名字是类名前加一个“~”符号。
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分的内存可以被程序分配给新对象使用。
析构函数不返回任何值,没有函数类型,也没有函数参数,由于没有函数参数,使用它无法被重载。一个类可以有多个构造函数,但是只能有一个析构函数。
例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<iostream>
#include<string>
using namespace std;
class student{
public:
student(int n,string nam,char s){
num=n;
name=nam;
sex=s;
cout<<"constructor called."<<endl;
}
~student(){
cout<<"destructor called."<<endl;
}
void display(){
cout<<"num:"<<num<<endl;
cout<<"name:"<<name<<endl;
cout<<"sex:"<<sex<<endl;
}
private:
int num;
string name;
char sex;
};

int main(){
student s1(101,"W",'f');
s1.display();
student s2(102,"E",'m');
s2.display();
return 0;
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
constructor called.
num:101
name:W
sex:f

constructor called.
num:102
name:E
sex:m

destructor called.
destructor called.

调用构造函数和析构函数的顺序

先构造的后析构,后构造的先析构。
相当于一个栈,先进后出。

对象数组

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>
using namespace std;
class Box{
public:
Box(int h=10,int w=12,int len=15):height(h),width(w),length(len){
}
int volume();
private:
int height;
int width;
int length;
};

int Box ::volume(){
return(height*width*length);
}

int main(){
Box a[3]={ //定义对象数组
Box(10,12,15), //调用构造函数Box,提供第一个元素的实参
Box(15,18,20), //调用构造函数Box,提供第二个元素的实参
Box(16,20,26) //调用构造函数Box,提供第三个元素的实参
};
cout<<"a[0] volume:"<<a[0].volume()<<endl;
cout<<"a[1] volume:"<<a[1].volume()<<endl;
cout<<"a[2] volume:"<<a[2].volume()<<endl;
return 0;
}

运行结果:

1
2
3
a[0] volume:1800
a[1] volume:5400
a[2] volume:8320

对象指针

指向对象的指针

一个对象存储空间的起始地址就是对象的指针。可以定义一个指针变量,用来存放对象的地址,这就是指向对象的指针变量。
一般形式:

1
类名 * 对象指针名;

例:

1
2
3
Time *pt;		//定义pt为指向Time类对象的指针变量
Time t1; //定义t1为Time类对象
pt=&t1; //将t1的起始地址赋给pt

这样,pt就是指向Time类对象的指针变量,它指向对象t1

指向对象成员的指针

对象有地址,存放对象的起始地址的指针变量就是指向对象的指针变量。对象中的成员也有地址,存放对象成员地址的指针变量就是指向对象成员的指针变量

指向对象数据成员的指针

一般形式:

1
数据类型名 * 指针变量名;

指向对象成员函数的指针

指向普通函数的指针变量:

1
类型名 (* 指针变量名)(参数表列);

指向公有成员函数的指针变量:

1
数据类型名(类名::* 指针变量名)(参数表列);

使指针变量指向一个公有成员函数:

1
指针变量名 = & 类名::成员函数名;

公用数据的保护

常对象

定义对象时加关键字const,可以指定对象为常对象
常对象必须要有初值,切之后无法改变
一般形式:

1
2
3
	类名 const 对象名[(实参表)];
也可以把const写在最左面
const 类名 对象名[(实参表)];

常数据成员

只能通过构造函数的参数初始化表对常数据成员进行初始化,任何其他函数都不能对常数据成员进行赋值。
例:

1
2
3
const int hour;
Time::Time(int h){hour=h;} //非法,不能对之赋值
Time::Time(int h):hour(h){} //通过参数初始化表对常数据成员hour初始化

常成员函数

如果将成员函数声明为常成员函数,则只能引用本类中的数据成员,而不能修改它们
声明常成员函数的一般形式:

1
类型名 函数名(参数表)const

指向对象的常指针

一般形式:

1
类名 * const 指针变量名;

使用例:

1
2
3
4
Time t1(10,12,15),t2;		//定义对象
Time * const ptr1; //const位置在指针变量名前面,指定ptr1是常指针变量
ptr1=&t1; //ptr1指向对象t1,此后不能再改变指向
ptr1=&t2; //错误,ptr1不能改变指向

指向常对象的指针变量

一般形式:

1
const 类型名 * 指针变量名;

对象的赋值和复制

赋值

一般形式:

1
对象名1=对象名2

使用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>
using namespace std;
class Box{
public:
Box(int h,int w,int len):height(h),width(w),length(len){
}
int volume();
private:
int height;
int width;
int length;
};

int Box ::volume(){
return(height*width*length);
}

int main(){
Box box1(15,30,25),box2;
cout<<"box1 volume:"<<box1.volume()<<endl;
box2=box1;
cout<<"box2 volume:"<<box2.volume()<<endl;
return 0;
}

复制

一般形式:

1
2
3
	类名 对象2(对象1);

类名 对象名1 = 对象名2//可以在一个语句中进行多个对象的复制

静态成员

静态数据成员

一般形式:

1
数据类型 类名::静态数据成员名 = 初值;

静态成员函数

静态成员函数是类的一部分而不是对象的一部分。如果要在类外调用公用的静态成员函数,要用类名和域运算符“::”
静态成员函数没有this指针,因此静态成员函数不能访问本类中的非静态成员
静态成员函数主要用来访问静态数据成员,而不访问非静态成员

类模板

一般形式:

1
类模板名 <实际类型名> 对象名(参数表);

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<iostream>
using namespace std;
template <class numtype> //声明类模板,虚拟类型名为numtype
class compare{ //类模板名为numtype
public:
compare(numtype a,numtype b){ //定义构造函数
x=a;y=b;
}
numtype max(){ //函数名为numtype
return (x>y)?x:y;
}
numtype min(){
return (x<y)?x:y;
}
private:
numtype x,y; //数据类型为numtype
};

int main(){
compare <int > cmp1(3,7); //定义对象cmp1,用于两个整数的对比
cout<<"max:"<<cmp1.max()<<endl;
cout<<"min:"<<cmp1.min()<<endl;

compare <float> cmp2(45.78,93.6); //定义对象cmp2,用于两个浮点型的对比
cout<<"max:"<<cmp2.max()<<endl;
cout<<"min:"<<cmp2.min()<<endl;

compare<char> cmp3('a','A'); //定义对象cmp3,用于两个字符的对比
cout<<"max:"<<cmp3.max()<<endl;
cout<<"min:"<<cmp3.min()<<endl;
return 0;
}

运行结果:

1
2
3
4
5
6
7
8
max:7
min:3

max:93.6
min:45.78

max:a
min:A