博客
关于我
剑指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 Can't connect to MySQL server
    查看>>
    mysql case when 乱码_Mysql CASE WHEN 用法
    查看>>
    Multicast1
    查看>>
    mysql client library_MySQL数据库之zabbix3.x安装出现“configure: error: Not found mysqlclient library”的解决办法...
    查看>>
    MySQL Cluster 7.0.36 发布
    查看>>
    Multimodal Unsupervised Image-to-Image Translation多通道无监督图像翻译
    查看>>
    MySQL Cluster与MGR集群实战
    查看>>
    multipart/form-data与application/octet-stream的区别、application/x-www-form-urlencoded
    查看>>
    mysql cmake 报错,MySQL云服务器应用及cmake报错解决办法
    查看>>
    Multiple websites on single instance of IIS
    查看>>
    mysql CONCAT()函数拼接有NULL
    查看>>
    multiprocessing.Manager 嵌套共享对象不适用于队列
    查看>>
    multiprocessing.pool.map 和带有两个参数的函数
    查看>>
    MYSQL CONCAT函数
    查看>>
    multiprocessing.Pool:map_async 和 imap 有什么区别?
    查看>>
    MySQL Connector/Net 句柄泄露
    查看>>
    multiprocessor(中)
    查看>>
    mysql CPU使用率过高的一次处理经历
    查看>>
    Multisim中555定时器使用技巧
    查看>>
    MySQL CRUD 数据表基础操作实战
    查看>>