深度探索C++对象模型读书笔记 二

本文是《深度探索C++对象模型》读书笔记。介绍了编译器在不同情况下对默认构造函数、拷贝构造函数的处理,如class含成员对象或虚函数时的构造操作。还阐述了程序转换语义学,以及成员初始化列表的适用情况、顺序规则等,帮助程序员理解编译器行为并优化代码。

深度探索C++对象模型读书笔记<二>


在使用C++时,常常会好奇或者抱怨,编译器为我们做了什么事呢? 为什么构造函数没有为我初始化呢?为什么我还要写默认构造函数呢?

2.1 Default Constructor 的构造操作

如果没有声明默认构造函数,编译器会在需要的时候帮我们产生出来。 为了避免在多个地方被需要导致重复,则编译器将产生的构造函数声明为inline方式。

class Foo {public:Foo(), Foo(int) };

class Bar {public: Foo foo;char *str;}

Bar bar; // 则会调用Bar的默认构造函数,同时该默认构造函数会初始化member object成员,调用其构造函数

编译器在Bar中插入代码:

inline Bar::Bar() { foo.Foo::Foo();}; 但不会初始化str,需要程序员来进行初始化;

【重点】编译器的行为是:如果class A内涵一个或者一个以上的member class objects,那么class A 的每一个constructor必须调用每一个member classes的default constructor。 如果多个member class object是都需要初始化,则根据在class中声明的顺序进行初始化;

如果已经有明确声明的构造函数,则不会在生命默认的构造函数,但仍需要在所有声明的构造函数中调用包含或者继承的member class objects相应的构造函数;如果没有明确的构造函数,则需要合成default constructor,并调用相应的member class objects的constructor。

2)带有virtual Function的class

编译器有两个扩张行为:每一个class生成一个vtable,包含virtual function地址;其次每个class object中包含一个pointer member(vptr)并指向vtable; 【注意】 每一个包含virtual函数的class都有一个vtable(自己带有virtual或者从父类继承过程的virtual,都需要创建一个vtable,和父类的vtable独立,这样才能够保证运行时多态,子类指针或者引用转换为父类的引用或者指针,还是指向该类对象所指向的vtable(只是指针所指向内存布局不同)

以下4中情况会造成编译器为未声明的classes合成一个default constructor。 (implicit nontrivial default constructors),被合成的constructors只用来满足编译器的需要。

1)member object(包含)或者base class(继承)的default constructor(先初始化父类base constructor,其次是member object)

2)为每一个object初始化其virtual function机制或virtual base class机制(多重机制仅保留一份)

如 class X{public: int i;}

class A:public virtual X{public:int j} class B:public virtual X{public:int d}

class C:public A,public B{public :int k}

void foo(const A *pa) (pa->i = 1024) 转换为 pa -> _vbcX->i = 1024, 则_vbcX需要在virtual继承过程的default constructor中初始化,保留仅有一份;

误解:

1)任何class如果没有定义default constructor,就会被合成出一个(只有被需要时才会)

2) 编译器合成出来的default constructor会显示设定"class 内每一个data member的默认值“ (显然不会)

2.2 Copy Constructor 的构造操作

出现的三种情景:

1) X x; X xx = x;

  1. foo(X x) 函数参数

  2. X foo() { return x} 函数返回值 => 转换为 foo(X &result) { result = x ; return }

default Memberwise Initialization

一种data memer(一个指针或者数组)从某一个object拷贝到另一个object上(bitwise copy semantics 位逐次拷贝)

但不会拷贝member class object(而是以递归的方式调用该member class object的copy constructor,所谓的memberwise initialization)

四种情况不会bitwise copy semantics

1) 当class 中内含一个member object ,而该object内含copy constructor(包含合成的)

2)class 继承一个base class

3)class 声明了一个或者多个virtual functions

4)class 派生自一个继承链只能够,其中一个或者多个virtual base classes时

主要介绍第三种情况,第四种情况太复杂,暂时不考虑

Bear 包含virtual function, 继承自 ZooAnimal(包含virtual function),都包含virtual void draw(){}

Bear yogi;

Bear winnie = yogi;

ZooAnimal franny = winie; // 如果实施bitwise copy semantics,则franny中的vptr则等于winie中的vptr;

则franny.draw() 将调用Bear中的draw,显然错误。 包含vptr的sliced强制拷贝,保留父类的vptr指针,则franny中的vptr仍指向ZooAnimal中的vtable。(补图)

总结:object自己生成的data member不会被赋值(通过copy or assignment constructor),这样可以保证自身独立性

2.3 程序转换语义学

分贝针对copy constructor存在的三种情况进行介绍,如何在编译层面进行转换,不同编译器实现不同(采用何种优化方式)。主要介绍返回值时如何调用copy constructor,这样方便程序员进行优化,主题提出的思路是添加函数第一个参数来替代函数的返回值。函数的返回值编译器自动优化为NRV。

T foo() {return t}; => 编译器优化 void foo(T &result) { X tmp; result = tmp; } => 程序员优化 void foo(T &result) { result.x = x;}

2.4 成员们的初始化列表 member initialization list

适应情况:

1) 当初始化一个reference member时 必须

2) 当初始化一个const member 时,必须

3) 当调用一个 base class 的constructor,而它拥有一组参数时,可以提高效率

4) 当调用一个member class的constructor,额它拥有一组参数时,可提高效率

class Word {

String _name;

int _cnt;

public:

Word(){_name = 0; _cnt = 0;}

}

则会转换为,Word构造函数中首先调用Sting的构造函数初始化_name,然后调用String的拷贝构造函数对0初始化,并生成临时变量String tmp,然后调用赋值构造函数operator=,将值赋给_name,最终调用destructor来销毁_tmp。

而通过member initialization list,则将直接可以调用String(0)实现_name构建。

Word():_name(0) { _cnt = 0;}

初始化列表顺序和代码位置

初始化列表的顺序和data member声明的顺序相关,和列表中初始化顺序无关,并且编译器会生成代码,将初始化列表中代码插入到constructor中,并且一定在explicit user code之前。

int i;

int j;

Word():j(val),i(j) {}

出现问题,先初始化i,而j未知,导致error。

转载:https://www.cnblogs.com/purejade/p/3860197.html

Delphi 12.3 作为一款面向 Windows 平台的集成开发环境,由 Embarcadero Technologies 负责其持续演进。该环境以 Object Pascal 语言为核心,并依托 Visual Component Library(VCL)框架,广泛应用于各类桌面软件、数据库系统及企业级解决方案的开发。在此生态中,Excel4Delphi 作为一个重要的社区开源项目,致力于搭建 Delphi 与 Microsoft Excel 之间的高效桥梁,使开发者能够在自研程序中直接调用 Excel 的文档处理、工作表管理、单元格操作及宏执行等功能。 该项目以库文件与组件包的形式提供,开发者将其集成至 Delphi 工程后,即可通过封装良好的接口实现对 Excel 的编程控制。具体功能涵盖创建与编辑工作簿、格式化单元格、批量导入导出数据,乃至执行内置公式与宏指令等高级操作。这一机制显著降低了在财务分析、报表自动生成、数据整理等场景中实现 Excel 功能集成的技术门槛,使开发者无需深入掌握 COM 编程或 Excel 底层 API 即可完成复杂任务。 使用 Excel4Delphi 需具备基础的 Delphi 编程知识,并对 Excel 对象模型有一定理解。实践中需注意不同 Excel 版本间的兼容性,并严格遵循项目文档进行环境配置与依赖部署。此外,操作过程中应遵循文件访问的最佳实践,例如确保目标文件未被独占锁定,并实施完整的异常处理机制,以防数据损毁或程序意外中断。 该项目的持续维护依赖于 Delphi 开发者社区的集体贡献,通过定期更新以适配新版开发环境与 Office 套件,并修复已发现的问题。对于需要深度融合 Excel 功能的 Delphi 应用而言,Excel4Delphi 提供了经过充分测试的可靠代码基础,使开发团队能更专注于业务逻辑与用户体验的优化,从而提升整体开发效率与软件质量。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值