构造函数列表初始化与赋值
构造函数列表初始化与赋值的区别
构造函数初始化的两种类型
- 手动给成员赋值
- 使用初始化列表
使用初始化列表的构造函数
类名::构造函数名(参数表): (成员初始化表){构造函数体}
构造函数中的初始化列表只需要在参数列表的后面加一个冒号(:),然后*将要初始化的成员按照*成员名(参数)的格式排列在后面,个成员之间用逗号隔开
class Test{
public:
int A;
int B;
Test(int a);
};
Test::Test(int a):A(a),B(10)
//给成员变量 A、B 初始化,不一定要和参数列表写在一行
{ /* …… */ }
其中成员的初始化顺序不是按照初始化列表中的顺序来的,而是按照成员声明的顺序来的,例如:
/* Test类的声明同上 */
Test::Test(int a):B(10),A(a)
// 虽然 B 在前面,但还是 A 先初始化
{/* …… */}
Test::Test(int a):B(a),A(B) //是错误的
//此处 A 的初始化依赖了 B,然而是 A 先初始化,这就导致 A 得到了 B 中还没初始化的错误内容
{/* …… */}
若类的数据成员是静态的const或者引用类型,必须使用初始化列表
const和static的区别
static:修饰的变量为静态变量,只会被初始化一次,该变量存储在内存中的静态区,地址不会改变。修饰全局变量时,每个函数对其的调用都是调用其生成的副本,修饰局部变量时每次调用都是上一次调用后的值。
const:修饰的变量只会被定义(可能也只能在定义的时候赋值)一次,定义之后无法对其进行赋值或修改(即不能充当左值)。
static和const修饰量的最大区别就是:static的值能修改,const不能(const修饰指针的情况另分)
const是静态局部变量,在超出其作用域后会被立即释放,在类的具体对象中,不同的类可以有不同的const变量
static是静态整体变量,在函数执行完毕后不会释放其空间,static变量是和类绑定的不同的对象的static变量是一样的
-
静态(const)的数据成员只能初始化而不能赋值,同样引用类型也是只可以被初始化,那么只有用初始化列表。
-
因为静态数据成员必须在定义时就被赋值,在构造函数体内进行赋值时,编译会报错。
-
静态数据成员在类声明中声明,在包含类方法的文件中初始化。初始化时使用作用域运算符来指出静态成员所属的类。但如果静态成员是整形const或枚举型const,则可以在类声明中初始化。
-
static类型的静态变量好像不能使用列表初始化的方式进行初始化
#include <iostream>
#include <string>
using namespace std;
template<class t>
class namedptr {
public:
namedptr(const string& initname, t *initptr);
private:
const string name; //静态数据成员的初始化必需用初始化列表
t * const ptr;
};
template<class t>
namedptr<t>::namedptr(const string& initname, t *initptr)
: name(initname), ptr(initptr) {}
//第二种方法是在构造函数体内赋值:
//但含有静态数据类型,所以不可用
//template<class t>
//namedptr<t>::namedptr(const string& initname, t *initptr)
//{
// name = initname;
// ptr = initptr;
//}
int main()
{
int a = 10;
namedptr<int> Test("SHENZHEN",&a);
}
两种初始化方式的对比
首先 构造函数体内进行赋值会带来额外的开销,效率会低于初始化列表的方式
#ifdef A_H_
#define A_H_
#include <iostream>
usingnamespace std;
class A{
public:
A(int a);
static void print();//静态成员函数
private:
static int aa;//静态数据成员的声明
static const int count;//常量静态数据成员(可以在构造函数中初始化)
const int bb;//常量数据成员
};
int A::aa=0;//静态成员的定义+初始化
const int A::count=25;//静态常量成员定义+初始化
A::A(int a):bb(a){//常量成员的初始化
aa+=1;
}
void A::print(){
cout<<"count="<<count<<endl;
cout<<"aa="<<aa<<endl;
}
#endif
void main(){
A a(10);
A::print();//通过类访问静态成员函数
a.print();//通过对象访问静态成员函数
}
在上面的例子中
- 第一种使用了初始化列表的方式。 只是调用了一次缺省的构造函数,并不会调用赋值函数。会减少不必要的开支,当类相当复杂时,就会看出使用初始化列表的好处。
- 第二种使用了构造函数体内赋值的方式。初始化数据成员时会两次对string的成员函数的调用:一次是缺省构造函数,另一次是赋值。