博客
关于我
剑指offer系列——C++成员变量初始化顺序
阅读量:798 次
发布时间:2023-04-15

本文共 2106 字,大约阅读时间需要 7 分钟。

成员变量初始化顺序的真相:你可能误解的原因

在C++编程中,成员变量的初始化顺序一直是许多开发者的头痛所在。特别是面试中,一个看似简单的问题可能会让人一筹莫展。记得《剑指offer》中提到的那个面试案例?对方声称精通C++却不清楚成员变量初始化顺序,最终回答错误。这背后隐藏着很多技术深度,也让我自己不得不反思。

1. 初始化顺序的误解:代码与内存的关系

首先,成员变量的初始化顺序与它们在构造函数中的初始化列表顺序无关。很多开发者误以为初始化列表的顺序决定了变量的初始化顺序,但实际上这与定义成员变量的顺序有关。

成员变量的初始化顺序是基于它们在内存中的排列顺序决定的。内存是按照编译期确定的顺序排列的,因此在类定义中的成员变量定义顺序决定了它们在内存中的存放顺序。因此,初始化列表中的变量顺序并不影响它们的初始化顺序。

2. 代码示例:揭示错误理解的根源

来看一个典型的例子:

class A {private:    int n1;    int n2;public:    A(): n2(0), n1(n2 + 2) {}    void Print() {        cout << "n1:" << n1 << ", n2: " << n2 << endl;    }};

在这个构造函数中,n2被初始化为0,然后n1被初始化为n2 + 2。这意味着n2已经被初始化完毕,可以安全地被n1引用。

然而,许多开发者会误以为n1的初始化会被执行在n2之前,这显然与实际情况不同。这是因为成员变量的初始化顺序是由它们在内存中的排列决定的,而不是构造函数的初始化列表顺序。

3. 初始化顺序的正确理解:内存排列决定一切

正确的理解是,成员变量的初始化顺序与它们在内存中的排列顺序一致。内存排列顺序由成员变量在类定义中的定义顺序决定。

因此,在构造函数的初始化列表中,成员变量的顺序并不影响它们的初始化顺序。它们总是按照它们在内存中的排列顺序被初始化的。

4. 常见误区:构造函数中的初始化顺序

很多开发者误以为在构造函数中手动初始化成员变量会影响它们的初始化顺序。实际上,只有在构造函数中手动初始化时,成员变量的初始化顺序才会与它们在构造函数中的定义顺序一致。

例如:

class A {private:    int n1;    int n2;public:    A() {        n2 = 0;        n1 = n2 + 2;    }    void Print() {        cout << "n1:" << n1 << ", n2: " << n2 << endl;    }};

在这个构造函数中,n2被手动初始化为0,然后n1被初始化为n2 + 2。因此,n2必须先被初始化,否则n1的初始化会失败。

5. 特殊情况:const成员常量与静态变量

需要注意的是,const成员常量必须在构造函数的初始化列表中初始化。不能在构造函数体内进行初始化。

此外,static成员变量必须在类外初始化。它们不能在类内进行初始化。

6. 静态变量的初始化顺序

对于静态变量,初始化顺序遵循以下规则:

  • 基类的static成员变量先初始化。
  • 派生类的static成员变量随后初始化。
  • 全局变量和static变量的初始化顺序不确定。
  • 需要注意的是,static变量和全局变量都被存放在公共内存区。因此,static变量可以被理解为带有“作用域”的全局变量。

    在所有静态变量都被初始化后,main函数才会被调用。如果某个类的构造函数被执行,基类的成员变量会被初始化。

    7. 总结:正确理解成员变量初始化顺序

    通过以上分析,可以得出以下结论:

  • 成员变量的初始化顺序与它们在内存中的排列顺序有关,而不是构造函数的初始化列表顺序。
  • 如果在构造函数中手动初始化成员变量,初始化顺序与它们在构造函数中的定义顺序一致。
  • const成员常量必须在构造函数的初始化列表中初始化。
  • static成员变量必须在类外初始化。
  • 静态变量的初始化顺序是基类先,派生类后,全局变量也在内存中。
  • 8. 示例:正确的构造函数

    以下是正确的构造函数示例:

    class A {private:    int n1;    int n2;    const int n3 = 42;public:    A() : n2(0), n1(n2 + 2), n3(10) {}    void Print() {        cout << "n1:" << n1 << ", n2: " << n2 << ", n3: " << n3 << endl;    }};

    在这个构造函数中:

    • n2被初始化为0
    • n1被初始化为n2 + 2
    • n3被初始化为10

    由于n3是常量,只能在初始化列表中初始化。

    结论

    通过以上分析,我们可以清晰地看到成员变量初始化顺序的关键点。理解这些规则可以帮助我们避免常见的错误,并提高代码的正确性。记住,成员变量的初始化顺序是由它们在内存中的排列顺序决定的,而不是构造函数中的初始化列表顺序。

    转载地址:http://brrfk.baihongyu.com/

    你可能感兴趣的文章
    MySQL-【1】配置
    查看>>
    MySQL-【4】基本操作
    查看>>
    Mysql-丢失更新
    查看>>
    Mysql-事务阻塞
    查看>>
    Mysql-存储引擎
    查看>>
    mysql-开启慢查询&所有操作记录日志
    查看>>
    MySQL-数据目录
    查看>>
    MySQL-数据页的结构
    查看>>
    MySQL-架构篇
    查看>>
    MySQL-索引的分类(聚簇索引、二级索引、联合索引)
    查看>>
    Mysql-触发器及创建触发器失败原因
    查看>>
    MySQL-连接
    查看>>
    mysql-递归查询(二)
    查看>>
    MySQL5.1安装
    查看>>
    mysql5.5和5.6版本间的坑
    查看>>
    mysql5.5最简安装教程
    查看>>
    mysql5.6 TIME,DATETIME,TIMESTAMP
    查看>>
    mysql5.6.21重置数据库的root密码
    查看>>
    Mysql5.6主从复制-基于binlog
    查看>>
    MySQL5.6忘记root密码(win平台)
    查看>>