C++类与对象

类中的构造函数和析构函数
C++中的类可以看做C语言中结构体(Struct)的升级版。结构体是一种构造数据类型,可以包含若干成员(变量),每个成员的数据类型可以不一样;可以通过结构体来定义结构体变量,每个变量拥有相同的性质。C++类也是一种构造数据类型,但是进行了一些扩展,类的成员不但可以是变量,还可以是函数;通过类定义出来的变量也有特定的称呼,叫做“对象”。
当创建一个对象时,往往需要做一些初始化工作,例如对数据成员赋值等。为了解决这个问题,C++提供了构造函数。
构造函数(Constructor)是一种特殊的成员函数,它的名字和类名相同,没有返回值,不需要用户调用(用户也不能调用),而是在创建对象时自动执行。构造函数的作用是在创建对象时进行初始化工作,最常见的就是对成员变量赋值。
实例:
#include <iostream>
using namespace std;
class Student{
private:
	char *name;
	int age;
	float score;
public:
	//声明构造函数
	Student(char *, int, float);
	//声明普通成员函数
	void say();
};
//定义构造函数
Student::Student(char *name1, int age1, float score1){
	name = name1;
	age = age1;
	score = score1;
}
//定义普通成员函数
void Student::say(){
	cout << name << "的年龄是 " << age << ",成绩是 " << score << endl;
}
int main(){
	//根据构造函数创建对象
	Student stu("小明", 15, 90.5f);  //传参形式类似于函数调用
	stu.say();
	getchar();
	return 0;
}
运行结果:
小明的年龄是 15,成绩是 90.5
在类中我们定义了一个构造函数 Student(),它的作用是给3个 private 属性的成员变量赋值。在 main 函数中,我们根据构造函数创建了一个对象 stu;因为构造函数有参数,所以创建对象时要相应地传入实参,形式类似于函数调用。
一旦在类中定义了构造函数,那么创建对象时一定会被执行;如果构造函数有参数,创建对象时就要传参。

另外,构造函数主要用来进行初始化,没有返回值(有返回值没有任何意义),这就意味着:
**不管是声明还是定义,函数名前面都不能出现返回值类型,即使是 void 也不允许;
**函数体中不能有 return 语句。
默认构造函数:
如果用户自己没有定义构造函数,那么编译器会自动生成一个默认的构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行任何操作。
一个类,必须有构造函数,要么用户自己定义,要么编译器自动生成。一旦用户自己定义了构造函数,不管它是 public 属性的,还是 private、protected 属性的,编译器都不再自动生成。上面的 Student 类,只有一个构造函数,就是我们自己定义的。
析构函数:
创建对象时系统会自动调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数来进行清理工作(例如回收创建对象时消耗的各种资源),这个函数被称为析构函数。
析构函数也是一种特殊的成员函数,没有返回值,不需要用户调用,而是在销毁对象时自动执行。与构造函数不同的是,析构函数的名字是在类名前面加一个”~“符号。
析构函数没有参数,不能被重载,因此一个类只能有一个析构函数。如果用户没有定义,那么编译器会自动生成。
实例:
#include <iostream>
using namespace std;
class Student{
private:
	char *name;
	int age;
	float score;
public:
	//构造函数
	Student(char *, int, float);
	//析构函数
	~Student();
	//普通成员函数
	void say();
};
Student::Student(char *name1, int age1, float score1) :name(name1), age(age1), score(score1){}
Student::~Student(){
	cout << name << "再见" << endl;
}
void Student::say(){
	cout << name << "的年龄是 " << age << ",成绩是 " << score << endl;
}
int main(){
	Student stu1("小明", 15, 90.5f);
	stu1.say();

	Student stu2("李磊", 16, 95);
	stu2.say();

	Student stu3("王爽", 16, 80.5f);
	stu3.say();
	cout << "main 函数即将运行结束" << endl;
	Student *p = new Student("",0,0);
	delete p;
	getchar();
	return 0;
}
运行结果如下:  
小明的年龄是 15,成绩是 90.5
李磊的年龄是 16,成绩是 95
王爽的年龄是 16,成绩是 80.5
main 函数即将运行结束
再见
可以看出,析构函数在 main 函数运行结束前被执行,并且调用顺序和构造函数正好相反,为了方便记忆,我们可以将之理解为一个栈,先入后出。
对象可以认为是通过类这种数据类型定义的变量,它的很多特性和普通变量是一样的,例如作用域、生命周期等。由此可以推断,对象这种变量的销毁时机和普通变量是一样的。
总结起来,有下面几种情况:
1) 如果在一个函数中定义了一个对象(auto 局部变量),当这个函数运行结束时,对象就会被销毁,在对象被销毁前自动执行析构函数。


2) static 局部对象在函数调用结束时并不销毁,因此也不调用析构函数,只有在程序结束时(如 main 函数结束或调用 exit 函数)才调用 static 局部对象的析构函数。


3) 如果定义了一个全局对象,也只有在程序结束时才会调用该全局对象的析构函数。


4) 如果用 new 运算符动态地建立了一个对象,当用 delete 运算符释放该对象时,先调用该对象的析构函数。
注意:析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以分配给新对象使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值