利用构造函数对类对象初始化
在类内如果数据成员是公有的则可以在类内直接进行初始化
#include<iostream>
using namespace std;
class Time
{
public :
int hour = 1;
int minute = 0;
int sec = 0;
};
int main()
{
Time t1;
cout << t1.hour << endl;
return 0;
}
或者这样
#include<iostream>
using namespace std;
class Time
{
public :
int hour;
int minute;
int sec;
};
int main()
{
Time t1 = {1, 1, 1};
cout << t1.hour << endl;
return 0;
}
上述初始化是从上到下,从左到右对应的,有顺序。
但是如果数据成员是 private 或者是 protected;就不能再这样初始化
#include<iostream>
using namespace std;
class Time
{
private:
int hour = 0; //错误,私有数据成员
};
int main()
{
Time t1 = {1}; //或者这样都是错误的
return 0;
}
一.1 , 构造函数实现数据成员的初始化
构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用,而是在建立对象时自动执行
构造函数的名字必须与类名相同。
#include<iostream>
using namespace std;
class Time
{
public:
Time()
{
hour = 0;
sec = 1;
minute = 0;
}
void set_time();
void show_time();
private:
int hour;
int minute;
int sec;
};
void Time::set_time()
{
cin >> hour >> minute >> sec;
}
void Time::show_time()
{
cout << hour << " : " << minute << " : " << sec << endl;
}
int main()
{
Time t1, t2;
t1.set_time();
t1.show_time();
t2.show_time();
return 0;
}
类外定义类内声明 Time();
Time::Time()
{
hour = 0;
sec = 1;
minute = 0;
}
构造函数不能被调用,可以使用一个类的对象初始化另一个对象
Time t1;
t1.Time(); //不能调用构造函数
Time t2 = t1; //一个类对象可以初始化另一个类对象
一.2 , 带参数的构造函数
Time(int, int, int); //类内声明
Time::Time(int h, int m, int s) //类外定义
{
hour = h;
minute = m;
sec = s;
}
Time t1(5, 5, 5); //传参
Time(int h, int m, int s) //类内定义
{
hour = h;
minute = m;
sec = s;
}
一.3,用参数初始化表对数据成员初始化
参数初始化表
Box::Box(int h, int w, int len):heigh(h), width(w), length(len){}
带有参数初始化表的构造函数的一般形式如下:
类名::构造函数名( [ 参数表 ] )[ :成员函数初始化表 ]
{
[ 构造函数体]
}
如果数据成员是数组,则应当在构造函数的函数体中用语句对其赋值,而不能在参数初始化表中对其初始化。
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
class Student
{
public:
Student(int n, char s,char nam[]):num(n), sex(s)
{
strcpy(name,nam);
}
void show()
{
cout << name << endl;
}
private:
int num;
char sex;
char name[20];
};
int main()
{
Student stud1(1111, 'm', "WangLin");
stud1.show();
return 0;
}
一.4,构造函数的重载
class Box
{
public:
Box();
Box(int h, int w, int len):height(h), width(w), length(len){}
private:
int height;
int width;
int length;
};
Box::Box()
{
height = 10;
width = 11;
length = 5;
}
Box(int); //有一个参数的构造函数
Box(int, int); //有两个参数的构造函数
在建立对象时不必给出实参的构造函数,成为默认构造函数(default constructor),显然无参构造函数是默认构造函数,一个类只能有一个默认构造函数。如果用户没有定义,系统会自动定义,但是它的函数体是空的,不起初始化的作用。如果你想要有初值,就需要自己初始化。
一.5,使用默认参数的构造函数
class Box
{
public:
Box(int h = 10, int w = 10, int len = 10);
private:
int height;
int width;
int length;
};
Box::Box(int h, int w, int len):height(h), width(w), length(len){}
int main ()
{
Box box1; //不传递参数
Box box2(10); //只传递一个参数
Box box3(10, 15); //传递2个参数
Box box4(10, 15, 30); //传递3个参数
}
在声明构造函数时,形参名字可以省略
Box(int = 10, int = 5, int = 6)
下面给出不能进行重载的例子
Box()
Box(int = 10, int = 5, int = 6)
原因:默认构造参数只能有一个,上面是错误的
Box()
Box(int = 10, int = 5, int = 6)
Box(int ,int)
Box box1; //是调用1还是2?
Box box2(10, 5); //是调用2还是3?
原因:在一个类中定义了一个全部是默认构造后,不能在定义重载构造函数
Box()
Box(int , int = 5, int = 6)
Box(int ,int)
Box box1(10, 5); //错误,出现歧义性
一.6,利用析构函数进行清理工作
析构函数的作用: 并不是删除对象,而是在撤销对象占用对象的内存之前完成一些清理工作,使这部分内存可以被程序分配给新的对象使用。程序设计者要事先设计好析构函数,已完成所需功能,只要对象生命期结束,程序就会自动执行函数完成这些工作
当对象的生命期结束,会自动执行析构函数、
(1) 如果在一个函数中定义了一个对象(假设是自动局部对象),当这个函数被调用结束时,对象应该被释放,在对象释放前自动执行析构函数。
(2)静态(static)局部对象在函数调用结束时对象并不释放,因此也不调析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对对象的析构函数。
(3)如果定义一个全局对象,则在程序的流程离开其作用域时(如main函数结束或调用exit函数)时,调用该全局对象的析构函数。
(4)如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数
析构函数不返回任何值,没有函数类型,也没有函数参数,不能被重载,一个函数可以有多个构造函数,但是析构函数只能有一个。
并且析构函数的用不值是释放资源,还可以用来执行“用户希望在最后一次使用对象之后所执行的任何操作”。你也可以在析构函数内写函数 调用数据。
如果用户没有定义析构函数c++ 编译系统会自动生成但是它只是徒有其名,什么操作都不进行,想让析构函数完成任何工作都必须在定义的析构函数内指定。
#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
Student(int , string , string);
~Student(); //析构函数
void display();
private:
int num;
string name;
string sex;
};
Student::Student(int n, string nam, string s)
{
num = n;
name = nam;
sex = s;
cout << "Constructor called." << endl;
}
Student::~Student()
{
cout << "Destructor called." << num << endl;
}
void Student::display()
{
cout << "number = " << num << endl;
cout << "name = " << name << endl;
cout << "sex = " << sex << endl;
}
int main(){
Student stud1(1001,"小明","man");
stud1.display();
Student stud2(1002,"小芳","woman");
stud2.display();
}
发现析构函数执行的顺序了么?
调用构造函数和析构函数的顺序
先构造的后析构,后构造的先析构
(1)如果在全局范围中定义对象(就是函数外),他的构造函数在本文件中所有函数执行前调用,但是一个程序若包含很多个文件,而不同的文件中有定义了全局对象,则他们执行构造函数的顺序不确定。他们都是在main执行完毕或调用exit函数时调用析构函数。
(2)如果定义的是局部自动对象(在函数内定义),则在建立对象时调用其构造函数。如果对象所在函数被多次调用,则每次建立对象时都要调用构造函数,在函数调用结束时,对象释放时调用析构函数。
(3)如果定义静态(static)局部对象,则只在程序第一次调用此函数定义对象时调用构造函数一次即可,在函数调用结束时对象并不释放,因此也不调用析构函数,只在main函数调用结束或exit函数结束时调用。
例子
void funtion()
{
Student stud1;
static Student stud2;
}
当调用到funtion函数时,先建立对象stud1,然后执行stud1的构造函数,然后建立对象stud2,然后执行stud2的构造函数。当funtion函数执行完后,调用stud1的析构函数,而stud2是静态局部对象在funtion结束后并不释放对象.直到整个程序结束时stud2才释放,执行析构函数。