本文对类的初始化方法进行梳理总结,类的初始化方法有多种形式,针对不同的变量也不一样。下面进入正题。
- 类的构造函数初始化列表方式:这种初始化方式都很熟悉,也是我们经常使用的初始化方式,这里面涉及构造函数的种类(默认构造函数、拷贝构造函数、赋值构造函数、右值引用构造函数、赋值运算符重载、右值引用赋值运算符重载),本专栏有专门的文章进行介绍,这里不再展开。下面给出一些典型的例子:
class Example
{private:int num;std::string str;public:Example(int value, std::string string):num(value),str(string){} //初始化列表的方式进行初始化
}
- 默认成员初始化方式:这是c++11引入的特性,怎么理解呢?就是在类声明时可以对某些变量进行初始化,而在c++11版本之前是不行的,在c++11之前的版本中只有const类型的变量才可以在类声明时进行初始化。请看下面的例子:
//c++98版本
class Example
{private:int num = 0; //编译报错,不支持这样的初始化std::string str = "hello"; //编译报错std::vector<int> vect{1,2,3,4,5}; //编译报错const int num1 = 2; //编译通过,仅支持const类型的变量在声明时定义
}//c++11版本及以后
class Example
{private:int num = 0; //默认初始化为0 正确std::string str = "hello"; 正确std::vector<int> vect{1,2,3,4,5}; //正确static int number = 1; //错误,静态成员变量的定义另有规则
}
- 列表初始化方式(聚合初始化):其实这个就是通过大括号的方式进行初始化,在c++98版本及之后的版本形式不太一样,请看下面的例子:
//例子一
struct Point
{int x;int y;
};Point p1={1,2}; //c++98版本这样通过列表进行初始化
Point p2{1,2}; //c++11及之后版本的列表初始化 x=1,y=2//例子二
struct Point
{int y;int x;double z;char h;
};Point p2{1,2,3.14,'a'}; //c++11及之后版本的列表初始化 y=1,x=2,z=3.14,h='a'//例子三
struct Point
{int x;double y;
};
Point p3{3.14, 5.55}; //编译报错,在初始化列表时不支持窄化转换double->int// 嵌套结构体初始化
struct Rectangle {Point topLeft;Point bottomRight;
};Rectangle rect{{0,0}, {1,1}}; // 嵌套列表初始化
注意上面的例子,
(1)使用初始化列表初始化时大括号的顺序一定是与类的参数声明顺序严格一致的。
(2)使用初始化列表方式进行初始化,不允许(窄化转换),例如讲一个double转换为int类型,在通过列表初始化时是不允许这种操作的,例如上面的例子三。
(3)这种初始化方法仅在未定义构造函数的情况才会生效,如果存在构造函数,则会优先调用对应的构造函数,请看下一小节。
- 统一初始化语法:与列表初始化方式类似,不同的是统一初始化语法存在对应的构造函数。请看下面的例子:
class Example
{private:int x;bool y;public:Example(int x, bool y):x(x),y(y){} //构造函数1Example(){} //构造函数2
};Example example0{} //调用构造函数2
Example example{1,true}; //此处调用构造函数
- 静态成员变量初始化:静态成员变量的初始化有多种情况(const类型的静态成员变量、非const类型的静态成员变量)。对于const类型成员变量必须在类声明时进行初始化;对于非const类型的成员变量,在c++17版本之前不允许在类声明时初始化,必须在cpp文件进行初始化,但是在c++17版本之后可以在类声明中进行初始化,但是必须结合关键字inline。请看下面的例子:
class Example
{prvate:static const int num = 0; //编译通过static const string str = "hello"; //编译不通过static int num1 = 2; //编译报错static int num1;inline static int num2 = 3; //c++17版本及之后结合inline关键字可以在类声明中对非const类型静态成员进行初始化
}//cpp文件int Example::num1 = 2; //c++17版本之前必须在外部初始化
需要注意的是const类型静态成员变量的初始化仅支持整型,对于非整型的const静态成员变量的初始化不支持,例如double,std::string 类型等。
- 初始化顺序:初始化都是按照声明的顺序进行初始化的
class Base {int x;
public:Base() : x(0) {} // 基类初始化
};class Derived : public Base {int a;int b;int c;public:// 初始化顺序按照声明顺序,不是初始化列表的顺序Derived() : c(1) // 虽然c在最后声明,但这里最先初始化不会影响顺序, a(2) // 实际上a会在b之前初始化, b(3) // b最后初始化{}
};
注意事项
- 列表初始化方式支持不同的类型的列表初始化,怎么理解呢,假设一个类有两个不同类型的成员变量,使用列表初始化方式的顺序一定是与声明的顺序保持一致的。