当前位置: 首页 > news >正文

C++创建对象过程

参考:

c++创建对象过程详解 - LEO__Y - 博客园 (cnblogs.com)

创建对象的过程

1.分配内存空间

2.初始化成员变量

3.调用构造方法

内存分配(Allocation)

全局对象和静态对象

编译器会为他们划分一个独立的段(全局段)为他们分配足够的空间

栈对象

MyClass obj; // 栈上分配

编译器在栈帧中直接预留空间,大小由 sizeof(MyClass) 决定。

分配速度极快(只需移动栈指针),无需手动释放。

堆对象

MyClass* obj = new MyClass(); // 堆上分配

调用 operator new 在堆上分配内存(底层可能调用 malloc)。

需要手动 delete 释放,否则内存泄漏。

注意:对象在栈或者堆上整体分配的,那么类里面的成员就在哪个位置存着,对象是局部的,那么成员就是局部的,对象是全局的,那么成员就是全局的。当然,不包括静态成员,因为静态成员不属于对象,而是属于类的,所以会在创建对象之前,程序启动时就初始化,后续详细说明。

在看到C++的类成员被调用时,比如一个类的成员变量被调用,我总是会下意识地去想这个到底是局部变量还是全局变量,这是C语言的惯性思维,而在C++中,成员是随着对象的位置而存在的,对象在哪片内存上,成员就在哪片内存上,访问成员,都需要通过对象来调用,当然,除了静态对象。

记住,类本质上只是一种数据和函数的组织形式。

其实类就跟结构体一样,是个声明而已,只有创建对应实例的时候才能使用(除了静态成员)

初始化成员变量

成员变量的初始化发生在构造函数体执行之前,具体分为两个阶段:

  1. 在进入构造函数体之前,所有成员变量会先进行默认初始化(类类型调用默认构造函数)。
  2. 如果使用了成员初始化列表(member initializer list),则会用指定的值覆盖默认初始化的结果。

初始化 (Initialization)和赋值(Assignment)。初始化早于赋值,它是随着对象的诞生一起进行的。而赋值是在对象诞生以后又给予它一个新的值。对象经过初始化以后,我们仍然可以对其进行赋值。我们可以通过构造函数的实现体(即构造函数中由"{}"包裹的部分)来实现。

注意:如果使用了构造函数的初始化列表,则会在初始化时直接就赋予对应的值,而不必分成初始化和赋值两个步骤了。


默认初始化的规则

内置类型(如intdouble、指针等):

如果未显式初始化,值是未定义的(除非是全局变量或static成员,会初始化为0)。

类类型:

调用默认构造函数初始化。如果没有默认构造函数且未在初始化列表中显式初始化,则编译错误。


初始化方式

(1) 成员初始化列表(推荐)

class Example {
public:Example(int x, int y) : a(x), b(y) { // 构造函数体(此时a和b已初始化)}
private:int a;int b;
};

时机:在构造函数体执行之前完成初始化。

特点:

直接调用成员的构造函数或赋值,效率更高(避免默认初始化 + 赋值的双重操作)。

const成员、引用成员、没有默认构造函数的类成员必须用初始化列表。

当类的成员变量是const 或者 引用类型时,必须使用初始化列表进行初始化,原因是:

  1. const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类的声明中初始化const数据成员,因为类的对象没被创建时,编译器不知道const数据成员的值是什么。

  2. const数据成员的初始化只能在类的构造函数的初始化列表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现,或者static cosnt

  3. 引用的指向只能初始化,不能修改其指向,赋值过程是在修改其指向,其实这就是赋值和初始化的本质区别

(2) 构造函数体内赋值

class Example {
public:Example(int x, int y) {a = x; // 赋值,非初始化b = y; // 赋值,非初始化}
private:int a;int b;
};

时机:在构造函数体内赋值时,成员变量已经经历了默认初始化(内置类型如int是未定义值,类类型调用默认构造函数)。

缺点:效率较低(尤其是类类型成员,会先默认构造再赋值)。


特殊情况

静态成员变量(static):

必须在类外单独定义和初始化(不占用对象内存)。

class Example {static int count;
};
int Example::count = 0; // 必须在类外初始化

常量静态成员(const static):

class Example {const static int MAX = 100;
};

C++11 后的类内初始化

C++11允许在类定义中直接为成员变量赋默认值:

class Example {int a = 10;     // 类内初始化std::string s = "Hello";
public:Example() {}     // a和s会以10和"Hello"初始化
};

初始化时机:如果构造函数未在初始化列表中显式指定值,则使用类内初始值(本质上等同于编译器将类内初始化放到初始化列表中)。


为什么基本类型成员默认不初始化为0?

性能考虑:C++的设计哲学是“不为不需要的操作付出代价”。强制初始化为零可能影响性能(尤其是频繁创建对象的场景)。

明确性:要求程序员显式初始化,避免隐藏的错误(如误用未初始化的值)。

通过显式初始化成员变量,可以确保代码的可预测性和安全性。

更多待补充。

相关文章:

  • 什么是单片机?
  • k8s中kubeSphere的安装使用+阿里云私有镜像仓库配置完整步骤
  • 2023年6级第一套长篇阅读
  • STM32 单片机启动过程全解析:从上电到主函数的旅程
  • 给echarts地图添加纹理底图不显示问题
  • Apache Airflow
  • EfficMultiCoreMemoryPool项目
  • 09_降维、特征提取与流行学习
  • 深度解析UniApp盲盒系统开发:从源码架构到多端部署全流程
  • 五、web安全--XSS漏洞(2)--XSS相关payload
  • 深入理解C#泛型:提升代码复用与类型安全的利器
  • 联通专线加持!亿林网络 24 核 32G 裸金属服务器,千兆共享带宽适配中小型企业 IT 架构
  • ONLYOFFICE文档API:编辑器的品牌定制化
  • 在 Ubuntu 服务器上 下载 Clash 文件使用代理
  • 动态规划-152.乘积最大子数组-力扣(LeetCode)
  • AI模型升级与机器人产业落地同步推进
  • 09《从依赖管理到容器化部署:Maven 全链路实战笔记,解锁 Java 项目自动化构建的终极奥秘》
  • 51c视觉~3D~合集3
  • 深入理解 Maven 循环依赖问题及其解决方案
  • 2022 RoboCom 世界机器人开发者大赛(睿抗 caip) -高职组(国赛)解题报告 | 科学家
  • qq排名优化网站/域名注册信息查询whois
  • 做资讯的网站/营业推广的方式有哪些
  • 成都自助建站软件/菏泽百度推广公司电话
  • 欧美网站建设排名大全/商业网站
  • 景德镇做网站/网络营销怎么做推广
  • 三亚婚纱摄影 织梦网站源码/中国联通和腾讯