类中定义const成员
如果类中有const成员,那const成员必须先初始化,初始化类中的const成员,就需要初始化列表。
C++初始化列表对成员变量进行初始化的语法规则
//v1对m1进行初始化,v1,v2对m2进行初始化,v3对m3进行初始化
ClassName::ClassName():m1(v1), m2(v1,v2), m3(v3)
{
//初始化操作
}
程序实例1:const成员变量初始化
#include
class Test
{
private:
const int ci; //const成员变量需要初始化
public:
Test() : ci(10) //在构造函数中进行变量初始化,用10来初始化ci
{
}
int getCI() { return ci; }
};
int main()
{
Test t;
printf("t.ci = %d\n", t.getCI());
return 0;
}
输出结果:
t.ci = 10
类成员的初始化
成员的初始化顺序与成员的声明顺序相同;
成员的初始化顺序与初始化列表中的位置无关;
初始化列表先于构造函数的函数体执行;
程序实例2:初始化列表的使用
#include
class Value
{
private:
int mi;
public:
Value(int i)
{
printf("i = %d\n",i);
mi = i;
}
int getI()
{
return mi;
}
};
class Test
{
private:
Value m2;
Value m3;
Value m1;
public:
Test() :m1(1),m2(2),m3(3) //初始化列表
{
printf("Test::Test()\n");
}
};
int main()
{
Test t;
return 0;
}
输出结果:
i = 2
i = 3
i = 1
Test::Test()
结果分析,因为在Test类中声明Value对象的顺序是m2、m3、m1,即使初始化的顺序是m1、m2、m3也不行,而且初始化列表的执行顺序先于构造函数体本身。
类可以定义多个对象,对象的构造顺序是怎样的
局部对象的构造顺序:当程序执行流到达对象的定义语句时进行构造
程序实例3:局部对象的构造顺序
#include
class Test
{
private:
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(int i):%d\n", mi);
}
Test(const Test& obj)
{
mi = obj.mi;
printf("Test(const Test& obj):%d\n", mi);
}
};
int main()
{
int i = 0;
Test a1 = i; //1、首先构造,打印 Test(int i):0
while (i < 3)
{
Test a2 = ++i; //2、反复构造3次
}
if (i < 4)
{
Test a = a1; //3、拷贝构造函数,打印Test(const Test& obj):0
}
else
{
Test a(100);
}
return 0;
}
堆对象的构造顺序
当程序执行流到达new语句时创建对象;
使用new创建对象将自动触发构造函数的调用;
程序实例4:堆对象的构造顺序
#include
class Test
{
private:
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(int i):%d\n", mi);
}
Test(const Test& obj)
{
mi = obj.mi;
printf("Test(const Test& obj):%d\n", mi);
}
};
int main()
{
int i = 0;
Test* a1 = new Test(i);
while (++i < 10)
{
if (i % 2)
{
new Test(i);
}
}
if (i < 4)
{
new Test(*a1);
}
else
{
new Test(100);
}
return 0;
}
输出结果:
Test(int i):0
Test(int i):1
Test(int i):3
Test(int i):5
Test(int i):7
Test(int i):9
Test(int i):100
全局对象的构造顺序
全局对象的构造顺序是不确定的;
不同的编译器使用不同规则确定的构造顺序;
既然这样就没必要写代码了。
对象被初始化之后才能使用,对象不需要了就销毁,销毁前需要做一些清理工作。C++中如何清理需要被销毁的对象。
解决方案:
为每个类都提供一个public的free函数;
对象不再需要时立即调用free函数进行清理;
但是这种方案存在明显的问题:free只是一个普通的函数,必须显式的调用,对象销毁前如果没有做清理,就可能造成资源泄露。
C++编译器能否自动调用某个特殊的函数进行对象的清理?答案是肯定的。
析构函数
C++中可以定义一个特殊的清理函数叫做析构函数,析构函数的功能与构造函数相反。
析构函数定义:~ClassName();
析构函数没有参数,也没有返回值类型声明;
析构函数在对象被销毁时自动被调用。
程序实例5:析构函数的调用
#include
class Test
{
public:
Test()
{
printf("调用Test()\n");
}
~Test()
{
printf("调用~Test()\n");
}
};
int main()
{
Test t;
return 0;
}
输出结果:
调用Test()
调用~Test()
结果分析
当定义了t时,构造函数就被调用,t只是个局部变量,用完之后是要被清理的,在return 之前就调用了析构函数。
程序实例6:堆变量的销毁
#include
class Test
{
public:
Test()
{
printf("调用Test()\n");
}
~Test()
{
printf("调用~Test()\n");
}
};
int main()
{
Test* pt = new Test();
delete pt;
return 0;
}
输出结果:
调用Test()
调用~Test()