深度搜索C++对象模型 - 构造函数

C++后台开发校招面试常见问题 C和C++语言基础 参考书籍:《C++ primer》,《effective C++》,《STL源码解析》,《深度搜索C++对象模型》 extern关键字作用 extern声明变量在在外部定义? extern修饰函数? extern C的作用?用法? static关键字作用 static修饰局部变量? static全局变量?(限定变量在一个编译单元内,一个编译单元就是指一个cpp和它包含... 阅读详情


深度搜索C++对象模型: 构造函数

Default Constructor 构造函数:
C++ARM告诉我们: Default Constructor在需要的时候被编译器产生出来.
关键字: 在需要的时候 --> 被谁需要 需要来干什么?
例子:
class Foo
{
 public:
  int m_val;
  Foo *next;
};

void FooBar()
{
 Foo bar;
 if( bar.m_val || bar.next )
 {
  //do something
 }
}

这个程序本身的语义是:要求Foo有一个默认的构造函数, 可以将内部的两个data member初始化为0;
但是实际上结果是不符合语义的; 他可曾符合ARM所说? 答案是no;
其间最重要的一点是:  被程序需要 ?  被编译器需要 ?
很自然 把两个data member初始化为0, 这是程序的需要, 这是需要程序员保证的;
而对于编译器来说 他根本就没有被需要; ( 所以根本不会有默认构造函数, 后面会讲 )

//*********************************************************************************************//

对于编译器来说 "被编译器需要的 有用的默认构造函数" 有4种 分别介绍:

//-----------------------------------------------------------------------------------------------------------------------//

---> "含有 带有Default Constructor 的 Member Class Object 的 class":
如果一个Class内没有任何Constructor, 但是他内含一个Member Class Object, 而且这个Mmeber Class Object有Default Constructor,
那么这个Class的隐式默认构造函数就是有用的;
例子:
class Foo
{
 public:
  Foo();
};

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

这种情况下, Bar里内含了一个成员类对象, 而且这个成员类对象含有默认构造函数, 那么编译器就会为class Bar合成一个默认构造函数;
当我们 Bar bar;的时候 Bar::foo 必须在此处被初始化, 被合成的Bar的默认构造函数内含必要的代码,能够调用class Foo的默认构造函数来初始化foo;
但是他并不产生任何代码来初始化str;  所以"将Bar::foo初始化是编译器的责任, 但是将Bar::str初始化是程序员的责任";
被合成的Bar的默认构造函数也许像这样:
inline
Bar::Bar()
{
 foo.Foo::Foo();
}


重申: "被合成的默认构造函数是编译器的需要 不是程序的需要";
至此 编译器的需要已经满足了, 所以我们要来满足程序的需要, 所以我们需要一个"显式默认构造函数"
Bar::Bar()
{
 str = nullptr;
}

此时, 程序的需要满足了 但是编译器还需要初始化member object foo ;
但是程序无法再次定义一个默认构造函数 因为我们已经显式的定义了一个,
此时 编译器行动如下: 如果class A内含一个或一个以上的member class object,
那么class A的"每一个构造函数"都会调用"每一个member calss object的默认构造函数";
编译器会扩张已存在的构造函数, 在其中安插一些代码, 使得我们user使用之前先执行默认构造,
如上 扩张后的默认构造函数可能如下:
Bar::Bar()
{
 foo.Foo::Foo();
 str = nullptr;
}

如果有多个member class object 则会按照声明的顺序来调用默认构造函数,
例如:
class A{ public: A(); };
class B{ public: B( int ); };
class C{ public: C(); };
class D{ public: A a; B b; C c; int num; };

如上: class D没有定义默认构造函数 则会有一个"有用的默认构造函数"被合成出来;
D::D() : b( 1024 )
{
 num = 2048;
}

那么他也许会被扩张为:
D::D : b( 1024 )
{
 a.A::A();
 b.B::B( 1024 );
 c.C::C();
 num = 2048;
}

//-----------------------------------------------------------------------------------------------------------------------//

---> "带有Default Constructor 的 Base Class":
如果一个没有任何constructor的class派生自一个"带有Default Constructor"的 base class,
那么这个 derived class 的默认构造函数为有用的;
例子:
class A{ public: int num_a; };
class B{ public: A a; int num_b; };
class C : public B

对于这个例子, class B是一个上文的 "含有 带有Default Constructor 的 Member Class Object 的 class";
那么 class C 派生自 class B; 那么 class C 的默认构造函数为有用的;
他将调用上一层( class B ) 的 "默认构造函数" 来 "构造其内含的 Member Class Object";
如果设计中提供多个构造函数,但是其中都"没有默认构造函数",
编译器会遍历所有构造函数, 内插上一层( class B )的构造函数 ( class B的构造函数又内插了Member Class Object的构造函数 );

//-----------------------------------------------------------------------------------------------------------------------//

---> "带有一个 Virtual Function 的 class":
对于一个 带有 virtual Function 的 class , 他的默认构造函数为有用的;

而一个 class 带有virtual Function 分为两种情况:
其一: 类申明( 或继承 ) 一个 virtual function;
其二: class 派生自一个继承串链, 其中有一个或多个 virtual base class ;

例子:
class Widget
{
 public:
  virtual void Func( const Wieget &idget ) = 0;
};

class Bell : public Widget
class Whistle : public Widget

Bell b;
Whistle w;
Func( b );
Func( w );

"两个扩张行动" 会在编译期间发生:
-> 一个 virtual function table ( vtbl )会被编译器产生出来, 其中存放着 class 的 virtual functions 地址;
-> 在每一个 class object 中, 一个额外的 pointer member ( vptr )会被编译器合成出来 内含有 virtual function table 的地址;
此外 weidget.Func() 的虚拟调用操作将被改写, 以使用 widget 的 vptr 和 vtbl 中的 Func() 条目;

为了让这个 "virtual function 机制" 发挥作用, 编译器必须"为每一个Widget Object 和 其派生类的Object 设置 vptr 的初值 放置适当的 vtbl地址";

对于 class 的每一个 Constructor ,编译器会安插一些代码来完成这个操作;

//-----------------------------------------------------------------------------------------------------------------------//

---> "带有一个 Virtual Base Class 的 Class":
class X
class A : public virtual X
class B : public virtual X
class C : public A, public B

带有 virtual Base Class 的 Class C, 他的构造函数是有用的;

//-----------------------------------------------------------------------------------------------------------------------//

总结: 以上4种情况, "编译器必须为未声明构造函数的类合成一个默认构造函数",
标准称这些合成出来的构造函数为"隐式有用的构造函数", 合成出来的构造函数能够满足编译器( 而非程序 )的需要,

至于"不属于以上4种情况的而且又没有声明构造函数" 标准称他们为"隐式无用的构造函数", 事实上他们"不会被合成出来";

在合成的"隐式有用的构造函数"中, 只有 base class subobjects ( 基类的子对象 ) 和 class member object ( 类成员对象 ) 会被初始化;
而其他的 data member, 等等都不会被初始化 ( 虽然他们也许对程序是有用的 );


---->"误解":
---> 任何class如果没有定义默认构造函数 就会被合成出来一个,
---> 编译器合成出来的默认构造函数会设定class内的每一个data member,
很明显 都是错误的,

深度探索C++对象模型笔记 一、关于对象C 语言是程序性的,语言本身并没有支持数据和函数之间的关联性C++ 中可能采取抽象数据类型,或者是多层次的类结构完成C++ 的封装并没有增加多少成本,每一个成员函数虽然在cla... 阅读详情

相关推荐

SpringBoot实战——仿b站项目(一)

热部署就是当应用程序这种运行的时候升级冉家或者修改某一部分代码、配置文件时,无需手动启动应用,即可修改的部分生效工具 + IDEA配置。

weixin_52880572的博客 3456

深度探索C++ 对象模型

深度探索C++ 对象模型 第二章 对象 第二章第一节 类对象所占用的空间 成员函数不占用类对象的内存空间一个类对象至少占用1个字节的内存空间成员变量是占用对象的内存空间成员函数 每个类只诞生 一个(跟着类走),而不管你用这个类产生了多少个该类的对象; 第二章第二节 对象结构的发

weixin_42252757的博客 1173

Uni-App推送踩坑实录:从云函数URL化到后台推送失效,我都经历了什么

本文详细记录了Uni-App开发者在接入uni-push 2.0时遇到的推送失效问题,从云函数URL化到后台推送失效的完整排查过程。通过系统化分析和与官方沟通,最终找到解决方案,并分享了预防措施与最佳实践,帮助开发者避免类似问题。

weixin_42552716的博客 487

C++对象模型详解

C++对象模型详解 原文链接:吴秦大神的C++对象模型。 何为C++对象模型? C++对象模型可以概括为以下2部分: 1、语言中直接支持面向对象程序设计的部分; 2、对于各种支持的底层实现机制。 语言中直接支持面向对象程序设计的部分,如构造函数、析...

dichuangheng8094的博客 605

达梦数据库与sharding-jdbc的深度适配实践

本文详细介绍了达梦数据库与sharding-jdbc的深度适配实践,包括驱动与依赖管理、核心适配实现、注册与配置等关键步骤。通过扩展shardingSphere的方式,成功实现了达梦数据库的分库分表功能,并提供了常见问题解决方案和性能优化建议,助力企业级应用高效处理海量数据。

weixin_30300225的博客 623

一文了解向量数据库在RAG中扮演的角色

向量数据库:AI新纪元的基石。探索如何通过这一创新技术优化RAG,提高语言模型的信息处理能力

2401_82452722的博客 2452

c++_learning-对象模型探索

深入介绍了c++类对象的内存布局,以及虚函数的引入对内存布局分布的影响。c++因虚函数的引入,产生的动态多态的性质分析。函数模板、类模板的分析。

qq_44599368的博客 1627

逆向工程师必备:用MDL绕过游戏保护读取内存数据的完整流程(附POC代码)

本文深入探讨了内核级内存访问技术,重点介绍了如何利用MDL(Memory Descriptor List)机制稳定、隐蔽地绕过游戏反作弊系统读取进程内存。通过对比MmCopyVirtualMemory等方法的优劣,提供了完整的MDL映射实战代码与反检测策略,为逆向工程师在内核态进行安全内存操作提供了专业指导。

weixin_29227425的博客 624

深度探索C++对象模型

c++对象模型语言中直接支持面向对象程序设计的部分对于各种支持的底层实现机制说白了是介绍编译器是如何支持、实现C++的面向对象机制的。如,继承、虚函数、指向class members的指针等等,编译器是如何实现的。本书C++语法基于C++95本书出版自2001年,虽然书中用到的标准早已盖棺定论,cfront编译器也早已过时,当时来看一些无法确定的标准、难以实现的技术、功能也早已实现,但是对C++对象模型的某些实现方式依然沿用至今。这本书依然不过时。

surfaceyan的博客 1825

学习心得——COMSOL Multiphysics with MATLAB联合仿真及寻优计算

学习心得——COMSOL Multiphysics with MATLAB联合仿真及寻优计算

weixin_41678956的博客 8658

解决usbisp不识别无法烧录Atmega328P,Arduino不识别问题

如果使用Arduino IDE里面的烧录,可能会遇到一个问题,就是不识别国产这种廉价的USBISP 点击烧录引导程序,会遭遇到找不到USB设备的问题,选哪个都会提示找不到,比如选择USBasp could not find USB device with vid=0x16c0 pid=0x5dc vendor='www.fischl.de' product='USBasp' 因此,我们需要使用到progisp这一个软件的1.72版本 选择好芯片的型号后,调用编译好的HEX文...

arenascat的博客 7436

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

https://www.cnblogs.com/wickedpriest/p/6527181.html https://www.cnblogs.com/wickedpriest/p/6580134.html 前言 今年中下旬就要找工作了,我计划从现在就开始准备一些面试中会问到的基础知识,包括C++、操作系统、计算机网络、算法和数据结构等。C++就先从这本《深度探索C++对象模型》开始。不同于...

$firecat利白的代码足迹$ 919

代谢组数据分析(五):代谢组的功能富集分析

本文介绍了代谢组数据分析中的功能分析,包括代谢物富集分析、GSEA和ssGSEA方法。文章详细阐述了分析原理、应用背景、数据准备、统计方法以及结果解释,强调了在代谢通路和代谢物ID对应关系建立、差异代谢物筛选、富集程度计算等方面的关键步骤。通过这些方法,可以揭示差异代谢物在生物过程中的作用,为疾病研究和药物开发提供依据。

专注生信领域 5981

深度搜索C++对象模型 - 复制构造函数

 深度搜索C++对象模型: 复制构造函数 由构造函数篇可以猜到, 复制构造函数其实也"不一定"会被编译器产生.. 提到复制,自然是类成员之间的复制, 有三种情况 会把一个 class object 的内容作为另一个 class object 的初值: --> 对一个 class object 做显示的初始化操作: class A { }; A a; A b = a; --> 对

github_21089181的专栏 360

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

深度搜索C++对象模型2.2 构造函数语义学-Default Constructor的构造操作

implicit 暗中的 explicit 显式的 trivial 没用的 no

春秋战车 965

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

深度搜索C++对象模型2.2 构造函数语义学-Copy Constructor的构造操作

Shallow Copy = Bitwise Copy,Deep Copy = Memberwise Copy.

春秋战车 1066

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

通过对象指针的方式强行指定到子类_c++对象模型

使用c++有些年头了,有一本深度搜索c++对象模型的书写的很赞,很经典。本文是本书的读书笔记。关于对象加上封装后的布局成本c语言中如下声明一个结构体typedef struct point3d{ float x; float y; float z;}Point3d;struct point3d 转化为class Point3d之后class Point3d{ public: Point3d(flo...

weixin_39517289的博客 94

c++中如何实现一个不能被继承的类

方法一:用单例模式,这里不做阐述。 方法二:c++11标准提供关键字final。 方法三:友元加虚继承,这篇文章重点介绍这个方法。声明一个类A,构造函数声明为private,在类中声明友元类Bclass A {       private:            A(){};                   friend class B; };我们在让B虚继承Aclass B:virtual

f905699146的博客 599

深度探索C++对象模型学习笔记总结

#非

HYB3701的博客 1266

深度搜索C++对象模型 - 构造语义学

 深度搜索C++对象模型:  构造,拷贝,析构语义学 //*********************************************************************************************// ---> "构造函数语义学": class A {     public:     virtual ~A() = 0;     v

github_21089181的专栏 473

[读书系列] 深度探索C++对象模型 初读

  2012年底~2014年初这段时间主要用C++做手游开发,时隔3年,重新拿起《深度探索C++对象模型》这本书,感觉生疏了很多,如果按前阵子的生疏度来说,现在不借助Visual Studio之类的工具的话,写C++代码感觉要比较费劲,最近重读了这本书后,感觉要写点东西下来(因为懒得用笔作笔记,太慢了-_-!)加深下印象。   以前还是新手的时候,总是认为: 1.class如果没有定...

139

对象传参_c++对象模型

使用c++有些年头了,有一本深度搜索c++对象模型的书写的很赞,很经典。本文是本书的读书笔记。关于对象加上封装后的布局成本c语言中如下声明一个结构体typedef struct point3d{ float x; float y; float z;}Point3d;struct point3d 转化为class Point3d之后class Point3d{ public: Point3d(flo...

weixin_32821643的博客 180

深度搜索C++对象模型(理念总结)

1. 目标: C++的语法规格(C++ 标准)如何具体实现出来的, 即编译器如何理解并构建一系列的数据结构, 去扩充/优化/翻译cpp源代码,然后组成串行指令,确保最终代码能够准确而高效执行. 大致包括1). 编译器功能的思考和设计逻辑                         2).cpp源代码的编译+链接(不用生成汇编)的步骤. 2.构造函数语义学: 遵循语意(C++ 标准

noticmp的专栏 769

《深度探索c++对象模型》与《Effective c++》读书笔记

Copy Constructor与条款4:确定对象被使用前已先被初始化 当class object 以"相同class的object"作为初值,其内部通过default memberwise initialization

weixin_37427660的博客 277

重读深度探索C++对象模型:构造

默认构造函数的生成: 在没有显示定义的情况下,编译器只会在四种情况下生成一个默认构造函数。 如果类成员X中没有特殊情况,则编译期只会生成一个不做任何工作的默认构造函数,这个默认构造函数是trivial的。 而只在四种情况下才会生成一个non-trivial的默认构造函数。 1.class的某个成员带有默认构造函数: 比如 class Foo { public: ...

weixin_30918415的博客 147

读《深度探索C++对象模型》有感

我想有看过不少C++的书籍,都会有以下的表述: 在Class中,如果我们没有声明构造函数,编译器都会给我们默认构造一个构造函数,也就是Default Construct,但是真的是如此吗,请看以下的example: lass AA { public: int x; AA *next; }; int main() { AA a; std::cout << a.x << std::end

smsmn的专栏 950
上一篇: 深度搜索C++对象模型 - 关于对象
下一篇: 深度搜索C++对象模型 - 复制构造函数
zhang_yao_wu1993
博客等级 码龄12年 0粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值