C++类中成员变量的初始化

本文详细对比了C++类中成员变量初始化的两种方式:构造函数初始化列表和构造函数体内赋值,包括初始化顺序、适用场景及效率差异。


C++类中成员变量的初始化有两种方式:

         构造函数初始化列表和构造函数体内赋值。下面看看两种方式有何不同。

         成员变量初始化的顺序是按照在那种定义的顺序。

1 内部数据类型(char,int……指针等)

复制代码
class Animal
{
public:
Animal(int weight,int height): //A初始化列表
m_weight(weight),

m_height(height)
{
}
Animal(int weight,int height) //B函数体内初始化
{

m_weight = weight;
m_height = height;
}
private:
int m_weight;
int m_height;
};
复制代码

对于这些内部类型来说,基本上是没有区别的,效率上也不存在多大差异。

当然A和B方式不能共存的。


 

2 无默认构造函数的继承关系中

复制代码
class Animal
{
public:
Animal(int weight,int height): //没有提供无参的构造函数
m_weight(weight),

m_height(height)
{
}
private:
int m_weight;
int m_height;
};

class Dog: public Animal
{
public:
Dog(int weight,int height,int type) //error 构造函数 父类Animal无合适构造函数
{

}
private:
int m_type;
};
复制代码


这种必须在派生类中构造函数中初始化提供父类的初始化,因为对象构造的顺序是:

 

父类——子类——……

 

所以必须:

 

复制代码
class Dog: public Animal
{
public:
Dog(int weight,int height,int type):
Animal(weight,height) //必须使用初始化列表增加对父类的初始化
{

;
}
private:
int m_type;
};
复制代码


 

3 类中const常量,必须在初始化列表中初始,不能使用赋值的方式初始化

 

复制代码
class Dog: public Animal
{
public:
Dog(int weight,int height,int type):
Animal(weight,height),
LEGS(4) //必须在初始化列表中初始化
{

//LEGS = 4; //error
}

private:
int m_type;
const int LEGS;
};
复制代码


4 包含有自定义数据类型(类)对象的成员初始化        

 

复制代码
class Food
{
public:
Food(int type = 10)
{
m_type = 10;
}
Food(Food &other) //拷贝构造函数
{

m_type = other.m_type;
}
Food & operator =(Food &other) //重载赋值=函数
{

m_type = other.m_type;
return *this;
}
private:
int m_type;
};

1)构造函数赋值方式 初始化成员对象m_food
class Dog: public Animal
{
public:
Dog(Food &food)
//:m_food(food)
{

m_food = food; //初始化 成员对象
}

private:
Food m_food;
};
//使用
Food fd;

Dog dog(fd); //
Dog dog(fd);结果:

先执行了 对象类型构造函数Food(int type = 10)——>
然后在执行 对象类型构造函数Food & operator =(Food &other)
想象是为什么?



2)构造函数初始化列表方式
class Dog: public Animal
{
public:
Dog(Food &food)
:m_food(food) //初始化 成员对象
{

//m_food = food;
}

private:
Food m_food;
};
//使用
Food fd;

Dog dog(fd); //
Dog dog(fd);结果:执行Food(Food &other)拷贝构造函数完成初始化
复制代码


不同的初始化方式得到不同的结果:

      明显构造函数初始化列表的方式得到更高的效率。

C++类中成员变量的初始化有两种方式:

         构造函数初始化列表和构造函数体内赋值。下面看看两种方式有何不同。

         成员变量初始化的顺序是按照在那种定义的顺序。

1 内部数据类型(char,int……指针等)

复制代码
class Animal
{
public:
Animal(int weight,int height): //A初始化列表
m_weight(weight),

m_height(height)
{
}
Animal(int weight,int height) //B函数体内初始化
{

m_weight = weight;
m_height = height;
}
private:
int m_weight;
int m_height;
};
复制代码

对于这些内部类型来说,基本上是没有区别的,效率上也不存在多大差异。

当然A和B方式不能共存的。


 

2 无默认构造函数的继承关系中

复制代码
class Animal
{
public:
Animal(int weight,int height): //没有提供无参的构造函数
m_weight(weight),

m_height(height)
{
}
private:
int m_weight;
int m_height;
};

class Dog: public Animal
{
public:
Dog(int weight,int height,int type) //error 构造函数 父类Animal无合适构造函数
{

}
private:
int m_type;
};
复制代码


这种必须在派生类中构造函数中初始化提供父类的初始化,因为对象构造的顺序是:

 

父类——子类——……

 

所以必须:

 

复制代码
class Dog: public Animal
{
public:
Dog(int weight,int height,int type):
Animal(weight,height) //必须使用初始化列表增加对父类的初始化
{

;
}
private:
int m_type;
};
复制代码


 

3 类中const常量,必须在初始化列表中初始,不能使用赋值的方式初始化

 

复制代码
class Dog: public Animal
{
public:
Dog(int weight,int height,int type):
Animal(weight,height),
LEGS(4) //必须在初始化列表中初始化
{

//LEGS = 4; //error
}

private:
int m_type;
const int LEGS;
};
复制代码


4 包含有自定义数据类型(类)对象的成员初始化        

 

复制代码
class Food
{
public:
Food(int type = 10)
{
m_type = 10;
}
Food(Food &other) //拷贝构造函数
{

m_type = other.m_type;
}
Food & operator =(Food &other) //重载赋值=函数
{

m_type = other.m_type;
return *this;
}
private:
int m_type;
};

1)构造函数赋值方式 初始化成员对象m_food
class Dog: public Animal
{
public:
Dog(Food &food)
//:m_food(food)
{

m_food = food; //初始化 成员对象
}

private:
Food m_food;
};
//使用
Food fd;

Dog dog(fd); //
Dog dog(fd);结果:

先执行了 对象类型构造函数Food(int type = 10)——>
然后在执行 对象类型构造函数Food & operator =(Food &other)
想象是为什么?



2)构造函数初始化列表方式
class Dog: public Animal
{
public:
Dog(Food &food)
:m_food(food) //初始化 成员对象
{

//m_food = food;
}

private:
Food m_food;
};
//使用
Food fd;

Dog dog(fd); //
Dog dog(fd);结果:执行Food(Food &other)拷贝构造函数完成初始化
复制代码


不同的初始化方式得到不同的结果:

      明显构造函数初始化列表的方式得到更高的效率。

<think>我们已知C++类成员变量初始化顺序的相关知识。现在,我需要根据用户的问题,系统地讲解C++类成员变量初始化顺序的规则。同时,按照系统指令,我需要使用正确的LaTeX格式和中文回答,并在最后生成相关问题。用户的问题是:“我想了解C++成员变量初始化顺序规则请问C++类成员变量初始化顺序声明顺序初始化列表顺序”根据引用内容,我们可以总结如下:1.初始化顺序首先遵循继承关系:先初始化,然后初始化派生成员变量。2.派生成员变量初始化顺序不是由初始化列表中的顺序决定的,而是由成员变量定义中的声明顺序决定的。3.如果成员变量初始化列表中的顺序与声明顺序不一致,可能会导致一些成员变量初始化时使用了尚未初始化的其他成员变量,从而产生未定义行为(如引用[3]中的例子)。4.对于常量成员(const)和引用成员(&),它们必须在初始化列表中进行初始化,因为无法在构造函数体内进行赋值。5.初始化列表的初始化操作发生在构造函数体执行之前。另外,引用[1]指出:“首先是基,然后是成员变量按照它们在中声明的顺序进行初始化初始化列表中的顺序不影响实际的初始化顺序。”引用[2]和[3]也强调了声明顺序的重要性。因此,回答可以这样组织:一、整体初始化顺序:1.基初始化(如果有基,按照继承列表的顺序)2.派生类成员变量初始化(按照在定义中的声明顺序)二、成员变量初始化细节:-每个成员变量初始化是在初始化列表中指定的,如果没有在初始化列表中指定,则:-如果成员是型且具有默认构造函数,则调用默认构造函数进行初始化。-内置型(如int、指针等)如果没有初始化,则其值是未定义的。-初始化列表中只能指定普通成员变量的值,但不能改变初始化的顺序。三、初始化列表顺序与声明顺序的关系:-初始化列表的顺序不影响实际初始化顺序,实际顺序只取决于声明顺序。-如果在初始化列表中使用一个成员变量初始化另一个成员变量,而声明顺序在后的变量被用来初始化声明顺序在前的变量,则会导致未定义行为(因为被使用的那个变量还没有初始化)。四、必须使用初始化列表的情况:1.常量成员(const)2.引用成员(&)3.没有默认构造函数的类成员五、举例说明(如引用[3]的例子):在A中,成员变量声明顺序为a,b,c。构造函数初始化列表写的是b(1),a(b),c(b)。由于初始化顺序是a先于b,所以初始化a时,b还没有被初始化,因此a的值是未定义的(乱码)。接下来,我们按照要求进行回答:</think> ### C++类成员变量初始化顺序规则 在C++中,类成员变量初始化顺序遵循以下严格规则: #### 1. **整体初始化顺序** - **基优先原则**:如果有继承关系,先初始化所有**直接基**(按照继承声明顺序) - **成员变量顺序**:随后初始化**当前成员变量** ```cpp class Base {}; class Derived : public Base { // 1. 先初始化Base int a; // 2. 按照声明顺序初始化成员 int b; }; ``` #### 2. **成员变量初始化细节(核心规则)** [^1][^2][^3] - **声明顺序决定初始化顺序**: - 成员变量初始化顺序**严格按定义中的声明顺序**进行 - 初始化列表中的顺序**不改变**实际初始化顺序 - *代码示例*: ```cpp class Test { public: Test() : y(5), x(y) {} // ⚠️ 危险:x在y前初始化 private: int x; // 先声明x int y; // 后声明y }; ``` ➔ `x(y)`会使用未初始化的`y`,导致未定义行为(UB) - **必须用初始化列表的情况**: - 常量成员(`const`) - 引用成员(`&`) - 无默认构造函数的类成员 ```cpp class MustInitList { public: MustInitList(int val) : ref(val), cval(10) {} // ✅ 必须初始化列表 private: const int cval; // const成员 int& ref; // 引用成员 }; ``` #### 3. **初始化列表 vs 构造函数赋值** | 特性 | 初始化列表 | 构造函数体内赋值 | |--------------------|-------------------------------|------------------------| | **执行时机** | 进入构造函数体**前** | 进入构造函数体**后** | | **效率** | 直接构造(更高效率) | 先默认构造再赋值 | | **特殊成员支持** | 支持const/引用/无默认构造成员 | 不支持这些成员 | | **顺序依赖** | 仍受声明顺序制约 | 无顺序依赖 | #### 4. **关键陷阱与示例** ```cpp class Danger { public: Danger() : b(1), a(b) {} // 初始化列表顺序≠实际顺序 int a; int b; }; ``` - **实际初始化顺序**:`a(b)` → `b(1)`(因声明顺序是`a`先于`b`) - **结果**:`a`用未初始化的`b`赋值 → 输出`a=乱码, b=1` [^3] - **修复方案**:调整声明顺序或避免交叉初始化 #### 5. **总结规则** 1. 基类成员优先于派生初始化 2. 成员变量初始化**只认声明顺序** 3. 初始化列表顺序可读但不改变实际顺序 4. const/引用/无默认构造成员**必须**用初始化列表 5. 避免在初始化列表中使用其他未初始化的成员
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值