精华内容
下载资源
问答
  • c++,类的对象作为形参时一定会调用复制构造函数吗? c++,类的对象作为形参时一定会调用复制构造函数吗?答:如果参数是引用传递,则不会调用任何构造函数;如果是按值传递,则调用复制构造函数,...

    c++,类的对象作为形参时一定会调用复制构造函数吗?

    c++,类的对象作为形参时一定会调用复制构造函数吗?

    答:如果参数是引用传递,则不会调用任何构造函数;如果是按值传递,则调用复制构造函数,按参数的值构造一个临时对象,这个临时对象仅仅在函数执行是存在,函数执行结束之后调用析构函数。

    如果类中没有定义复制构造函数 那对象就不能作为形参?

    答:如果没有定义,编译器会自动为你定义一个,编译器自己定义的复制构造函数是按类成员变量的值复制的。有几个成员变量就重新创建一个对象,那个对象的成员变量和被复制的对象其成员变量的值相同。这里如果成员变量有指针的时候,就会出现多个指针指向同一个对象的问题。
    posted @ 2018-02-06 09:29 史D芬周 阅读(...) 评论(...) 编辑 收藏
    展开全文
  • 首先,函数形参和返回值如果在不使用引用...那么,当我们面对类类型对象作为形参和返回值时,其构造函数及析构函数是如何运作的呢?下面通过一系列代码来进行追踪: 通过这个程序可以看到,我在主函数中定义了一个

    首先,函数形参和返回值如果在不使用引用的情况下是按照所谓传值(by-value)的方式来进行传递的。其本质是由编译器产生临时对象,将实参或者返回值拷贝给临时对象,之后的操作都是在临时对象上进行,当函数结束的时候再释放掉临时对象。

    那么,当我们面对类类型对象作为形参和返回值时,其构造函数及析构函数是如何运作的呢?下面通过一系列代码来进行追踪:

    通过这个程序可以看到,我在主函数中定义了一个对象,在foo函数中也定义了一个局部对象,那么总共会发生几次构造几次析构呢?答案在这里:

    可以看到,在程序中总共存在着两次构造函数和两次拷贝构造函数,但是只有三次析构函数。也就是说,存在一个对象没有被析构,这是为什么呢?下面通过对foo函数的伪代码展开来进行分析。

    Foo()的C++伪代码:

    //第一次构造

    xx.XX::XX();                                      

    XX  _temp0;                                                                                       

    //第一次拷贝

    _temp0.XX::XX(xx);                                                                      

    void foo(XX&_result, _temp0)

    {

      //第二次构造

    yy.XX::XX();                                                                              

    //赋值

    yy.operator=(_temp0);                                                                

       //第二次拷贝

    _result.XX::XX(yy);                                                      

    return;

    }

     //第一次析构

    yy.XX::~XX();

     //第二次析构                                                                         

    _result.XX::~XX();               

     //第三次析构                                                           

    _temp0.XX::~XX();                                                                         

     

    可以看出,main()函数中的对象xx并不参与析构,可以理解为对象xx将于整个程序结束后方由编译器析构释放。此时,无法在控制台中追踪析构情况。

     

    接下来讨论一个变种情况,主函数代码修改如下:

    可以看到,此时我在主函数中又申请了一个XX类型的对象t用来保存foo函数的返回值,这次运行又会发生什么事呢?

    可以看到,析构函数的调用又少了一次!!

    再次对foo函数进行展开分析:

    Foo()的C++伪代码:

     //第一次构造

    xx.XX::XX();                                       

    XX  _temp0; 

    //第一次拷贝                                                                                    

    _temp0.XX::XX(xx);                                                                         

    XX t;

    void foo(&t,_temp0)

    {

      //第二次构造

            yy.XX::XX();

      //赋值                                                                   

            yy.operator=(_temp0);  

    //第二次拷贝                                   

            t.XX::XX(yy);                                                                    

    return;

    }

    //第一次析构

    yy.XX::~XX();    

     //第二次析构                                                                                

    _temp0.XX::~XX();                                                                            

     

    可以看到,由于主函数中的对象t取代了临时对象_result,所以导致对_result的析构调用不存在了,而t本身是main函数中的对象,所以和xx一样在main函数结束的时候才会被析构调用,故无法追踪。

     

    在对象作为返回值时,存在一种称为NRV的优化措施,该措施对于上面的代码展开的影响如下:

    Foo()的C++伪代码:

     //第一次构造

    xx.XX::XX();                                        

    XX  _temp0;    

    //第一次拷贝                                                                                   

    _temp0.XX::XX(xx);                                                                           

    XX t;

    void foo(&t,_temp0)

    {

      //第二次构造

             t.XX::XX();           

      //赋值                                                         

             t.operator=(_temp0);                                                            

    return;

    }

     //第一次析构

    _temp0.XX::~XX();                                                                            

     

    可以看到,在开启NRV优化的情况下,局部对象yy将被临时对象_result或是用来保存返回值的对象t所替代,所以对于对象yy的析构调用也不存在了,所以只会有一次析构调用。


    展开全文
  • 问题1: 可变对象 & 不可变对象 **可变对象:**变量所指内存中的对象值可以被改变,...问题2:可变对象直接做函数形参存在的问题: 在python中,一个函数的形参是可以设置默认值的,这是非常方便的一个特性;n...

    问题1: 可变对象 & 不可变对象
    **可变对象:**变量所指内存中的对象值可以被改变,列表list、字典dict、集合set都是典型的可变对象
    **不可变对象:**变量所指内存中的对象值不能被改变,字符串str、数值类型(int float)元组都是典型的不可变对象
    问题2:可变对象直接做函数形参存在的问题:
    在python中,一个函数的形参是可以设置默认值的,这是非常方便的一个特性;note,在设置默认值时,默认值最好设置成不可变对象类型的值;如果设置成可变对象,默认值可能会出现预期之外的result,如列表list
    问题2解决办法:
    对于一个函数,如果某一个参数存在对应的值,直接函数调用即可;如果某一个参数不存在对应的值,可将默认参数设置为None,这样不会报错

    reference: https://www.cnblogs.com/liulaolaiu/p/11744390.htmlk

    展开全文
  • python中的可变对象和不可变对象 可变对象,是指该对象所指向的内存中的值可以被改变。变量改变后,实际上是其所指向的对象的值发生了变化,也就是说在原地址发生了变化。 不可变对象,是指该变量所指的内存中的对象...

    python中的可变对象和不可变对象

    可变对象,是指该对象所指向的内存中的值可以被改变。变量改变后,实际上是其所指向的对象的值发生了变化,也就是说在原地址发生了变化。
    不可变对象,是指该变量所指的内存中的对象的值不能被改变。

    Python中,字符串、数值类型(int和float)与元组是典型的不可变对象,而列表list、字典dict、集合set是典型的可变对象类型。

    如何判断对象是否改变?

    在Python中,对象是由对象的id来唯一确定的,因此我们可以用id(object)方法来查看每个对象的id,从而进行比较。
    还有一种简单的方法是,可以用is来比较两个变量是否指向同一个对象,其所对应的,==用来比较两个变量指向的对象是否相等。

    python中的可变对象作为形参的默认值

    在python中,一个函数的签名中的形参是可以设置默认值的,这是非常方便的一个特性,但是在使用的时候,要注意,默认值最好设置为不可变的对象类型的值,如数字、元组或字符串,如果设置为可变的对象类型的话,如列表,会产生种种不容易预期的后果,原因是,这些对象并不是我们每次调用函数的时候会生成一个新的对象,而是一个函数的默认值,在函数定义的时候,被赋值一次,且这是唯一的一次初始化。

    详细的可以看下面的例子:

    def get_extended_list(extend_value, list_to_extend=[]):
        list_to_extend.append(extend_value)
        return list_to_extend
    
    
    if __name__ == "__main__":
        list_1 = get_extended_list(1)
        list_2 = get_extended_list(2, [])
        list_3 = get_extended_list('a')
    
        print "list_1:\t", list_1
        print "list_2:\t", list_2
        print "list_3:\t", list_3
    
        print "list_1 is list_2:\t", list_1 is list_2
        print "list_1 is list_3:\t", list_1 is list_3
    
        list_4 = [1, 'a']
        print "list_4 is list_1:\t", list_4 is list_1
        print "list_4 == list_1:\t", list_4 == list_1
    
        print id(list_1)
        print id(list_2)
        print id(list_3)
        print id(list_4)
    

    输出结果:

    list_1:	[1, 'a']
    list_2:	[2]
    list_3:	[1, 'a']
    list_1 is list_2:	False
    list_1 is list_3:	True
    list_4 is list_1:	False
    list_4 == list_1:	True
    140275885988896
    140275077913848
    140275885988896
    140275885281648
    

    中间,我们重点关注list_1与list_3,它们之所以是同一个对象,是因为它们都指向内存中的同一个列表,也就是函数get_extended_list在被定义的时候初始化出的形参list_to_extend,之后的每一次调用这个函数的时候,如果用到这个形参的初始值,都是对同一个对象进行操作,因此产生了如上的输出。

    解决方案

    在我们明白了问题之后,接下来就是思考如何解决这样的问题了。

    如果我们是想要对于一个函数而言,如果某个参数并没有输入,则为其创建一个新的可变对象(如列表),我们这时就不能直接将这个可变对象放到函数的形参中,而是放到函数的代码中,如下:

    def get_extended_list(extend_value, list_to_extend=None):
        if list_to_extend is None:
            list_to_extend = []
        list_to_extend.append(extend_value)
        return list_to_extend
    

    在如上的代码中,我们将形参list_to_extend的默认值设置为None,也就是说如果没有输入这个参数的话,函数会将其设为默认值None,之后在函数中的起始部分,会检测该变量是否为None,如果是的话,会为其开辟一块新的内存来创建一个新的列表,最后返回这个新的列表。

    因此,如果再调用之前的main函数的话,就可以输出我们直观上认为会有的输出了:

    list_1:	[1]
    list_2:	[2]
    list_3:	['a']
    list_1 is list_2:	False
    list_1 is list_3:	False
    list_4 is list_1:	False
    list_4 == list_1:	False
    139858452864032
    139857644788984
    139858452156784
    139858452156568
    
    展开全文
  • 今天看了有关类的对象作为函数形参的实现的一些...类的对象作为形参的时候,也要用到运行栈,来看它的实现:首先将对象压入运行栈的传参区域,区别就在此产生,然后调用复制构造函数建立一个临时对象在传参区域,而基本
  • 1.类名作为形参和返回值 package java_learn; /* 类名作为形参和返回值。 1.方法的形参是类名。其实需要的是对象; 2.方法的返回值是类名,其实返回的是 */ public class Cat { public void eat(){ System....
  • deleteNodeWithValue(node (1,2,3,4),2); System.out.println(node); //print node(1,3,4) 改变了node System.out.println(deleteNodeWithValue(node (1,2,3,4),2)); //print node(1,3,4) ...
  • 抽象类和接口作为形参和返回值的问题 类名作为形参和返回值 //类名作为形参 pubilc void useCat(Cat c){ c.eat(); } //类名作为返回值 public Cat getCat(){ Cat c = new Cat(); return c; } 注意:抽象类不...
  • ### 1.1 类名作为形参和返回值(应用) * 1、类名作为方法的形参 方法的形参是类名,其实需要的是该类的对象 实际传递的是该对象的【地址值】 * 2、类名作为方法的返回值 方法...
  • 类或接口作为形参

    2020-07-15 19:39:27
    类或接口作为形参 形式参数: 基本类型:这个没什么讲的 引用类型 类名: (匿名对象的时候其实我们已经进过了)需要的是该类的对象。 抽象类:需要的是该抽象的类子类对象。 接口:需要的是该接口的实现类对象。 /*...
  • 类名作为形参实际上要的是----该类的对象。 (2)类名作为方法的返回值 雷鸣座位方法的返回值实际上返回的是—该类的对象 class Teacher{ //Student类名作为show方法的形式参数 void show(Student s){ s....
  • String作为形参时:其值不该变 因为String是在常量池中创建对象 当改变原引用的值时,是在常量池中又创建了一个对象 方法弹栈后后一个变成了垃圾,原值没变 StringBuffer是在队堆中创建对象,改变其值后,即使方法弹栈 ...
  • Java面向对象程序设计 多态 主讲人何鑫 软件技术专业教学资源库 父类作为方法形参 第四部分 代码修改 public class Managerment{ public void insert(Person person) { person.showInfo; System.out.println"人员...
  • 一、什么是引用类型 在Java中引用类型包括三种:类、抽象类... * 类作为形参,实际传递的是该类的对象 */ class Student { public void study() { System.out.println("Good Good Study, Day Day Up"); ...
  • ### 1.1 类名作为形参和返回值(应用) * 1、类名作为方法的形参 方法的形参是类名,其实需要的是该类的对象 实际传递的是该对象的【地址值】 * 2、类名作为方法的返回值 方法的返回值是类名,其实返回的是该类的...
  • 1、类名作为形参和返回值 方法的形参是类名,其实需要的是该类的对象 方法的返回值是类名,其实返回的是该类的对象 2、抽象类名作为形参和返回值 由于抽象类无法实例化,所以必须有继承抽象类的子类帮助建立对象 ...
  • u 类名作为形参和返回值案例 第1章 面向对象概述 1.1 面向对象思想 1.1.1 面向过程思想与面向对象思想 A:什么是面向过程 面向过程,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些...
  • 近来做到几个关于对象作为函数形参,返回值时,构造函数,复制构造函数,析构函数的调用顺序的问题,于是研究了一下,发现问题似乎还有些麻烦,现在在此分享下: 问题一: •对象参数的传递方式 •通过运行栈来...
  • 接口作为返回值类型,多态形式实现了一个j对象,因为接口不能够直接形成对象,只能单独开辟一个子类继承这个接口完成实例化创建。 在main函数中创建j2这个对象,等号右侧为jo.getJumpping表明j2实例化的为上图中方...
  • public class yinyong{ public static void main(String args[]){...结果是引用对象作为形参,并不会改变所引用的对象,指向新的对象。(但可以改变原引用对象的参数状态) 参考自JAVA核心技术第十版中文版第四章第五节
  • Java中,Java类也可以作为一个形参传递,(类名,对象名),不过类作为参数,传递的是类的堆地址。 也可以返回,返回的也是一个地址。
  • 之前一直在想string属于引用数据类型那么指向的应该是堆内存中的一个地址,在作为形参传递过程中如果在方法内部对这个对象进行改变方法外部的值为什么没有变化? eg: String s = “123” change(s){ s = "456...
  • 类名作为形参和返回值 方法的形参是类名,其实需要的是该类的对象 方法的返回值是类名,其实返回的是该类的对象 public class Cat { public void eat(){ System.out.println("猫吃鱼"); } public void jump()...
  • #include using namespace std; class Student {public: Student(int n,float s):num(n),score(s){} void change(int n,float s) {num=n;score=s;} void display() {cout;} private: int nu

空空如也

空空如也

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

对象作为形参