精华内容
下载资源
问答
  • C++ 赋值构造函数 复制构造函数

    千次阅读 2018-08-25 15:29:11
    默认构造函数 编译器提供一个不接受任何参数,也不执行任何操作的构造函数,称之为默认构造函数 这是因为创造对象的时候总会调用默认构造函数 Klunk::Klunk() {} //定义 Klunk lunk; //声明 使用默认构造函数 ...

    这里写图片描述

    默认构造函数

    编译器提供一个不接受任何参数,也不执行任何操作的构造函数,称之为默认构造函数

    这是因为创造对象的时候总会调用默认构造函数

    Klunk::Klunk() {}   //定义
    Klunk lunk;         //声明  使用默认构造函数

    如果定义了构造函数,C++不会定义默认构造函数,如果希望创建对象时不显示地对他进行初始化,则必须显示的定义默认构造函数,这种默认的构造函数没有任何参数,但是可以用来设定特定的值,比如说:

    Klunk::Klunk() 
    {
        klunk_cnt = 0;
    }

    带参数的构造函数也可以是默认构造函数,只要所有的参数都有默认值
    Klunk::Klunk(int n = 0)
    {
    klunk_cnt = n;
    }

    但是注意,下面两种构造函数不能共同声明,会引起歧义

    Klunk::Klunk(int n = 0) {klunk_cnt = n;}
    Klunk::Klunk() {klunk_cnt = n;}
    
    Kulnk kar (10);  //这回选择只用第一种
    Kulnk bus;       //两种都可以,所以会报错

    复制构造函数

    // 对象的声明
    Stringbad sailor = sports

    上面这句话是常见的一种对象声明方式,这种对象方式使用了哪种构造函数呢?不是默认构造函数,也不是 Stringbad ::Stringbad (const char *)这种构造函数,而是等效于下面这句话

    StringBad sailor = StringBad (sports)

    因为sports的类型为StringBad ,所以说此时构造函数的原型如下

    StringBad (const StringBad  &)

    当使用一个对象初始化另一个对象的时候,编译器会自动生成构造函数,成为复制构造函数

    复制构造函数用于将一个对象复制到新创建的对象中。也就是说,它用于初始化过程中(包括按值传递参数),而不是常规的复制过程,累的复制构造函数原型:

    StringBad (const Class_name &) // 他接受一个指向类的对象的常量引用作为参数

    何时调用复制构造函数

    新建一个对象,并将其初始化为同类现有对象的时候,复制构造函数就会被调用,在很多情况下都可能发生,最常见的情况是将新对象显示的初始化为现有的对象

    StringBad ditto (motto)  //使用复制构造函数构造ditto
    StringBad metto = motto
    StringBad also = StringBad (motto)
    StringBad * pStringBad = new StringBad (motto)

    其中中间两种的声明可能会使用复制构造函数直接创建metto 和 also,也可能会生成一个临时对象,然后将临时兑现的内容赋值给metto 和also。最后一种是初始化一个匿名对象,并将新对象复制给指针。

    当函数按值传递对象或者函数返回对象时,都将会使用复制构造函数,每当程序生成了副本,编译器都将会使用复制构造函数

    注意: 由于使用按值传递的时候会调用复制构造函数,那么会浪费一定的时间和空间,所以应该经常使用引用传递参数,这样的话,可以节省调用构造函数的时间以及存储空间。

    默认的复制构造函数的功能
    默认的复制构造函数逐个复制非静态成员(成员复制也成为浅复制),复制的是成员的值

    StringBad sailor = sports;
    //与下面的函数等价
    StringBad sailor;
    sailor.str = sports.str;
    sailor.len = sports.len;

    浅复制构造函数带来的缺陷
    浅复制构造函数会让新的对象和以前的对象使用同一个地址,那么当调用析构函数的时候,析构了一次,但是会让两个对象都失去地址,然后GG思密达

    解决办法
    定义一个显示复制构造函数以解决问题
    所谓的显示复制构造函数,就是加了地址这一项。

    StringBad::StringBad (const StringBad & st)
    {
        num_strings++;
        len = st.len;
        str = new char [len + 1]
        std::strcpy (str, st.str);
    }

    警告:如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,而不是指针,这类被称为深度复制。复制的另一种形式是浅复制,只是复制指针值,浅复制仅仅浅浅的复制指针信息,而不会深入挖掘复制指针引用的结构


    赋值运算符

    运算符原型:

    Class_name & Class_name::operator=(const Class_name &);

    赋值运算符的功能以及何时使用它
    将已有的对象赋给另一个对象时,将使用重载的赋值运算符:

    StringBad headline1 ("Celery Stalks at Midnight");
    StringBad knot;
    knot = headline1;   // 使用复制构造函数创建一个临时对象然后通过赋值将临时对象复制到新的对象中。
    /*
        这样就是说初始化总是会调用复制构造函数创建一个临时的对象。
        然后通过赋值将临时对象的值复制到新对象中。
    */

    这个和上面的复制构造函数是有区别的
    复制构造函数:

    // 对象的声明
    Stringbad metoo= knot
    这里的metto是一个新创建的对象,被初始化knot的值,因此使用复制构造函数
    这里的knot是一个先使用默认构造函数创建的对象,然后使用knot对其进行赋值操作

    默认赋值运算符带来的问题
    使用默认的赋值运算符所产生的问题的原因和复制运算符产生的问题原因是一样的,都是同一块地址,析构就没有了。

    解决办法—-创建一个深复制函数
    实现与复制函数一样,但是也有一些小区别

    1. 由于目标对象可能引用了以前分配的数据,所以在使用之前使用delete[]进行释放
    2. 函数应当避免将对象赋值给自身,否则,给新对象重新赋值前,释放内存操作可能删除的对象
    3. 函数返回一个指向调用对象的引用。
    StringBad & StringBad::operator=(const StringBad & st)
    {
        if (&st == this)
            return *this;
        delete [] str;
        len = st.len;
        str = new char [len + 1];
        std::strcpy (str, st.str);
        return * this;
    }

    参考 《C++ Primer Plus》

    展开全文
  • 构造函数的种类: 默认构造函数 无参数构造函数 一般构造函数(重载构造函数) 复制(拷贝)构造函数 class Student { private: int num; int age; string name; public: //当一个类...

    构造函数的种类:

    1. 默认构造函数

    2. 无参数构造函数

    3. 一般构造函数(重载构造函数)

    4. 复制(拷贝)构造函数

    class Student
    {         
    private:
        int num;
        int age;
        string name;
        
    public:
            //当一个类没有定义任何构造函数时,系统会自动生成默认的无参构造函数。
    
            //系统合成的默认构造函数自己定义的默认构造函数(无参数构造函数)的区别以及为什么在自己提供了其他构造函数的同时再提供一个默认构造函数(无参数构造函数)也总是对的
            //原因:合成的默认构造函数无法初始化内置和复合类型的成员,如指针和数组。即默认构造函数非我们所期望,应该由自己明确定义构造函数,而非编译器完成。
    
    
            // 一旦实现了的任何一种构造函数,系统就不会再自动生成这样一个默认构造函数。
    
            //无参数构造函数
            Student()
            {
                num = 0;
                age = 0;
                name = "zero";
            }   
     
            // 一般构造函数(也称重载构造函数)
            // 一般构造函数可以有各种参数形式,一个类可以有多个一般构造函数,前提是参数的个数或者类型不同(基于c++的重载函数原理)
            // 创建对象时根据传入的参数不同调用不同的构造函数
            Student(int num_temp)
            {
                num= num_temp;
                age= 20;   
                name = "zero";      
            }  
            Student(int num_temp, int age_temp, string name_temp)
            {
                num = num_temp;
                age = age_temp;   
                name = name_temp;      
             }
    
            //带有默认参数的构造函数(与上面三个构造函数不能共存,切记,切记)
            Student(int num_temp = 0, int age_temp = 0, string name_temp = "zero")
            {
                num = num_temp;
                age = age_temp;   
                name = name_temp;      
             }
            
    
            //复制构造函数(也称为拷贝构造函数)
            //复制构造函数的形式为X(X&)  函数名与类名必须一致,参数为类对象本身的引用
            
            //若没有显示的复制构造函数,则系统会默认创建一个复制构造函数,但当类中有指针成员时,由系统默认创建该复制构造函数会存在风险,具体原因看下文。
    
            //复制构造函数参数为类对象本身的引用,用于根据一个已存在的对象复制出一个新的该类的对象,一般在函数中会将已存在对象的数据成员的值复制一份到新创建的对象中
            Student(const Student & s)
            {
                num = s.num;
                age = s.age;   
                name = s.name;      
             }            
            
            virtual ~Student(){} 
    };
    
    int main()
    {
            // 调用了无参构造函数
            Student s1,s2;
    
            // 调用一般构造函数(当没有默认参数的构造函数)
            Student s3(1);
            Student s4(1,20,"张三");
    
            //当有默认参数的构造函数,可传递任意个数(包括0)的参数去调用该构造函数。
           
            // 调用拷贝构造函数( 有下面两种调用方式) 
            //复制初始化
            Student s5(s4);
            //赋值初始化
            Student s6 = s4;  
    }

    深拷贝和浅拷贝

    • 浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么浅拷贝就会出问题了。即浅拷贝只拷贝指针
    1. 两个指针指向同一块内存,任何一方的变动都会影响到另一方。
    2. 两个指针指向同一块内存,被析构2次,即delete同一块内存2次,造成程序崩溃。
    • 深拷贝,相对于浅拷贝,不仅对象中的数据成员进行了赋值,同时还为动态成员开辟了新的空间。
    class Student
    {         
    
    private:
        int num;
        int age;
        string name;
        int gradenumber;
        int *grade
        
    public:
            Student(int num_temp, int age_temp, string name_temp, int gradenumber)
            {
                num = num_temp;
                age = age_temp;   
                name = name_temp;    
                grade - new int[gradenumber];  
             }
            
            //浅拷贝,默认拷贝构造函数是浅拷贝
            Student(const Student & s)
            {
                num = s.num;
                age = s.age;   
                name = s.name;
                grade = s.grade;      
             }  
              
            //深拷贝
            Student(const Student & s)
            {
                num = s.num;
                age = s.age;   
                name = s.name;
                grade - new int[s.gradenumber];
                for(int i = 0; i < gradenumber; i++)
                {
                    grade[i] = s.grade[i];
                }
             }    
    
            virtual ~Student()
            {
                    delete []grade ;
                    grade = NULL;
             }
    };
    
    int main()
    {
            Student s4(01,20,"张三",5);
            Student s5(s4);
            Student s6 = s4; 
            return 0;
    }

    在什么情况下系统会调用拷贝构造函数:

    1. 一个对象以值传递的方式传入函数体
    2. 一个对象以值传递的方式从函数返回
    3. 一个对象需要通过另外一个对象进行初始化。
    class Student 
    {  
    private:
        int num;
        int age;
        string name;
        int gradenumber;
        int *grade
        
    public:
            Student(int num_temp, int age_temp, string name_temp, int gradenumber)
            {
                num = num_temp;
                age = age_temp;   
                name = name_temp;    
                grade - new int[gradenumber];  
             }
            
            //浅拷贝,默认拷贝构造函数是浅拷贝
    //        Student(const Student & s)
    //        {
    //            num = s.num;
    //            age = s.age;   
    //            name = s.name;
    //            grade = s.grade;      
    //         }  
              
            //深拷贝
            Student(const Student & s)
            {
                num = s.num;
                age = s.age;   
                name = s.name;
                grade - new int[s.gradenumber];
                for(int i = 0; i < gradenumber; i++)
                {
                    grade[i] = s.grade[i];
                }
             }    
    
    
            virtual ~Student()
            {
                    delete []grade ;
                    grade = NULL;
            }
                    
    }; 
      
    //参数是对象,是值传递,会调用拷贝构造函数
    int get_student(Student s) const
    {
        return s.num;
    }
      
    //返回值是对象类型,会调用拷贝构造函数。  
    Student get_student()       
    {  
        Student s(1, 20, "张三", 5);  
        return s;  
    }  
      
    
      
    int main()  
    {  
        //调用构造函数
        Student s1(1, 20, "张三", 5);
    
        //调用拷贝构造函数 
        Student s2 s2 (s1);            
        Student s3 s3 = s1;            
      
        //函数形参是类的对象,调用拷贝构造函数 
        int num = get_student(s1);   
          
      
        //函数返回值是类的对象,调用拷贝构造函数 
        Student s4 = get_student();     
      
        return 0;  
    }  

    结论:

    1. 对象不存在,且没用别的对象来初始化,就是调用了构造函数;
    2. 对象不存在,且用别的对象来初始化,就是拷贝构造函数(上面说了三种用它的情况!)
    3. 对象存在,用别的对象来给它赋值,就是赋值函数。

    为什么用成员初始化列表会快一些

    • 定义:初始化列表是一种C++初始化列表,有初始化阶段和计算阶段两个阶段。初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段。
    • 初始化类的成员有两种方式,一是使用初始化列表,二是在构造函数体内进行赋值操作。例如:
    
    class Student 
    {  
    private:
        int num;
        int age;
        
    public:
        //构造函数初始化列表
        Student():num(1),age(20)
        {}
            
        //构造函数内部赋值
        Student(int num_temp, int age_temp)
        {
            num = num_temp;
            age = age_temp;   
        }
    };
    • 用成员初始化列表会快一些的原因是:
    1. 对内置类型成员变量(指针,引用),两者性能差别不大。
    2. 对非内置类型成员变量(类类型),构造函数体内进行会使用两次构造函数,而成员初始化列表则只需要一次。
    • 必须使用成员初始化列表的情况
    1. const成员或者引用类型的成员。因为const对象或者引用类型只能初始化,不能赋值。
    2. 需要初始化的数据成员是对象的情况,并且这个对象只有含参数的构造函数,没有无参数的构造函数。
    3. 派生类初始化基类的私有成员。构造函数只能在初始化列表中被显示调用,不能在构造函数内部被显示调用。

     

     explicit关键字的作用

    • 可以阻止不应该允许的经过转化构造函数进行的隐式转换的发生。
    class Test1
    {
    public:
        Test1(int n)
        {
            num=n;
        }//普通构造函数
    private:
        int num;
    };
    class Test2
    {
    public:
        explicit Test2(int n)
        {
            num=n;
        }//explicit(显式)构造函数
    private:
        int num;
    };
    int main()
    {
        Test1 t1=12;//隐式调用其构造函数,成功
        Test2 t2=12;//编译错误,不能隐式调用其构造函数
        Test2 t2(12);//显式调用成功
        return 0;
    }
    • effective c++中说:被声明为explicit的构造函数通常比其non-explicit兄弟更受欢迎。因为它们禁止编译器执行非预期(往往也不被期望)的类型转换。除非我有一个好理由允许构造函数被用于隐式类型转换,否则我会把它声明为explicit。我鼓励你遵循相同的政策。

    本系列文章目的为个人准备面试的简单总结,文中多有不足,敬请批评指正!

    参考:

    https://blog.csdn.net/feitianxuxue/article/details/9275979

    https://blog.csdn.net/zxc024000/article/details/51153743

    https://blog.csdn.net/zzwdkxx/article/details/53409803

    https://blog.csdn.net/sinat_20265495/article/details/53670644

    展开全文
  • 原文地址:... 觉得很好,就拿来参考了~ 1、拷贝构造函数:  模型: [cpp] view plain copy class A   {   public :   A(A& a){   

    原文地址:http://blog.csdn.net/jefry_xdz/article/details/7935760

    觉得很好,就拿来参考了~

    1、拷贝构造函数:

      模型:  

    [cpp]  view plain  copy
    1. class A   
    2.   {  
    3.      public :  
    4.     A(A& a){  
    5.       //函数体  
    6.     }  
    7.   };  

    什么时候调用拷贝构造函数:
    (1) 当用类的一个对象去初始化该类的另一个对象时候。系统
    自动调用它实现拷贝赋值
      形如: A a(1,1); A b(a);
    (2) 若函数的形参为类的对象,调用函数时,实参赋值形参,系统自动
    调用拷贝函数.
            test(A a);       A aa; test(aa);

    2、组合类构造函数

     模型:
      类::类(对象成员所需的形参,本类成员形参):对象1(参数),对象2(参数),……{
      本类初始化
     }
     调用顺序:
         先调用内嵌对象的的构造函数,先声明的先调用。如果是缺省构造函数,则内嵌对象的初始化也将调用相应的缺省构造函数,析构相反。
     举例:

    [cpp]  view plain  copy
    1. class Base   
    2. {  
    3. private:  
    4.     int b1;  
    5.     int b2;  
    6. public:  
    7.     Base(int b1,int b2)  
    8.     {  
    9.        printf("base create \n");  
    10.        this->b1 = b1;  
    11.        this->b2 = b2;  
    12.     }  
    13.     ~Base()   
    14.     {  
    15.         printf("base destroy \n");   
    16.     }  
    17. };  
    18.   
    19.   
    20. class Test  
    21. {  
    22. private:  
    23.     int t1;  
    24.     Base b;  
    25. public:  
    26.     Test(int b1,int b2,int t1):b(b1,b2)  
    27.     {  
    28.         printf("test create \n");  
    29.         this->t1 = t1;  
    30.     }  
    31.     ~Test()  
    32.     {  
    33.        printf("test destroy \n");  
    34.     }  
    35. };  
    36.   
    37.   
    38.   
    39.   
    40. int _tmain(int argc, _TCHAR* argv[])  
    41. {  
    42.     Test* test = new Test(1,2,3);  
    43.       
    44.     delete test;  
    45.   
    46.   
    47.     int in;  
    48.     scanf("&d",in);  
    49. }  

    结果:
    base create
    test create
    test destroy

    base destroy


    例子:拷贝构造函数与组合类构造函数混用
    [cpp]  view plain  copy
    1. #include "stdafx.h"  
    2. #include <iostream>  
    3. using namespace std;  
    4.   
    5.   
    6. class Base   
    7. {  
    8. private:  
    9.     int b1;  
    10.     int b2;  
    11. public:  
    12.     Base(int b1,int b2)  
    13.     {  
    14.        printf("base create \n");  
    15.        this->b1 = b1;  
    16.        this->b2 = b2;  
    17.     }  
    18.        
    19.     Base(Base & b)   
    20.     {  
    21.         printf("copy create\n");  
    22.     }  
    23.   
    24.   
    25.     ~Base()   
    26.     {  
    27.         printf("base destroy \n");   
    28.     }  
    29. };  
    30.   
    31.   
    32. class Test  
    33. {  
    34. private:  
    35.     int t1;  
    36.     Base b;  
    37. public:  
    38.     Test(Base b1,int t1):b(b1)  
    39.     {  
    40.         printf("test create \n");  
    41.         this->t1 = t1;  
    42.     }  
    43.     ~Test()  
    44.     {  
    45.        printf("test destroy \n");  
    46.     }  
    47. };  
    48.   
    49.   
    50.   
    51.   
    52. int _tmain(int argc, _TCHAR* argv[])  
    53. {  
    54.     Base b(1,2);  
    55.     Test* test = new Test(b,3);  
    56.       
    57.     delete test;  
    58.   
    59.   
    60.     int in;  
    61.     scanf("&d",in);  
    62. }  

    结果:
    base create
    copy create
    copy create
    test create
    base destroy
    test destroy
    base destroy

    3、含有继承关系的构造函数

    模型:
    派生类:派生类(基类1新参,基类2新参,基类3形参,……,基类n新参,本类新参):
    基类1(参数),基类2(参数),……基类n(参数),对象数据成员初始化 
    {
      本类成员初始化赋值语句;

    };

    实例:

    C(int a,int b,int c,int d):
    B1(a),memberB2(d),memberB1(c),B2(b)
     {
    }


    我就不举例了,太多了

    展开全文
  • C++——构造函数、析构函数以及复制构造函数

    千次阅读 多人点赞 2021-03-09 16:28:49
    文章目录一、构造函数1.1 构造函数是什么?1.2 为什么要有构造函数?1.3 如何使用构造函数?1.4 构造函数的实现二、使用步骤 一、构造函数 在程序执行的过程中,当遇到与对声明语句时,程序会向操作系统申请一定的...

    一、构造函数

    在程序执行的过程中,当遇到与对声明语句时,程序会向操作系统申请一定的内存空间用于存放新建的对象。但是与普通变量相比,类的对象特别复杂,编译器不知如何产生代码去初始化对象,这便引出了构造函数。

    1.1 构造函数是什么?

    C++中,构造函数是一种特殊的成员函数,在每次创建一个类的时候编译器都会默认调用构造函数进行初始化。

    1.2 为什么要有构造函数?

    构造函数的作用就是在对象被创建的时候,利用特定的值构造对象,将对象初始化为一个特定的状态。

    1.3 如何使用构造函数?

    要学会如何使用构造函数,首先需要了解构造函数的一些特殊性质:构造函数的函数名与类名相同,而且没有返回值;构造函数通常被声明为公有函数。

    Notes:只要类中有了构造函数,编译器就会在创建新对象的地方自动插入对构造函数调用的代码。所以构造函数在对象被创建的时候将会被自动调用。

    下面分别介绍常见的几种构造函数:

    1. 默认构造函数:
    class Clock
    {
    public:
        Clock()   //编译器自动生成的隐含的默认构造函数;
        {
            
        }
        ....
    };
    

    默认构造函数调用时无须提供参数。如果类中没有写构造函数,那么编译器会自动生成一个隐含的默认构造参数,该构造函数的参数列表和函数体都为空,这个构造函数不做任何事情。

    Notes: 无参数的构造函数与全缺省的构造函数都称为默认构造函数。

    Q:既然默认构造函数不做任何事情,那么为什么还要生成这个构造函数?

    答:因为在建立对象时自动调用构造函数时C++必然要做的事情。上述例子中,默认构造函数什么都没有做,但是有些函数体为空的构造函数并非什么都不做,因为它还要负责基类的构造和成员对象的构造。

    1. 有参数的构造函数和无参数的构造函数
    class Clock
    {
    public:
        Clock(int NewH,int NewM,int NewS);  //有参数的构造函数
        Clock()   //无参数的构造函数
        {
            hour = 0;
            minute = 0;
            second = 0;
        }
        void SetTime(int NewH,int NewM,int NewS);
        void ShowTime();
    
    private:
        int hour,minute,second;
    };
    
    int main()
    {
        Clock(0,0,0); //调用有参数的构造函数
        Clock my_clock;  //调用无参数的构造函数
        return 0;
    }
    
    

    上述例子中出现了两种重载的构造函数的形式:有参数的和无参数的(即默认构造函数)

    1.4 构造函数的实现

    
    Clock::Clock(int NewH, int NewM, int NewS) 
    {
        hour = NewH;
        minute = NewM;
        second = NewS;
    }
    

    二、复制构造函数

    生成一个对象的副本有两种途径,第一种途径是建立一个新的对象,然后将原始对象的数据成员取出来,赋值给新对象。这样做显然太繁琐了,所以为了使得一个类具有自行复制本类对象的能力,复制构造函数被引出。

    2.1 什么是复制构造函数?

    复制构造函数是一种特殊的构造函数,其具有一般构造函数的所有特性,其形参是本类对象的引用。

    2.2 为什么要有复制构造函数?

    复制构造函数的作用是使得一个已经存在的对象(由复制构造函数的参数指定),去初始化一个同类的一个新对象。如果程序没有定义类的复制构造函数,系统就会在必要时自动生成一个隐藏的复制构造函数。这个隐藏的复制构造函数的功能是,把初始值对象的每个数据成员复制到新建立的对象中去。这样得到的对象和原本的对象具有相同的数据成员和属性。

    2.3 复制构造函数的功能

    在说明复制构造函数的功能之前,我们先看一下声明和实现复制构造函数的一般方法:

    class 类名
    {
    public:
        类名(形参); //构造函数
        类名(类名& 对象名); //复制构造函数
        ...
    };
    
    类名::类名(类名 &对象名) //复制构造函数的实现
    {
        //函数体
    }
    

    前面我们知道,普通的构造函数在对象被创建的时候调用,而复制构造函数在下面3种情况下均会被调用:

    例:

    class Point
    {
    public:
        Point(int x = 0,int y = 0)
        {
            _x = x;
            _y = y;
        }
        Point(Point& p); //复制构造函数
        int GetX()
        {
            return _x;
        }
        int GetY()
        {
            return _y;
        }
    
    private:
        int _x,_y;
    };
    
    1. 当用类的一个对象去初始化另一个对象时:
    int main()
    {
        Point a(1,2);
        Point b(a); //用对象a初始化对象b时,复制构造函数被调用
        Point c = a; //用对象a初始化对象c时,复制构造函数被调用
        return 0;
    }
    

    Notes:上面对b和c的初始化都能够调用复制构造函数,两种写法是等价的,执行的操作完全相同。

    1. 如果函数的形参是类的对象,调用函数时,进行形参和实参结合时:
    void Fun(Point p)
    {
        //函数体
    }
    
    int main()
    {
        Point a(1,2);
        Fun(a); //函数的形参为类的对象,当调用对象时,复制构造函数被调用.
        return  0;
    }
    

    Notes:只有把对象用值传递的时候,才会调用复制构造函数。如果传递的是引用,则不会调用复制构造函数。所以这也是传递引用会比传值的效率高的原因。

    1. 如果函数的返回值是类的对象,函数执行完成返回调用者时:
    Point Fun()
    {
        Point a(1,2);
        return a;  //函数Fun的返回值是类的对象,返回函数值的时候,调用复制构造函数
    }
    
    int main()
    {
        Point b;
        b = Fun();
        return 0;
    }
    

    Q:为什么在这种情况下,返回函数值的时候会调用复制构造函数?

    答:函数Fun()将a返回给了主函数,但是我们都知道a是Fun()的局部变量,当Fun()函数的生命周期结束的时候,a也就消亡了,不可能在返回主函数后继续生存。所以在这种情况下编译器会在主函数中创建一个无名的临时对象,该临时对象的生命周期仅仅在b = Fun()中。当执行语句return a时,实际上是调用复制构造函数将a的值复制到无名临时对象中。当函数Fun()运行结束时,对象a消失,但是临时对象会存在于b = Fun()中。当计算这个表达式后,临时对象也就完成了它的工作。

    三、析构函数

    我们刚讨论了当一个局部变量随着它的函数生命周期结束的时候,函数中的对象也会消失,那么在对象,要消失的时候(比如构造对象的时候,在函数中用malloc动态申请了空间)谁来做这些所谓的“善后”工作呢?这样我们就引出了析构函数。

    什么是析构函数?

    与构造函数一样,析构函数通常也是类的一个公有成员函数,它的名称是由类名前面加一个"~"构成,没有返回值。析构函数与构造函数不同的是,析构函数不接受任何参数!(参数可以是虚函数),如果我们不自行定义析构函数,则编译器同样会自动生成一个隐藏的析构函数,它的函数体为空。

    下面我们看一下析构函数的声明:

    class Clock
    {
    public:
        Clock(int NewH,int NewM,int NewS);  //有参数的构造函数
        Clock()   //无参数的构造函数
        {
            hour = 0;
            minute = 0;
            second = 0;
        }
        void SetTime(int NewH,int NewM,int NewS);
        void ShowTime();
        ~Clock(); //析构函数
    
    private:
        int hour,minute,second;
    };
    

    Notes:函数体为空的析构函数并不是什么都不做。

    Tips:
    类的构造顺序是按照语句的顺序进行构造
    类的析构函数调用完全按照构造函数调用的相反顺序进行调用
    1.全局对象先于局部对象进行构造
    2.静态对象先于普通对象进行构造

    展开全文
  • 赋值构造函数和拷贝构造函数 常见的给对象赋值方式有构造函数,拷贝构造函数,赋值运算符这三种方法,如下代码演示了这几种常见的方法。 Tan a1; (1) Tan a2(a1);
  • 详解C++ 拷贝构造函数

    2021-01-19 23:44:42
    拷贝构造函数是一种特殊的构造函数,...拷贝构造函数的最常见形式如下: classname (const classname &obj) { // 构造函数的主体 } 在这里,obj 是一个对象引用,该对象是用于初始化另一个对象的。 #include <io
  • C++构造函数调用构造函数问题

    千次阅读 2010-09-09 11:32:00
    关键字:C++ 构造函数 定位new placement new 最近在整理C++知识的时候,突然想到如何在C++中实现构造函数调用构造函数的问题,常见的错误是按照如下方式来调用: 1: #include 2: 3: class Test 4...
  • Java的构造函数与默认构造函数(深入版)

    千次阅读 多人点赞 2020-03-07 22:39:11
    我们知道在创建对象的时候,一般会通过构造函数来进行初始化。在Java的继承(深入版)有介绍到类加载过程中的验证阶段,会检查这个类的父类数据,但为什么要怎么做?构造函数在类初始化和实例化的过程中发挥什么作用...
  • c++构造函数分类说明

    千次阅读 2017-07-15 15:43:23
    在面向对象编程中,创建对象时系统会自动调用构造函数来初始化对象,构造函数是一种特殊的类成员函数,它有如下特点: 1. 构造函数的名子必须和类名相同,不能任意命名; 2. 构造函数没有返回值; 3. 构造函数...
  • 在我的上一篇文章里面 阐述了jQuery的大致框架,知道了所有代码都是写在了一个自...如果是构造函数为什么不是 new $(document)的常见形式呢? 其实jQuery是面向对象js库,也有构造函数,每次调用jQuery方法是就会实例化
  • 构造函数 构造函数的主要功能是为对象分配空间,其次也可以对类的数据成员进行初始化。构造函数有如下性质: 1.构造函数的名字必须与类名相同。 2.构造函数的参数可以是任何数据类型,但是没的返回值,不能为它...
  • Dart 构造函数最详细的解析

    千次阅读 2019-12-10 18:53:43
    本文讲述了Dart中构造函数写法 。工厂构造函数 常量构造函数 普通构造函数的关系
  • 每一个类只有一个析构函数,但可以有多个构造函数(包含一个默认构造函数,一个拷贝构造函数,和其他普通构造函数)和多个赋值函数(包含一个拷贝赋值函数,其他的为普通赋值函数)。一般情况下,对于任意一个类A,...
  • 拷贝构造函数和赋值函数

    千次阅读 2014-08-21 10:25:37
    在C++中复制控制是一个比较重要的话题,主要包括复制构造函数、重载赋值操作符、析构函数这三部分,这三个函数是一致的,如果类需要析构函数,则它也需要复制操作符 和 复制构造函数,这个规则被称为 C++的“三法则...
  • struct构造函数

    千次阅读 2010-06-11 08:43:00
    最近才知道struct和class的静态构造函数的触发规则是不同的,不像class在第一次使用类的时候触发静态构造函数。如果只访问struct实例的字段是不会触发静态构造函数调用的。通过测试发现当访问静态字段,struct本身的...
  • 拷贝构造函数

    2009-05-06 14:01:00
    拷贝构造函数  拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的参数(对象的引用)是不可变的(const类型)。此函数经常用在函数调用时用户定义...
  • 以TestClass为例: class TestClass { public: TestClass() {} }; 拷贝构造函数: TestClass(const TestClass&... // 形式1 TestClass(TestClass&...形式1是最常见构造函数声明,这也是最好的书写方式。 ...
  • C 构造函数的运用

    千次阅读 2018-11-15 08:08:31
    C 构造函数的运用
  • C++基础:缺省构造函数

    万次阅读 多人点赞 2014-05-10 16:01:50
    缺省构造函数是C++以及其他的一些面向对象的程序设计语言中,
  • 构造函数的几种方式

    千次阅读 2017-06-29 19:50:03
    工厂模式使用工厂模式构造函数,系统会在函数内部自动帮你定义一个对象,如:var obj = new Object();函数构建完成后系统还会自动帮你返回一个对象,如:return this;工厂模式分为三个步骤构造函数: 1.原料:原料...
  • 主要介绍了JavaScript创建对象方式,结合实例形式总结分析了工厂模式、构造函数模式、原型模式等各种常见的javascript对象创建方式与相关操作注意事项,需要的朋友可以参考下
  • 【C++】C++类和对象、构造函数和析构函数

    千次阅读 多人点赞 2018-06-03 20:32:37
    类是对某一事物的抽象描述,具体地讲,类是C++中的一种构造的数据类型。它即可包含描述事物的数据,又可包含处理这些数据的函数,类在程序运行时是被用作样板来建立对象的。所以要建立对象,首先必须定义类。 定义...
  • struct的构造函数

    千次阅读 2011-09-28 21:13:26
    C++之struct构造函数 (2010-10-19 15:04:47) 转载 标签: cpp struct 构造函数 校园 分类: C/C_PlusPlus  在网络协议、通信控制、嵌入式系统的C/C+
  • Swift 基本知识之十三 构造函数

    千次阅读 2016-01-29 17:09:46
    通过闭包或函数设置属性的默认值 构造过程是使用类、结构体或枚举类型的实例之前的准备过程。在新实例可用前必须执行这个过程,具体操作包括设置实例中每个存储型属性的初始值和执行其他必须的设置或初始化工作。...
  • 构造函数、析构函数与赋值函数是每个类最基本的函数。...一般,对于任意一个类A,如果程序员不显式地声明和定义上述函数,C++编译器将自动为A产生4个public inline的默认函数,其最常见形式为: A() //默认构造函数
  • 构造函数的8种方式

    千次阅读 2021-04-19 09:55:34
    没有绝对优秀的构造函数的方法,每一种方法都有他们的优缺点,我们需要考虑的是知道他们的应用场景,合理的使用他们,从而达到自己的要求。 1.Object构造函数模式 使用方式:先创建空对象,再添加属性/方法 适用场景...
  • Flutter学习之Dart语言基础(构造函数)

    千次阅读 2019-03-25 12:03:07
    常见构造函数形式,即生成构造函数,创建一个类的新实例: //Dart class Point { num x, y; //Dart中int和double是num的子类 //this引用当前类对象 Point(num x, num y) { this.x = x; this.y = y...
  • 主要介绍了JS常见构造模式,结合实例形式对比分析了工厂模式、构造函数模式、原型模式、寄生构造函数模式、稳妥构造函数模式等相关概念、原理、实现方法与相关操作技巧,需要的朋友可以参考下
  • C#OOP之六 构造函数和析构函数

    千次阅读 2016-04-27 20:48:45
    系统默认的 构造方法是无参数的构造方法,但一旦在类中定义了,无参数的 构造函数或其他构造函数,系统将不再默认该无参构造方法。   析构函数 析构方法的作用刚好和构造方法相反,构造方法在创建对象时...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 149,110
精华内容 59,644
关键字:

常见构造函数的形式