C++基础第三章(使用类和对象)上篇

利用构造函数对类对象初始化

在类内如果数据成员是公有的则可以在类内直接进行初始化

#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才释放,执行析构函数。

猜你喜欢

转载自blog.csdn.net/Harington/article/details/84189510