精华内容
下载资源
问答
  • C++函数的返回类型为一个类时

    千次阅读 2009-12-20 20:10:00
    仅仅测试一下,当函数返回类型为一个类时的情况。#includeusing namespace std;class A{public: int i; int *n; A() // 构造函数 { n= new int; *n = 101; } ~A()

    仅仅是测试一下,当函数返回类型为一个类时的情况。

    展开全文
  • #include using namespace std; //定义 ...//定义默认构造函数 ...还有就是返回值作为左值问题,c++提供默认数据类型作为返回值 不能作为左值,用户自定义数据类型可以,有什么要求和注意事项吗?
  • 〇、基础知识0.1 X86 寄存器基础(1)ESP:栈顶指针,X86中的栈向下增长,所以入站push esp--,出栈pop,esp++(2)EBP:函数的参数和局部变量都存储在程序栈中,所以一个函数想要获取它自己的参数或者...

    Return

    希望对此文档的阅读,可以对栈空间使用、函数调用以及返回内置类型或对象的过程有所掌握。

    〇、基础知识

    0.1 X86 寄存器基础

    (1)ESP:栈顶指针,X86中的栈是向下增长,所以入站push时 esp--,出栈pop时,esp++

    (2)EBP:函数的参数和局部变量都是存储在程序栈中,所以当一个函数想要获取它自己的参数或者局部变量时,想到的第一个方案就是使用(ESP寄存器的值+栈偏移量)推算出参数和局部变量的地址。但是栈顶指针的值会随着程序入栈和出栈操作不断变化。所以为了计算方便,可以将该值保存到另一个寄存器---EBP(extended base pointer,扩展基址寄存器)。这样获取参数可以用:EBP+偏移量,获取局部变量就可以用  EBP-偏移量了。(下图中的数据是根据第一部分的代码得到的)

    (3)EBX ,基址寄存器,在内存中寻址时使用。

    (4)ESI/EDI,源/目的地址寄存器,暂时不清楚有什么用

    (5)ECX,(extendedcounter )计数器寄存器,和rep和loop指令搭配使用。主要用来进行循环计数

    0.2汇编语言

    1)call 指令,格式 :call+目标地址,作用:将程序调转到目标地址处执行。call指令使用的是相对寻址,所谓的相对寻址就是:基址+偏移量 = 最终地址。在call指令中,基址就是call指令的下一条指令的起始地址。偏移量就是call指令中后4字节的内容。call指令返回地址会在指令执行过程中被压到程序栈中。等价指令:push EIP+5 ,jmp 目标地址

    2)ret指令,作用:将栈顶保存的地址弹入EIP指令寄存器,这个过程ESP要增大(因为执行了一次出栈操作)

    3)rep 指令,格式 rep+其他指令,作用:重复rep后面的其他指令,重复次数记录在ECX寄存器中,每次循环ECX寄存器执行减减操作。

    4)stos指令,格式 stos+目的地址,将寄存器EAX中的内容保存到目的地址处。目的地址格式 ES:[EDI] ,ES保存了段选择符,EDI保存了段偏移量。如果设置了direction flag, 那么EDI会在该指令执行后减小, 如果没有设置direction flag, 那么EDI的值会增加, 为下一次的存储做准备

    5)MOV指令的功能是传送数据,例如MOV AX,[1000H],作用是将1000H作为偏移地址,寻址找到内存单元,将该内存单元中的数据送至AX。

    6)LEA指令的功能是取偏移地址,例如LEA AX,[1000H],作用是将源操作数[1000H]的偏移地址1000H送至AX;

    7)mov与lea 对[]的区别(针对第二个参数):1对于mov指令来说:有没有[]对于变量是无所谓的,其结果都是取值;对于寄存器而言,有[]表示取地址,没[]表示取值。2. 对于lea指令来说:有没有[]对于变量是无所谓的,其结果都是取变量的地址,相当于指针(与mov相反);对于寄存器而言,有[]表示取值,没[]表示取地址

    一、返回内置类型:

    现给出结论:内置类型的返回,会使用到CPU的寄存器eax进行两个栈空间内的赋值。

    测试使用的部分源码如下:

    int TestBuiltInReturnValue(int a, int b, intc)  //返回值

    {

       return a;

    }

     

    int* TestBuiltInReturnPointer()//返回指针

    {

       int  a=10;

       return &a;

    }

     

    int& TestBuiltInReturnreference()//返回引用

    {

       int d =1;

       returnd;

    }

     

    void Do_BuiltIn()//main函数会调用此函数

    {

       int a =0; 

       a =TestBuiltInReturnValue(1, 2, 3);

       int b =TestBuiltInReturnValue(1, 2, 3);

     

    int *p =TestBuiltInReturnPointer();

     

       int&d = TestBuiltInReturnreference();

       inte = TestBuiltInReturnReference();

    }

     

    1.1返回值

    为了方便之后内容的展开,现对调用a=TestBuiltInReturnValue(1,2,3);以及以上的过程进行占内存的展示。

    调用的函数为

    int TestBuiltInReturnValue(int a, int b, intc)  //返回值

    {

       return a;

    }

     

    void Do_BuiltIn()//main函数会调用此函数

    {

       int a =0; 

       a =TestBuiltInReturnValue(1, 2, 3);

    }

    由此过程可知:在进行内置数据的返回时,会把待返回的值赋值给CPU的寄存器eax。之后通过eax把该值赋值给目标变量。

       代码intb = TestBuiltInReturnValue(1, 2, 3)的汇编语言如下所示:


    经查看,此过程与a= TestBuiltInReturnValue(1,2,3)一样。因此上述的结论在此处一样适用。

    1.2返回指针

    调用的函数为:

    int* TestBuiltInReturnPointer()//返回指针

    {

       int  a=10;

       return &a;

    }

    int *p = TestBuiltInReturnPointer()

    汇编代码。如下图



    此时,使用到了汇编指令LEA。LEA指令的功能是取偏移地址,例如LEA AX,[1000H],作用是将源操作数[1000H]的偏移地址1000H送至AX。理解时,可直接将[ ]去掉,等同于MOV AX,1000H。再如:LEA BX,[AX],等同于MOV BX,AX。此处是把a的地址保存到寄存器EAX中。之后,调用int *p = TestBuiltInReturnPointer();时,把TestBuiltInReturnPointer内变量a的地址返回出去了。

    1.3 返回引用

             返回引用时,相关代码的汇编代码如下:


             由图六红框的内容可知,TestBuiltInReturnReference()函数返回的是函数内部变量d的地址。之后把该地址返还给调用函数的外部变量d。引用的本质是指针常量 * const

           如果不用引用取接收返回的引用数据呢?如int e= TestBuiltInReturnReference(),该语句的汇编代码如下:

     

             可知,TestBuiltInReturnReference()函数返回地址后,会通过mov eax,dword ptr[eax]从该地址读数据,并把该数据赋值给int e。

    虽然对于内置类型,返回引用时由于返回的时地址(被调用函数的栈空间)。

    在此时返回出的地址是可以使用的,但随着程序的执行。被调用函数的栈空间被释放(该函数的ebp被覆盖,再也无法找到)。当调用其他的函数时,该地址的值是会发生变化的。

    二、返回类对象:

    测试源码如下:

    class Person

    {

    public:

       intm_nAge;

       intm_nId;

    public:

     

       Person(intage,int id)

       {

          m_nAge= age;

          m_nId= id;

          cout<< "构造函数" << endl;

       }

       Person(constPerson& person)

       {

          m_nAge= person.m_nAge;

          m_nId= person.m_nId;

          cout<< "拷贝构造函数" << endl;

       }

       ~Person()

       {

          cout<< "析构函数" << endl;

       }

    };

     

    Person ReturnObjectValue1()

    {

       Personp(10,1);

       returnp;

    }

     

    Person ReturnObjectValue2()

    {

       returnPerson(10, 1);

    }

     

    Person* ReturnObjectPointer()

    {

       Personp(20, 2);

       return&p;

    }

     

    Person& ReturnObjectReference()

    {

       Personp(30, 3);

       returnp;

    }

     

     

    void Do_Object()

    {

       //值传递

       Personvalue1(20, 2);

       value1 =ReturnObjectValue1();

       cout<< "*******************************************" << endl;

       Personvalue2 = ReturnObjectValue1();

       value1 =ReturnObjectValue2(); Person value3 =ReturnObjectValue2();

      

       //指针传递

       Person*p = ReturnObjectPointer();

     

       //引用传递 

       Person&referencre = ReturnObjectReference();

    }

     

     

     

     

     

     

     

     

     

     

     

     

     

    2.1 返回对象

             先给出结论:

    情景如下:A函数调用函数B,并且B中返回对象(假设并非调用new 或malloc在堆中创建一个对象,即返回的对象是在栈中)。

    执行到return时,会调用构造函数。生成一个匿名对象,但是此匿名对象所在的地址并非在B的栈中,而是在A函数中。匿名对象的生命周期看他之后是如何被处理的。

    当赋值给一个已经存在的对象时,赋值完成则该匿名对象被析构掉;当初始化一个对象a时,则该对象a就是此匿名对象。

    之后是详解:为了对这个过程有一个比较透彻的了解,现在对上述部分测试源码进行栈空间的绘制。

    (绘制的栈空间所对应的源码为

    Person ReturnObjectValue1()

    {

       Personp(10,1);

       returnp;

    }

     

    void Do_Object()

    {

       Personvalue1(20, 2);

       value1 =ReturnObjectValue1();//赋值给一个已经存在的对象

    }

     

     

    当返回的值初始化一个对象时,汇编代码如下:

    调用的函数语句为Personvalue2=ReturnObjectValue1()

    对比上述可知:此时并非传入一个匿名对象的地址([ebp-138h])而是直接把新对象的地址&value2传入被调用函数,因此被调用函数执行完后,并未上一个例子的两个对象的赋值过程。

    2.2 返回对象指针

    调用的函数为

    Person* ReturnObjectPointer()

    {

       Personp(20, 2);

       return&p;

    }

    Person *p = ReturnObjectPointer();

    汇编代码如下:


    此过程与返回内置类型的过程类似,是通过寄存器eax完成对象地址的赋值。

    2.3 返回对象的引用

    调用的函数如下

    Person& ReturnObjectReference()

    {

       Personp(30, 3);

       returnp;

    }

     

    Person& referencre = ReturnObjectReference();

    对应的汇编代码为:


    即:把被调用函数内部对象p的地址赋值给referencre,,但是此时p已经析构掉。因此通过分析可知:函数返回一个对象的引用的时候,最好该对象不是局部变量或临时变量。

    做个小结:

    1.我们都知道函数返回时,会销毁局部变量。那么到底是怎么销毁的局部变量?从汇编中稍微分析下就发现原来只是简单的用调用函数所在栈的EBP值覆盖掉被调用函数所在的栈空间的EBP值,函数定位局部变量就是用EBP寄存器作为基址,没了EBP,那么也就找不到局部变量了,换句话说也就是局部变量被销毁了。

    2.函数的调用环节可以分为:(1)传参(2)保存上下文(3)向返回值空间写值(4)恢复上下文(5)从临时空间拷贝数据

    其中,传参和返回数据的方式有两种:通过寄存器(由于寄存器大小和数量的限制,所以只能小型参数)和通过栈;返回值的方式也有两种寄存器和栈。

    3.函数返回一个对象的引用的时候,最好该对象不是局部变量或临时变量。

    4. 通常来讲,除非是迫不得已,否则最好不要采用传值的方式传递和返回对象,这是因为采用传值的方式传递和返回对象的过程中需要经历对象间的拷贝操作,这样会在一定程度上降低程序运行的效率,从而使得待处理数据量增大,增加内存的使用

     

     

     

    展开全文
  • 通过对比,我们发现使用函数返回值初始化cat3,少执行了一次析构函数,应该是函数返回值临时变量未进行析构。并且使用函数返回值初始化cat3并没有再次调用复制构造构造函数,就像给没有名字的函数返回值临时...
  • 你参考下这样来:NameError: name 'Position' is not defined官方...还有这样方法:转发引用当类型提示包含尚未定义名称,该定义可以表示为字符串文本,稍后解析。发生这种情况情况通常容器类的定义,其中...

    你参考下这样来:NameError: name 'Position' is not defined

    官方建议:使用一个字符串

    只需使用字符串而不是类本身:...

    def __add__(self, other: 'Position') -> 'Position':

    ...

    还有这样的方法:转发引用

    当类型提示包含尚未定义的名称时,该定义可以表示为字符串文本,稍后解析。

    发生这种情况的情况通常是容器类的定义,其中定义的类出现在某些方法的签名中。例如,以下代码(简单二叉树实现的开始)不起作用:class Tree:

    def __init__(self, left: Tree, right: Tree):

    self.left = left

    self.right = right为了解决这个问题,我们写道:class Tree:

    def __init__(self, left: 'Tree', right: 'Tree'):

    self.left = left

    self.right = right字符串文字应该包含一个有效的Python表达式(即,compile(lit,'','eval')应该是一个有效的代码对象),并且在模块完全加载后它应该没有错误地评估。在其中进行评估的本地和全局命名空间应该是相同的命名空间,其中将对同一个函数的默认参数进行评估。

    在类定义之前,放置一个伪定义:class Position(object):

    pass

    class Position(object):

    ...

    这将摆脱,NameError甚至可能看起来不错:>>> Position.__add__.__annotations__

    {'other': __main__.Position, 'return': __main__.Position}

    但是吗?>>> for k, v in Position.__add__.__annotations__.items():

    ... print(k, 'is Position:', v is Position)

    return is Position: False

    other is Position: False

    B. Monkey-patch为了添加注释:

    你可能想尝试一些Python元编程魔术并编写一个装饰器来为类定义添加猴子补丁以添加注释:class Position:

    ...

    def __add__(self, other):

    return self.__class__(self.x + other.x, self.y + other.y)

    装饰者应该对此负责:Position.__add__.__annotations__['return'] = Position

    Position.__add__.__annotations__['other'] = Position

    至少看起来是对的:>>> for k, v in Position.__add__.__annotations__.items():

    ... print(k, 'is Position:', v is Position)

    return is Position: True

    other is Position: True

    展开全文
  • 【问答题】在滑动轴承中什么瓦背?其特点有哪些?【多选题】起重机采用变频调速改造后...【多选题】质体包括【填空题(主观)】通过MyClass中不含参数构造函数,生成该类的一个对象obj,可通过以下语句实现:...

    【问答题】在滑动轴承中什么是瓦背?其特点有哪些?

    【多选题】起重机采用变频调速改造后,有哪些效果?

    【判断题】当热继电器动作不准确时,可用弯折双金属片的方法来调整。

    【单选题】X62W型万能铣床进给电动机容量为( )

    【判断题】电弧电压升高,焊缝熔宽增加,焊缝余高相应减小。

    【多选题】质体包括

    【填空题(主观)】通过类MyClass中的不含参数的构造函数,生成该类的一个对象obj,可通过以下语句实现: [填空(1)] 。

    【问答题】轴承材料的性能要求有哪些?

    【单选题】剖分式轴瓦周向定位一般采用( )

    【填空题(主观)】Java中 [填空(1)] 是创建对象的模板。

    【填空题(客观)】道岔是一种使 能从一股道转入 的线路连接设备,在 大量铺设。最常见的是 。

    【多选题】变频器模拟量输出可代表的物理量有

    【单选题】MM440 变频器用外部端子实现启停控制以及用面板进行频率给定设置,对应的工作模式参数设置为( )

    【单选题】关于实例方法和类方法的描述正确的是()。

    【判断题】变 频器在显示面板上显示的输出电流、电压、频率等各种数据是否正常。(

    【多选题】组态软件:一般英文简称有三种分别为(  )。

    【填空题(主观)】对象创建完后,通过使用运算符 “ . ” , 对象可以实现对变量的访问和 [填空(1)] 的调用。

    【判断题】剖分式径向滑动轴承构造简单、成本低,但磨损后无法修整,且装拆不方便

    【填空题(客观)】滑动轴承按所受载荷的方向分为( )和( )

    【单选题】某普通合伙企业为内部管理与拓展市场的需要,决定聘请陈东为企业经营管理人;已知,合伙协议未对该事项作出约定。根据合伙企业法律制度的规定,下列说法正确的是( )。

    【判断题】焊条电弧焊不适合仰焊。

    【判断题】滑动轴承主要应用于高速、重载、要求剖分结构等场合中

    【判断题】绘制电气安装接线图时,一个元件的所有部件绘在一起,并用点画线框起来。

    【多选题】关于左旋多巴描述正确的是:

    【单选题】糖酵解过程中那个过程发生了脱氢过程:

    【判断题】推力滑动轴承用来承受周向载荷

    【问答题】市场调研的作用是什么?

    【单选题】根据合伙企业法律制度的规定,下列各项中,不属于合伙企业财产的是( )。

    【填空题(主观)】类体有两部分构成:一部分是变量的定义,另一部分是 [填空(1)] 的定义。

    【填空题(客观)】径向滑动轴承的主要结构形式有( )和( )两大类

    【单选题】下列单位中哪个不是国际制单位?

    【问答题】1.如何在CAD2014版本中打开 “帮助”。请用文字回答

    【填空题(客观)】滑动轴承最常见的失效形式是( )、胶合(烧瓦)、( )和由于制造工艺原因而引起的轴承衬脱落

    【单选题】下面关键字中哪一个是不可用来控制对类成员的访问()。

    【单选题】为避免推力滑动轴承工作面上压强严重不均,通常采用( )

    【单选题】与开关量端子 5 、 6 、 7 、 8 对应的参数是 ( )

    【问答题】市场调研的内容包括哪些?

    【单选题】下列不是高能化合物的是

    【填空题(客观)】

    【填空题(主观)】java中 [填空(1)] 方法与类名相同,没有返回值,在创建对象实例时由new运算符自动调用。

    【单选题】植物细胞在生活过程中,由于新陈代谢活动而产生的各种非生命物质,统称为

    【填空题(主观)】在Java中,当一个方法不需要返回数据时返回类型必须是 [填空(1)] 。

    【单选题】导游在各旅游企业之间起着重要的协调作用,这主要体现的是导游的()的作用。

    【单选题】根据合伙企业法律制度的规定,有限合伙人在出现一定情形时当然退伙。下列各项中,不属于当然退伙情形的是( )。

    【单选题】下列不属于对开式正滑动轴承的结构是( )

    【单选题】X62W型万能铣床主轴电动机的正反转采用( )来实现

    【判断题】1. 低压开关的灭弧装置大都采用六氟化硫作为介质。( )

    【单选题】油菜花冠类型为

    【多选题】组态软件产品于( )年代初出现,并在80年代末期进入我国。但在90年代中期之前,组态软件在我国的应用并不普及。

    【单选题】X62W型万能铣床的工作进给( )可进行

    展开全文
  • 派生传递给以下函数发生什么?不要返回为什么运算符重载,返回value,形参引用?22 成员尽量用private23封装的程度怎么衡量?怎么方便地扩展工具包?24如果函数的形参都需要类型转换,则定义为non-member为...
  • C++的成员函数其返回值*this,表示返回值调用该成员函数的变量的引用。例如 classA { public: A& func1() { return*this; } int i{0}; } 此时,A的成员函数func1的返回值*this,该成员函数...
  • 当返回对象,C++编译器将调用默认的拷贝构造函数,将对象赋值给一个匿名对象并将其扔出去 这个类似于拷贝构造函数的第四种方法,此时如果外面没有同一个类型的对象将其接住,就会直接析构掉。 若定义的...
  • 这次内容要说的当类的成员函数做为谓词什么样子的,如何使用呢? 中一共会有三种函数:1.非静态非虚函数 非静态非虚函数的函数指针,因为成员函数里面会传递this指针,所以就算函数指针,也必须有对象来...
  • 3.中默认的函数

    2020-11-26 10:52:23
    1.构造函数的定义与使用 构造函数特殊的共有成员函数 (1). 函数名与类名相同; (2).构造函数无函数返回类型说明。注意没有而不是void,即什么也不写,也不可写void!实际上构造函数有返回 值,返回的就是构造...
  • 新的概念:成员函数形式的运算符重载 ...运算符重载为成员函数函数的参数个数比原来的操作数要少一个(后增、后减单目运算符除外)。因为成员函数用this指针隐式地访问了的一个对象,它就是运算符最左边的
  • 我将该包含到我的主页面并获取函数的返回值,我称它不是来自数据库的结果,而是一个布尔值。我收到此错误消息:Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in C:\xam.....
  • 定义的函数类似于某个内置运算符,应令该函数的行为尽量模仿这一运算符。 内置的赋值运算符将左侧运算对象当成左值返回,故combine函数(+=)需返回引用类型(*this)。 display函数用于打印的数据成员,并未...
  • 看stl源码,有一段代码感觉很奇怪 iterator begin() { return (link_type)((*node).next);...转换构造函数的作用将某种类型的数据转换为的对象,一个构造函数只有一个参数,而且该参数又不是本的co
  • 我正在学习Mybatis,使用select返回查询结果,我使用List<实体>返回查询结果,但是想要获取指定列值,就只能通过"每个对象 . getter函数",我列数非常多,我就觉得非常麻烦,能通过整数型索引值实现随机...
  • C++矩形 构造函数的定义与使用

    千次阅读 2018-11-06 19:58:28
    定义一个对象,C++ 会自动调用构造函数建立该对象并进行初始化,一个对象...②析构函数函数返回类型在这方面与构造函数是一样。 但析构函数不带任何参数。 ③一个有一个且只有个析构函数, 这也与构造函...
  • 构造函数的主要作用完成对的初始化操作4.在创建一个的新对象(使用new关键字),系统会自动调用 的构造函数初始化新对象; 析构函数:一种特殊的成员函数,对象销毁时候调用。...
  • ● 构造函数是一个类的特殊的类成员函数,该函数没有返回类型, 没有参数,也不能重载。一个也只能有一个析构函数。 ● 析构函数是为生命期即将结束的类对象返还相关资源或者自动释放资源, 类的对象离开...
  • Java中Math(随机数)和函数

    千次阅读 2018-01-02 20:03:41
    Java中的Math(随机数)和函数及函数的重载 Math(随机数) Math中,随机数的代码:random. 也就是 Math.random(); 这时一个 返回[0,1)double类型的值 一个伪随机数 伪随机数就是按照一定规则去随机的数...
  • 3.某一个的一个成员函数被定义为虚函数,则由该派生出来的所有派生中,该函数始终保持虚函数的特征。 4.在派生中重新定义虚函数(overriding a virtual function,亦译作超载或覆盖),不必加关键字...
  • 1.复制构造函数 ...具有类类型传值参数或者返回类类型,都需要调用复制构造函数,完成局部 对象初始化。 深复制和浅复制 当类的数据成员简单数据类型时,在创建对象,默认复制构造函数工作很好。
  • 1.什么虚函数:虚函数的定义在基类中进行的,被 virtual 修饰的,基类中的某个成员函数被声明为“虚函数”后,可以在一个或多个派生中重新定义该函数,重新定义,其函数原型(包括:返回类型,函数名,...
  • 构造函数是类的一种特殊成员,本质上也是类的成员函数函数名和类名相同,没有返回类型,可以有参数,也可以没有参数。 创建类一个新对象,构造函数被自动调用,完成对象初始化工作。 那么构造函数如何...
  • concat函数 String str1="...,即str2字符长度为0返回对象本身,而不会新创建对象。 “+”运算符可连接任何类型的的数据。 测试: 1、连接字符串为空字符串("") ...
  • C++中函数的用法小结

    2021-01-20 07:07:47
    而函数的定义则非常简单,由三个部分组成:函数的返回类型、函数名和函数的形参表。当然,这里不同的函数定义可以还会稍有不同,比如的成员函数、内联函数等。这里我们主要讨论函数的调用需要注意的一些问题。 ...
  • C++中拷贝构造函数的定义  有一个参数的类型是类型的构造函数是为拷贝构造函数。如下:  X::X( const X& x);...  当函数返回一个对象。  后两种情形会产生一个临时对象。  C++中编译器何时合成
  • 字符函数的返回类型所受的限制和基本数据库类型所受的限制相同的,比如: VARCHAR2数值被限制为2000字符(ORACLE 8中为4000字符),而CHAR数值被限制为255字符(在ORACLE8中2000).在过程性语句中使用,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,100
精华内容 440
关键字:

当函数的返回类型是类时