5.1 无继承情况下的对象构造

【JS继承】JS继承之构造函数继承 一、构造函数js中定义一个function,当使用new关键字调用这个function的时候,这个function成为一个构造函数。如下所示: 二、new关键字当使用new关键字调用构造函数生成一个对象实例时,js做出的关键处理如下: 1.创建一个新的对象,将构造函数内this指针指向新建对象。 2.将新建对象的__proto__属性设置成构造函数的prototype属性,确保新建对象是构造函数实例。 3.运行一遍构造函数,如果构造函数本身需要返回一个object或者array对象,则舍去新创建对象 阅读详情

Q1:POD对象的构造

• 以下讨论围绕下述例子展开:

 Eg:

            struct point
            {
                float x, y, z;
            };


            point global;
            int main()
            {
                point local;
                point * heap = new point;
                *heap = global;
                delete heap;
                return 0;
            }

• 观念上,编译器会为 point 声明一个 trivial 默认构造函数,一个trivial 析构函数,一个 trival 复制构造函数,以及一个 trival 赋值操作符函数

• 实际上,这些 trivial member 要不就是没定义,要不就是没有调用,程序行为与 C 中表现的一样

• 与 C 中的区别为:

• 在 C 中,全局变量 global 被视为 “临时性的定义(因为没有显示的初始化操作)”,将被放在 BSS 段中

•在 C++ 中,全局变量 global 被视为完全定义的,由于类构造行为的隐式应用,因此,C++不支持“临时性定义”

• C与C++一个区别:BSS段在 C++ 中相对不重要

*注:也即是说,在 C++ 中所有的全局对象都被以“初始过的数据”来对待

• 例子中各个变量的性质:

    • global : 初始化过的对象
    • local : 既没有被构造也没有被析构
    • heap = new point :传回的类对象: 没有被构造
    • *heap = local : 观念上,触发了 trivial 赋值操作符函数做拷贝操作;事实上,赋值操作执行纯粹的位搬移操作
    • delete heap : 观念上,触发了 trivial 析构函数;事实上,未定义或调用

• 该对象会分析类 point 的声明,并为其贴上 POD 的标签,之后的构造操作如上述,执行简单的位搬移操作



Q2:ADT(抽象数据类型)

• 以下围绕以下例子讨论:

Eg:

        class Point
        {
        public:
            Point(int i = 0, int j = 0, int k = 0) :x(i), y(j), z(k){}

        private:
            int x, y, z;
        };

该类中仅定义了默认构造函数,并未定义复制构造函数,赋值操作符函数与析构函数,这些函数时 trivial的,事实上,编译器根本没有定义这些函数

• 这种情况下,其余三种成员函数将不被定义,其对应操作采用“逐比特行为”

• 考虑类成员的显示初始化式

• 显示初始化式的使用要求:

1. 没有定义构造函数

2. 全体数据成员均为 public

3. 只能指定常量



• 显示初始化式的使用例子:

Point p = {1,2,3};   //假设数据成员 x,y,z 均是 public

• 显示初始化式与构造函数的效率问题:

Eg:

        void test()
        {
            Point local1 = {1,2,3};     //假设数据成员 x,y,z 均是 public;
            Point local2;       //该语句将调用默认构造函数对 local2 进行初始化

            //对local2 调用默认构造函数,相当于如下的 inline expansion
            local2.x = 0
            local2.y = 0
            local2.z = 0
        }

local1 的初始化:当函数的 activation record 放进程序堆栈时,上述显示初始化列表中的常量就可以被放入 local1 的内存中
local2 的初始化:对默认构造函数进行了内联展开,对初始化列表中的每一个成员逐一进行赋值操作

*说明:显示初始化式的效率比内联构造函数的高,但其存在很多使用要求与条件。

• 在编译器层面有一个优化机制:编译器会抽取构造函数中逐成员的常量指定操作中的常量值,并对相应成员直接进行显示初始化式中的初始化方式,即直接将常量值放入对应类成员的内存中,而不是将构造函数扩展为一系列的赋值指令。

Eg:

        {
            Point local;    //将调用默认构造函数对其进行初始化,其中初始化式中有逐成员指定常量值的操作 x(0), y(0), z(0)
        }

编译器优化调整,将不再扩展构造函数,改为:

        {
            Point local = {0,0,0};
        }

• 例子中各个变量的属性:

    point global;
    point test()
    {
        point local;
        point * heap = new point;
        *heap = global;
        delete heap;
        return local;
    }

• global:执行 point::point(0,0,0); 调用默认构造函数
• local:也要执行默认构造函数进行初始化
• heap:被附加一个对默认函数的有条件的调用操作。如下:

            point * heap = new point;
            if(heap != 0)
                heap->point::point(0,0,0);

• *heap = global:仍然是简单的位拷贝操作
• delete heap:不会导致析构函数的调用,因为没有显示的提供一个析构函数实例,并不会合成
• return local:简单的位拷贝操作




Q3:为继承做准备,引入虚函数的情况

• 围绕以下例子进行讨论:

    class Point
    {
    public:
        Point(int i = 0, int j = 0, int k = 0) :x(i), y(j), z(k){}

        virtual float func();

    private:
        int x, y, z;
    };

• 在数据成员均是用数值来存储的情况下,默认构造函数,复制构造函数,赋值操作符函数,析构函数均使用默认语义(逐比特操作)是合理的

• 加入虚成员函数后,每一个类对象要多负担一个 vptr,同时会引起对某些未定义成员函数的合成,以及对某些已定义成员函数的膨胀:

1. 默认构造函数的膨胀

自定义的默认构造函数在完成了基类构造函数的调用之后,被附加了对 vptr 进行初始化的代码,然后才是程序员提供的代码

Eg:

            point::point(point * this, int i = 0, int j = 0, int z = 0) : x(i),y(j),z(k)
                {
                    //紧跟在基类的构造函数被调用后执行以下步骤:
                    this->_vptr_point = __vtbl_point;

                    //用户定义的代码:
                    this->x = i;
                    this->y = j;
                    this->z = k;
                    return this;
                }


2. 编译器需要合成复制构造函数与赋值操作符函数(因为此处类中有虚函数,为之前讨论的需要合成的情况)

• 不能对有虚函数的类采用逐比特的复制构造函数,假设调用复制构造函数的类的参数是其派生类对象,则此时派生类对象中的 vptr 指向派生类的虚函数表,此时直接逐比特复制将会导致基类的 vptr 指向了派生类的虚函数表,是一个错误的 vptr 初始化,因此,编译器需要合成一个复制构造函数。

Eg:

point* point::point(point * this, const point & rhs)
{
    //直接指定 point 的虚函数表的地址为 vptr 的值,而不是使用 rhs 的 vptr 的值来初始化
    this->_vptr_point = __vtbl_point;    

    //将 rhs 对象中的数据成员的值逐比特拷贝到 this 对象

    return this;  
}

• C++标准要求编译器尽量延迟 nontrival member 的实际合成操作,直到真正遇到起使用场合

• 例子中各个变量的属性:

    point global;
    point test()
    {
        point local;
        point * heap = new point;
        *heap = global;
        delete heap;
        return local;
    }

• global, local, heap 的初始化操作均调用默认构造函数进行初始化,delete heap 操作也是逐比特操作(不合成析构函数)

• *heap = global:该操作将触发复制构造函数的合成

• return local:由于复制构造函数的出现,将会初始 test() 函数发生变化,激发 NRV 优化

• 若存在大量传值返回操作,则应该定义复制构造函数,因为这会触发 NRV 优化,而触发了NRV 优化后,将不再需要调用复制构造函数

c++无继承情况下的对象构造 1)C struct的Point声明 /* C++称这是一种所谓的Plain O1’ Data声明形式。如果以C++来编译,观念上,编译器会为 Point声明一个trivial default construct、一个trivial destructor、一个 trivial copy constructor,以及一个trivial copy assignment operator。 但实际上,编译器会分析这个声明,并为它贴上Plain OI’ Data标签 */ typedef struct { 阅读详情

相关推荐

C++继承体系下的对象构造

class Point{ public: Point(float x = 0.0,float y = 0.0); Point(const Point&); Point& operator=(const Point&); virtual ~Point(); virtual float z() {return 0.0;} protected: float _x,_y; }; 虚拟继承 假设具有如下继承体系: class Point{ p

希望我的博客,能帮上你解决学习中工作中所遇到的问题 440

C++中慎用逐位拷贝(bitwise copy)的函数

1.简单介绍C语言中的memcpy(),memset(),memcmp()函数   memcpy(),memset(),memcmp()等这些内存操作函数经常会帮我们完成一些数据复制、赋值等操作。因为C语言中,无论是内置类型,还是自定义类的结构类型(struct),其内存模型对于我们来说都是可知的,透明的。所以我们可以对该对象的底层字节序列一一进行操作,简单而有效。例如如下代码:struct ST

3023

【C#面向对象】第五课——类的继承、调用父类的构造方法、继承的特性

知识点:理解继承的概念 、 掌握在程序中实现继承、 掌握 base 和 protected 关键字 、掌握如何调用父类构造方法 、 掌握继承的特性 1、理解继承 面向对象有三大特性:封装、继承和多态。我们学习过封装,封装是信息隐藏,我们定义类的过程就是对数据的一种封装,今天我们将重点讨论继承。 继承反映的是类之间的层次关系,生活中就有很多继承的例子,如:我们知道汽车有型号、颜色、排量、油耗等属性,有行驶和刹车方法。而公交车是汽车的一种,除了有汽车基本的属性...

王迪 5956

深度探索C++对象模型(五)构造、析构、拷贝语意学

考虑下面这个abstract base class声明: class Abstract_base{ public: virtual ~Abstract_base()=0; virtual void interface() const =0; virtual const char* mumble() const {return _mumble;} protected:

Super的博客 1001

js对象高级:08、详解3种继承模式(原型链继承、借用构造函数继承、组合继承)

JavaScript继承的三种模式:原型链继承通过将子类原型指向父类实例实现继承,但会导致constructor指向问题;借用构造函数继承在子类中通过call()调用父类构造函数,只能继承属性无法继承方法;组合继承结合两者优点,利用原型链继承方法,借用构造函数继承属性。每种方式各有特点,原型链继承简单但有缺陷,组合继承是较优解决方案。实际开发中应根据需求选择合适的继承方式,理解原型链机制是关键。

狮子座的男孩 1016

焦距与视差的关系及其对深度估计的影响

焦距在立体视觉中的作用至关重要,它直接影响视差的大小,从而影响深度估计的精度。焦距越长,视差差异越大,物体的深度估计就越精确。这一关系使得焦距长的相机在一些需要高精度深度估计的应用场景中更加优越。了解焦距与视差的关系,对于优化相机配置和提升深度估计精度具有重要意义。在实践中,选择合适的焦距对于获得精确的深度信息至关重要,特别是在自动驾驶、虚拟现实、三维重建等领域,精确的深度估计能够提供更好的用户体验和技术支持。

计算机科学与技术专业学生的成长之路 1671

C++对象模型学习——构造、析够、拷贝语意学

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34321977的博客 236

使用sklearn学习多项式回归(三)

1,什么是线性 我们无数次提到”线性“这个名词。在支持向量机中,我们也曾经提到最初的支持向量机只能够分割线性可分的数据,然后引入了”核函数“来帮助我们分类那些非线性可分的数据。我们也曾经说起过,比如说决策树,支持向量机是”非线性“模型。所有的这些概念,让我们对”线性“这个词非常熟悉,却又非常陌生——因为我们并不知道它的真实含义。接下来我们看看线性回归模型改进的核心之一:帮助线性回归解决非线性问题。 1.1,变量之间的线性关系 ”线性“这个词用于描述不同事物时有着不同的含义。我们最常使用的线性是指“变量

理科男同学 5100

5.1 “无继承”情况下的对象构造

考虑如下的程序片段: Point global; //1 Point foobar() { Point local; //2 Point* head = new Point; //3 *head = local; //stuff delete heap; //4 return local; } 上述表现出三种不用的对象产生方式:global对象、local对象和heap对象。...

hallå的博客 272

别再买模块了!手把手教你用FT232RL-REEL芯片,从零设计一个USB转串口电路板

本文详细介绍了如何使用FT232RL-REEL芯片从零设计USB转串口电路板,涵盖核心器件选型、原理图设计、PCB布局布线及焊接调试等关键步骤。通过实战案例和性能对比,展示自制电路板在成本、性能和可靠性上的优势,特别适合硬件爱好者和工程师参考。

weixin_30561425的博客 432

Unity集成抖音小游戏:从IL2CPP配置到SDK接入全流程解析

本文详细解析了使用Unity开发抖音小游戏的完整流程。从关键的IL2CPP编译后端配置、PlayerSettings设置,到StarkSDK的接入与资源优化(如AutoStreaming),再到激励视频广告、录屏分享等核心功能的代码实现,提供了从环境准备到打包上传的全方位实战指南,帮助开发者高效完成技术适配。

weixin_27943395的博客 690

第5章 构造、析构、拷贝语义学1: “无继承”情况下的对象构造

🍉重点:const与virtualpublic:private:一般而言,类的data members应该被初始化,并且只在constructor中或者类的其他member functions中指定初值。其他任何操作都将破坏封装性,使class的维护和修改更加困难。不将一个函数声明为const,意味着此函数不能够获得一个const reference或const pointer。将一个函数声明为const,意味着不能对data members进行更改。

qq_40178082的博客 740

华为MetaERP PTP采购到应付全流程解析

摘要:本文系统解析华为MetaERP中的PTP(采购到应付)全流程管理方案,涵盖从采购申请到付款执行的完整业务流程。文章详细分解了PR、PO、GR、IV、AP等关键环节的财务核算规则,并提供了预算校验、库存更新等Python代码示例。同时阐述了IT落地架构设计,包括会计引擎配置、系统集成方案及银企直连支付接口实现。该方案通过三单匹配自动化和智能会计引擎,将处理效率提升10倍(200笔/人天→2000笔/人天),实现98%的自动化率,为集团企业提供了高效的数字化财务管理样板。文中所有技术方案均需根据实际场景调

金牌架构师 1743

在C++中子类继承和调用父类的构造函数方法

构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承(子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法)。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。 如果没有显式的构造函数,编译器会给一个默认的构造函数,并且该默认的构造函数仅仅在没有显式地声明构造函数情况下创建。 构造原则如下: 1.如果子类没有定义构造方...

大隐隐于野 9239

Pyhon在振动信号处理中的高级应用(一):振动信号特征(时域、频域)提取

文章目录一、概述二、算法原理2.1 时域统计特征三、python代码实现 一、概述 二、算法原理   这里我们借鉴西安交通大学机械学院雷教授的论文《Fault diagnosis of rotating machinery based on multiple ANFIS combination with GAs》相关研究成果。雷教授在论文中共列举了4类共24种振动信号的时域和频域特征。 2.1 时域统计特征 p1=∑n=1Nx(n)NP2=∑n=1N(x(n)−p1)2N−1p3=(∑n=1N∣x(n)∣N

白银时代的博客 1万+

【Agent从入门到实践】01 从“工具函数”到“智能体”:Agent与传统程序的核心区别

传统程序是“你教它怎么做,它才做什么”,Agent是“你告诉它做什么,它自己想怎么做”。从技术层面来说,这个区别的背后,是Agent融合了大语言模型(LLM)、记忆能力、工具调用能力、决策能力等技术,才实现了“自主思考”和“灵活执行”,而这些技术,咱们会在后面的章节中一步步拆解,手把手教大家实现。

人工智能AI技术 987

15、无继承情况的对象构造

public:private:这个经过封装的Point class,其大小并没有改变,还是三个连续的float。是的,不论是private或public存取层,或是member function的声明,都不会占用额外的对象空间。

u012750235的博客 649

OpenCV-Python实战(10)——详解 OpenCV 轮廓检测

在计算机视觉领域,轮廓通常指图像中对象边界的一系列点。因此,轮廓通常描述了对象边界的关键信息,包含了有关对象形状的主要信息,该信息可用于形状分析与对象检测和识别。在本文中,将首次通过简单示例了解轮廓的基本概念,然后通过实际示例来了解如何检测和压缩轮廓,最后利用介绍如何利用图像矩描述检测到的轮廓属性。

盼小辉丶的博客 3万+

ES5中的构造函数实现继承

先复习一下ES5里的构造函数 //ES5中的构造函数 /* *写一个名为Monster的构造函数 *有属性:name、hp *有方法:init *给Monster构造函数的的原型链上添加名为mp的属性和名为finish的方法 */ function Monster(name='小羊',hp=500){ this.name = name this.age = age this.init = ...

weixin_45254698的博客 596

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

构造函数的继承

在将继承之前先说一下ES5和ES6的构造函数语法 ES5的构造函数语法 function CreateObj1(name,age){ this.name = name; this.age = age; } createObj1.prototype.fun = function(){ console.log('我是ES5语法创建的实例化对象') } ES6的构造函数语法 class CreateObj2{ constructor(name,age){ this

jhl13475236412的博客 1079

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

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

js对象继承的5种方法

1、原型链继承 假设现在有a,b两个函数,b函数的实例如果想要访问a函数的属性和方法。就可以通过b函数的原型(b.prototype)指向a的实例(new a())来实现,这种继承方法就称为原型链继承。 代码实现: 这里用 parent 和 child 分别表示上述的 a 和 b function parent(){ this.a = '111' } function child(){} child.prototype = new parent() var c = new child() c

jiangjunyuan168的博客 4906

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

C++之子类继承与父类构造

本文详细介绍了C++子类实例化时,如何调用父类的构造函数。主要场景包括单继承,多继承,链式继承

qq_44914161的博客 1358

面试向:原型、原型链、构造函数、继承、实例对象

介绍了原型、原型链、构造函数、继承、new的实例化过程

接着奏乐接着舞的博客 1686

JavaScript对象继承 - ES5构造函数

Prototype:js继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享,不仅节省了内存,还体现了实例对象之间的联系。 JS中规定,每一个函数都有一个prototype属性,指向一个对象。 我们来看下下边代码: function test(){} console.log(test.prototype) //{constructor: ƒ} 打印结果: 上边的代码...

记录点滴 444

C/C++编程:无继承情况下的对象构造

结构体 对于下面程序片段 L1、L2、L6表现出三种不同的对象产生方式: 全局(global)内存配置 本地(local)内存呢配置 堆(heap)内存配置 L7将一个类对象指定给另一个,L10设定返回值,L9则明确以delete运算符删除堆对象 一个对象的生命,是该对象的一个执行期属性: 全局对象的生命和整个程序的生命相同 本地对象的生命从L5的定义开始,到L10结束 堆对象的生命从它被new配置出来开始,到delete销毁为止 下面是Point的第一次声明,可以写成C程序。C++标准说设置一种

OceanStar的博客 231

JS面向对象及继承

创建对象的方法及对象继承的方式。像组合继承不共享引用类型属性,它结合原型链继承和构造函数继承的优点,通过在子构造函数中调用父构造函数来继承属性,同时将子构造函数的原型设置为父构造函数的实例......

qq_53911056的博客 917
上一篇: C/C++改变终端输出字体的颜色(Linux)
下一篇: 5.2 继承体系下的对象构造
Virtual_Func
博客等级 码龄11年 38粉丝 113原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值