构造函数
构造函数的形式
构造函数常用于对类成员进行初始化操作,其在对象被创建的时刻运行。构造函数的写法通常是 类名(characters…) 代码如下:
class Example
{
public:
int age;
void fun()
{
age = 0; //成员函数对成员进行初始化
cout << "member function running" << endl; //成员函数会后与构造函数运行
}
Example()
{
age = 1; //构造函数初始化
cout << "constructor running" << endl; //构造函数先运行
}
};
int main()
{
Example s1; //对象被创建,构造函数即运行
s1.fun();
return 0;
}
运行结果:
可以看到,构造函数在对象s1创建的时候即执行。并对成员age进行赋值,之后其他成员函数才能对其进行赋值操作。同样的,通过堆区指针创建的对象,构造函数也会执行。
值得一提的是,不用去纠结构造函数有没有返回值的问题,对象创建完毕,函数也就回收了,没有任何意义。
构造函数也可以带参数:
class Example
{
int a;
float b;
Example(int a, float b) //可以直接初始化,或者传参初始化
{
}
};
int main()
{
Example c1(0, 0.1f); //传参初始化
return 0;
}
构造函数可以有多个,可以重载及缺省,对于函数重载以及缺省的概念请参考C++函数特性一节的内容。如果我们没有写构造函数,那么系统会默认生成一个空函数作为构造函数。
同样地,构造函数可以类内声明,类外定义,注意定义的时候需要加上作用域运算符,如:
Example :: Example(int a, float b);
初始化列表
除了通过参数列表传参的方式进行初始化以外,还可以通过初始化列表的方式进行初始化。
class Example
{
int a;
float b;
Example() : a(1),b(0.1f) //初始化列表初始化
{
}
};
初始化列表的方式初始化优先级低于传参,如果同时在初始化的时候传参并且在构造函数中用该参数对成员赋值,会覆盖掉初始化列表的初始值。另外,可以缺省传参。代码如下,请自行测试:
class Example
{
int a;
float b;
Example(int s1 = 2, float s2 = 0.2f) : a(1),b(0.1f) //初始化列表初始化
{
a = s1;
b = s2; //构造函数内赋值可以覆盖初始化列表的值。
}
};
关于引用的初始化:可以引用成员,引用参数,引用外部变量。使用的时候注意被引对象的作用域。关于引用请查看C++引用一节。
关于const成员,只能初始化,不能赋值。并且一定要初始化。(最好通过构造函数初始化列表的方式进行初始化)
析构函数
析构函数的形式
析构函数在对象被回收的时候运行,通常用于清理相关内存空间,以及对象生命周期结束时对现场的清理,对于防止内存泄漏等程序故障有重要的意义。
代码如下:
#include <iostream>
using namespace std;
class Example
{
public:
int a;
Example()
{}
~Example() //析构函数括号中不能有参数,没有重载
{}
};
int main()
{
Example c1;
Example *c2 = new Example;
delete c2; //析构函数在此执行
return 0;
}
析构函数与构造函数一样,如果不进行声明,编译器默认补充空函数。
特殊情形:临时对象
int main()
{
Example(); //生命周期只在本行,析构函数也会在此执行
int a;
a = int(12); //临时对象的使用方法
}
malloc, free与 new, delete
malloc不会触发构造函数,new会;
free不会触发析构函数,delete会。
this指针的用法
this指针用于对象内,表示对象的地址,而*this表示对象本身。
class Example
{
public:
int a;
Example(int b)
{this->a = b}
}
在main函数体中执行其构造函数,可以通过传参对成员a进行赋值。
关于this:
- 在对象创建时产生。
- 类型为对应类的指针类型,指向当前对象。
- this指针本身不是成员。
- 可以做为成员函数的参数。
- 不能作为类内成员的映射在类外出现。