构造函数_c++中复制构造函数、移动构造函数、拷贝构造函数 - CSDN
构造函数 订阅
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。 展开全文
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。特别的一个类可以有多个构造函数 ,可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载。
信息
作    用
为对象成员变量赋初始值
语    句
new运算符一起使用
中文名
构造函数
外文名
constructor
构造函数主要特点
1.构造函数的命名必须和类名完全相同。在java中普通函数可以和构造函数同名,但是必须带有返回值;2.构造函数的功能主要用于在类的对象创建时定义初始化的状态。它没有返回值,也不能用void来修饰。这就保证了它不仅什么也不用自动返回,而且根本不能有任何选择。而其他方法都有返回值,即使是void返回值。尽管方法体本身不会自动返回什么,但仍然可以让它返回一些东西,而这些东西可能是不安全的;3.构造函数不能被直接调用,必须通过new运算符在创建对象时才会自动调用;而一般的方法是在程序执行到它的时候被调用的;4.当定义一个类的时候,通常情况下都会显示该类的构造函数,并在函数中指定初始化的工作也可省略,不过Java编译器会提供一个默认的构造函数.此默认构造函数是不带参数的。而一般的方法不存在这一特点;5.构造函数有回滚的效果,构造函数抛出异常时,构造的是一个不完整对象,会回滚,将此不完整对象的成员释放(c++)6.当一个类只定义了私有的构造函数,将无法通过new关键字来创建其对象,当一个类没有定义任何构造函数,C#编译器会为其自动生成一个默认的无参的构造函数。7.在Python中构造函数必须通过重写__init__方法实现
收起全文
  • 构造函数

    2016-10-22 10:23:12
    类中一个很重要的概念就是构造函数(constructor)。一、定义 (1)构造函数,顾名思义,就是起到构造作用的函数。当我们创建类的一个对象时,会自动调用构造函数构造函数是对象调用的第一个函数,它不需要用户显式...

    类中一个很重要的概念就是构造函数(constructor)。

    一、定义

    (1)构造函数,顾名思义,就是起到构造作用的函数。当我们创建类的一个对象时,会自动调用构造函数。构造函数是对象调用的第一个函数,它不需要用户显式调用,也不能由用户显式调用,只会在对象创建时执行。

    (2)构造函数的作用:构造函数用来确保每个对象的所有数据成员都有一个明显的初始值(sensible initial value)。

    (3)不存在常构造函数。构造函数用于初始化对象,不管对象是否为常对象(const object)。

    (4)构造函数定义方式: 类名(构造函数参数)[:初始化列表]{} []表示这部分可省略。构造函数没有返回值,函数名和类名一样,可以不接收参数,也可以接收单个或多个参数。

    (5)用户可以显式的定义构造函数,但不可显式调用构造函数。如果用户没有显式的定义构造函数,那么如有必要,编译器会自动生成一个构造函数,这个构造函数是默认构造函数。

    上面这些在任何一本C++书中都会介绍,没什么可讲的。但是为了本文的完整性,还是把它写了出来。

    二、构造函数初始化(The Constructor Initializer)

    构造函数是一个函数,由函数名、参数表和函数体构成。与其它函数不同的是,构造函数可以包含构造函数初始化列表(consturctor initializer list)。

    构造函数初始化列表跟在函数参数表后面,以一个冒号开始,冒号后是类的一些数据成员,每个数据成员后有一个括号,括号内为其初始值,数据成员间以逗号隔开,如下所示:

    //类名为Test,我们可以在类中这样定义  
    Test(int x, int y):fir(x),sec(y),thr("hello")  
    {  
    }  

    参数化列表的作用在于初始化对象的数据成员。

    很多时候初始化列表被省略,我们在类中使用赋值语句(“=”)来为对象的数据成员赋值。很多人误以为构造函数初始化的过程在函数体内完成,其实不然。构造函数的初始化过程是在构造函数的初始化列表中完成的,函数体内不是初始化过程。

    我们可以认为构造函数执行的过程是这样的:

    (1)根据创建对象的语句,将对应的实参传递给构造函数的形参。

    (2)执行构造函数初始化列表。使用初始化列表中的初始值来初始化其对应的数据成员。

    如果数据成员没有出现在初始化列表中,或者构造函数没有定义初始化列表,那么根据对象的数据成员的类型,采取对应的初始化方法:类型为类的数据成员,调用类的构造函数初始化它;类型为string的数据成员(其实这个也可视为类),调用string的构造函数初始化;内置类型(built-in type)或者混合类型(compound)的数据成员,如果它在的对象是局部的,那么不初始化它,如果是全局的,初始化为0。(这个初始化规则和定义变量后初始化变量的规则一样)

    (3)执行构造函数体。通常是对对象的一些数据成员赋值。

    以下程序可以验证这一点:

    class Test  
    {  
    public:  
        Test()  
        {  
              cout<<fir<<" "<<sec<<" "<<"thr:"<<thr<<endl;  
              fir=sec=10;  
              thr="hello";  
               cout<<fir<<" "<<sec<<" "<<"thr:"<<thr<<endl;  
        }  
    private:  
        int fir;  
        int sec;  
        string thr;  
    };  
    
    int main()  
    {  
        Test app;  
        return 0;  
    }  

    我们定义了一个无参构造函数,它没有初始化列表。首先它会输出对象的成员变量,然后我们执行赋值语句,再输入这些成员变量。在主程序中我们定义了类的一个对象,当编译器执行到这一句时,会调用构造函数。该程序输出两行,第一行fir和sec的值不确定,因编译器的不同而不同,thr的值为空,第二行的值为10 10 thr:hello。

    这个程序说明在构造函数中的赋值语句执行之前,对象的成员变量已被初始化了。fir和sec是内置整型变量,仅分配了内存(至于是不是在此时分配内存,根据语法,猜测是这样,但是无法肯定),未进行初始化。thr是string类型,调用string的默认构造函数,初始化为空。
    根据上述说明,不难理解下面这句话:

    有些成员必须使用构造函数初始化列表初始化。例如没有默认构造函数的类类型的成员必须使用构造函数初始化列表初始化,由const修饰的常成员,引用成员,不管它们是什么类型,也必须使用构造函数初始化列表初始化。

    三、对象成员的初始化顺序

    这是一个小知识点。对象成员的初始化顺序与其类中定义的顺序是保持一致的,通常在构造函数初始化列表中,我们无需关心这个顺序。但是,如果我们使用对象的某个成员来作为另一成员的初始值,就要注意初始化列表中成员的顺序。

    比如我们这些写初始化列表:Test(int x,int y):sec(x),fir(sec),thr(“hello”){},那么就会出现错误。因为虽然sec写在了fir前面,但是执行时仍然先初始化fir,再初始化sec,这样用未初始化的sec去初始化fir,是不正确的。

    当我们写构造函数初始化列表时,最好按顺序书写。最好尽可能的避免使用某些成员变量去初始化其它的成员变量。

    四、构造函数的分类

    构造函数的参数个数不定,这使得构造函数可以重载。我们可以在一个类中定义多个构造函数。有几种构造函数比较特别,它们有专门的名字,下面一一道来。

    (1)带默认参数的构造函数(constructor with default argument)

    在构造函数的参数表中指出某些参数的值(即默认值、缺省值default value)。构造函数的参数通常是用于在构造函数体中对对象的数据成员进行赋值。(请注意区分:构造函数的参数表是指构造函数名后的括号中的参数,构造函数的初始化列表指的是构造函数参数表后面冒号后的那些参数)。有时候我们有必要提供一个默认值。

    [cpp] view plaincopyprint?
    Test(int x,int y=10)  
    {   
           fir=x;   
           sec=y;   
           thr="hello";   
    } //我们这样定义构造函数         
    
    Test app(100,100);//对象appfir=100,sec=100  
    Test app2(100);//对象app2fir=100,sec=10  

    对象app2虽然只有一个参数,但是第二个参数缺省为10,所以仍然有结果。

    (2)默认构造函数(default constrcutor)

    默认构造函数就是默认情况下使用的构造函数。什么叫默认情况呢?所谓默认情况,就是我们在定义一个对象时,没有为对象提供初始化值的情况,这时,就会调用默认的构造函数。例如我们这样定义Test类的对象app:Test app; 我们没有为对象提供初始值,这个时候调用的构造函数就是默认构造函数。

    默认构造函数有两种,这两种可以说是两个极端情况。

    一是构造函数参数表为空的构造函数。

    例如这样的构造函数Test(){…..},构造函数参数表为空,构造函数的函数体可以不空。

    这种没有参数的构造函数可以被用户显式的定义,也可以由编译器隐式的生成,编译器隐式生成的默认构造函数的函数体是空的。

    需要注意到一点,如非必要,编译器不会隐式的生成默认构造函数。当我们在类中提供了构造函数,那么编译器不会生成默认构造函数,即使我们没有提供构造函数,在一些特殊的情况下编译器也不会生成默认构造函数。(这些特殊情况出现的概率较小,即使出现了,我们也不关心它是否有构造函数)

    有时候我们需要默认构造函数。因为没有这种构造函数会给我们带来极大的不便。例如我们定义了多个构造函数,那么编译器不会为我们生成默认构造函数。这时这个类就是没有默认构造函数的类。如果我们想像Test app那样定义对象,就会编译错误。我们想让这种类的一个对象成为另外一个类的数据成员,就必须在那个类的构造函数初始化列表对此类对象初始化。还有很多情况就不一一列举了。所以,当类中已定义了构造函数,我们最好也定义一个默认构造函数,即使这个函数什么也不做。

    二是构造函数参数表中参数值全为默认值的构造函数。

    这种情况不难理解,当我们为参数表中所有的参数都提供了缺省值,那么我们可以不必为对象提供实参值,对象会自动将其参数设为缺省值(这里要注意是构造函数的所有参数都是缺省值,而不是对象的所有数据成员,它们是两个无关的概念)。例如构造函数Test(int x=100,int y=100){…},我们可以使用Test app;定义对象app,也可以使用Test app(100);定义,还可以使用Test app(100,100);定义,这三种定义方式都定义了一个对象app,它的两个参数均为100。

    这种构造函数并不是很好用,因为它带来了一些限制。当我们将构造函数参数表中的所有参数值全部设为默认后,我们无法再定义类似于Test(int x){}或者Test(int x,int y){}这样的构造函数,因为编译时无法识别到底该调用哪一个构造函数。

    (3) 复制构造函数(copy constructor)

    复制构造函数是指只有一个参数,且参数为类对象的引用的构造函数。形为Test(Test& ap){}。

    复制构造函数主要作用是复制对象。所谓复制对象就是将对象的所有(非静态)数据成员的值去初始化另外一个对象。

    在一个类里面,总是会有复制构造函数,如果我们不显式定义,那么编译器就会自动生成。请注意到这点,它和默认构造函数不同,当我们在类中定义了构造函数,没有定义默认构造函数时,编译器是不会为我们生成的,而没有定义复制构造函数时,编译器会为我们生成。

    编译器自动生成的复制构造函数仅仅是用对象的非静态数据成员的值去初始化新创建的对象,使新创建的对象成为当前对象的副本。对于对象中的内置类型成员变量,直接复制,对于对象去中类类型的成员变量,调用它所属类的复制构造函数。

    我们可以这样定义对象:假设我们定义了默认构造函数,则可使用Test app定义对象app。我们可以使用Test app2(app);来定义对象app2,它是对象app的一个副本。当然,我们也可以使用Test app2=app;来定义app2,编译器会自动重载赋值运算符,如果我们没有显式的重载它。重载赋值运算符和复制构造函数的目的都是为了完成对象的复制。

    类的复制构造函数十分有用,所以类中总是有复制构造函数(我们不讨论(2)中提到的特殊情况)。当我们将类的一个对象作为实参传递,那么就会复制这个对象,此时调用的就是复制构造函数。当我们定义一个函数,返回类型为类类型,那么最终返回的是这个类的一个对象,也需要调用复制构造函数。

    有些类的对象需要防止被复制,例如iostream类的对象。我们通过显式的声明复制构造函数为private来实现。我们在类的private部分声明一个复制构造函数,而不定义它。这样任何试图复制对象的行为都将会失败。

    如果显式定义了复制构造函数,我们一定要显式定义默认构造函数,这样可以避免一些不必要的问题出现。

    五、构造函数的另一个作用——隐式的类类型转换

    构造函数除了可以初始化类的对象外,它还有一个很重要的作用,就是将一种类型转换成类类型。转换过程通常是隐式的调用对应的构造函数完成的。

    例如:我们在Test类中定义了一个函数,它接受Test类的对象的引用为参数,比如bool compare(Test& ap);倘若我们定义了四(1)中程序的构造函数,我们可以这样调用函数,设app为Test类的一个对象,则可以这样写:int a=20; bool c=app.compare(a);这个过程中,整型变量a作为参数传递给函数compare,虽然compare函数需要接受类对象,但是由于存在构造函数,编译器会隐式的调用构造函数,将实参a构造成一个临时对象,进而参与到函数中,当函数执行完成后,该临时对象被删除。

    当我们在构造函数声明时,在构造函数名前加上关键字explicit,这个关键字使得无法隐式的调用构造函数来完成类型转换。

    当构造函数声明为explicit后,我们可以显式的进行类型转换。如app.compare(Test(a));,有没有感到很熟悉?这个过程十分类似于强制类型转换,只不过是类类型的强制类型转换。

    通常,单个参数的构造函数会加上explicit关键字,这样可以避免很多错误,防止隐式的类型转换。当需要进行类型转换时,显式的使用类型转换会让代码更加清晰明了。

    总结:类的构造函数十分重要,涉及到的内容也十分的多。

    1、构造函数的初始化列表非常有用,也很重要。这个特性经常被很多人忽略。

    2、类中如果显式定义了构造函数,编译器是不会为我们提供默认构造函数的。所以,当显式定义了一个构造函数后,最好也定义一个默认构造函数,这个默认构造函数最好是无参构造函数。

    3、即使我们显式定义了构造函数,只要没有定义复制构造函数,编译器总会为我们生成一个。通常我们不用自己显式定义,最好由系统自己生成。除非我们不想让类的对象被复制。

    4、隐式的类型转换很难被发现,但是如果我们一直显式的使用强制类型转换,那么可以避免一些不必要的麻烦。

    5、据说,一个类是可以没有构造函数的。这些特殊情况比较复杂,涉及的非常深。

    原文链接:
    http://blog.csdn.net/szchtx/article/details/6894883

    展开全文
  • 对于一个C++刚入门的小盆友来说,构造函数怎么写还不简单么?然而C++中构造函数的写法不止一种,而且从效果和性能上来说并不相同。先看两种构造函数的写法,找到其区别。 写法一(我赌一包辣条很多人没见过这种...

    对于一个C++刚入门的小盆友来说,构造函数怎么写还不简单么?然而C++中构造函数的写法不止一种,而且从效果和性能上来说并不相同。先看两种构造函数的写法,找到其区别。

    写法一(我赌一包辣条很多人没见过这种写法):

    #include <iostream>
    using namespace std;
    
    template <typename Type>
    class testClass {
    public:
    	// 构造函数 
    	testClass(Type key);
    	
    	// 参数
    	int defaultValue;
    	Type keyValue;
    };
    
    template <typename Type>
    testClass<Type>::testClass(Type key):defaultValue(10),keyValue(key){}
    
    int main() {
    	testClass<int> test(20);
    	cout<<"defaultValue: "<<test.defaultValue<<endl;
    	cout<<"keyValue: "<<test.keyValue<<endl;
    	return 0;
    } 

    写法二(熟悉的味道!课本上教的就是这种写法):

    #include <iostream>
    using namespace std;
    
    template <typename Type>
    class testClass {
    public:
    	// 构造函数 
    	testClass(Type key);
    	
    	// 参数
    	int defaultValue;
    	Type keyValue;
    };
    
    template <typename Type>
    testClass<Type>::testClass(Type key) {
    	this->defaultValue = 10;
    	this->keyValue = key;
    } 
    
    int main() {
    	testClass<int> test(20);
    	cout<<"defaultValue: "<<test.defaultValue<<endl;
    	cout<<"keyValue: "<<test.keyValue<<endl;
    	return 0;
    }

     

    方法一叫成员初始化列表,可以将方法一的构造函数格式归纳为: 类名::类名(形参表):内嵌对象1(形参表),内嵌对象2(形参表)... { 类的初始化 }    

    方法二即为比较容易理解的赋值方式。

     

    下面考量一下这两种写法在运行时的区别。

    一般地这两种构造方法并没有太大的区别,在效率上也基本一致。在这里我推荐你使用第一种初始化列表方法,那么为什么会这样累?在《Effective C++》中条款04中有解释以上两种初始化的区别:

    方法一应该叫作初始化,方法二应该叫作赋值。二者是有本质的区别的。

    C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。因此方法二的构造函数内属性不能算是被初始化,是被赋值了。初始化发生的时间更早,发生在这些成员的default构造函数被自动调用之时。使用方法二的构造函数需要执行两次copu构造:defaultValue以10为初值进行copy构造,keyValue以key为初值进行copy构造。因此理论上使用方法一的成员初始化列表(member initialization list)方式的效率更高,因为比起先调用default构造函数然后再调用copy assignment操作符,单只调用一次copy构造函数是比较高效的。

    也就是说采用方法二的话,构造函数本体实际上不需要有任何操作,因此效率更高。借用《Effective C++》中的图片说明一下:

    想看具体的更加详细解释可以移步详细了解初始化列表构造方式为什么更通用

    另外:如果想要使用成员初始化方法写无参数的构造函数的话,可以通过以下的方式实现:

     

    最后,说明一下注意事项。

    使用成员初始化列表方法的时候需要注意:在初始化的时候需要按照声明的顺序进行初始化,比如你的类定义为:

    template <typename Type>
    class testClass {
    public:
    	// 构造函数 
    	testClass(Type key1, Type key2);
    	
    	// 参数
    	Type m_value1;
    	Type m_value2;
    };
    
    template <typename Type>
    testClass<Type>::testClass(Type key1, Type key2):m_value1(key1),m_value2(key2){}

    定义的时候有两个参数,声明的顺序是m_value1, m_value2,那么在通过成员初始化列表的时候也应该按照这个顺序,先给m_value1赋值,再给m_value2赋值。

    展开全文
  • 一直搞不懂什么是构造函数,为什么要用构造函数构造函数有什么用,逃避这个问题,今天做了简单的总结: 1.构造函数有什么用? 当你需要大批量的写对象的时候,就需要用到构造函数,它可以方便创建多个对象的实例...

    一直搞不懂什么是构造函数,为什么要用构造函数,构造函数有什么用,逃避这个问题,今天做了简单的总结:

    1.构造函数有什么用?

    当你需要大批量的写对象的时候,就需要用到构造函数,它可以方便创建多个对象的实例,并且创建的对象可以被标识为特定的类型,可以通过继承扩展代码

    2.构造函数的特点

    a:构造函数的首字母必须大写,用来区分于普通函数
    b:内部使用的this对象,来指向即将要生成的实例对象
    c:使用New来生成实例对象

    首先创建一个简单的构造函数

    		//创建一个构造函数
    		function People (name,str) {
    			this.name = name;
    			this.fun = function() {
    				console.log(str);
    			};
    			this.act = function () {
    				console.log("我是"+this.name+str);
    			};
    		}
    		//实例化一个People
    		var g1 = new People("郭小妹","美美美");
    		var g2 = new People("东东","吃吃吃")
    		g1.fun();
    		g1.act();
    		g2.act();

    打印结果:

     

     

    如果只是一个单独的对象,直接使用字面量就行了,如果你的对象有很多实例,或者涉及继承或者构造函数传参

    展开全文
  • 构造函数和析构函数的由来? 构造函数和析构函数的基本语法 C++编译器构造析构方案 PK 对象显示初始化方案 构造函数的分类以及调用 默认的构造函数 构造函数调用规则 构造函数和析构函数的总结 构造函数和析构...

    文章概述

    1. 构造函数和析构函数的由来?
    2. 构造函数和析构函数的基本语法
    3. C++编译器构造析构方案 PK 对象显示初始化方案
    4. 构造函数的分类以及调用
    5. 默认的构造函数
    6. 构造函数调用规则
    7. 构造函数和析构函数的总结

    构造函数和析构函数的由来

    类的数据成员不能在类的声明时候初始化,为了解决这个问题? 使用构造函数处理对对象的初始化。构造函数是一种特殊的成员函数,与其他函数不同,不需要用户调用它,而是创建对象的时候自动调用。析构函数是对象不再使用的时候,需要清理资源的时候调用。


    构造函数和析构函数的基本语法

    a. 构造函数:

    • C++中的类需要定义与类名相同的特殊成员函数时,这种与类名相同的成员函数叫做构造函数;
    • 构造函数可以在定义的时候有参数;
    • 构造函数没有任何返回类型。
    • 构造函数的调用: 一般情况下,C++编译器会自动的调用构造函数。特殊情况下,需要手工的调用构造函数。
    class Test
    {
       public:
       //构造函数
       Test()
       {
    
       }
    }

    b. 析构函数:

    • C++中的类可以定义一个特殊的成员函数清理对象,这个特殊的函数是析构函数;
    • 析构函数没有参数和没有任何返回类型;
    • 析构函数在对象销毁的时候自动调用;
    • 析构函数调用机制: C++编译器自动调用。
    class Test
    {
      ~Test()
      {
    
      }
    }

    C++编译器构造析构方案 PK 对象显示初始化方案

    class Test
    {
    private:
        int x;
    public:
        Test(int x)
        {
            this->x = x;
            cout << "对象被创建" << endl;
        }
        Test()
        {
            x = 0;
            cout << "对象被创建" << endl;
        }
        void init(int x)
        {
            this->x = x;
            cout << "对象被创建" << endl;
        }
        ~Test()
        {
            cout << "对象被释放" << endl;
        }
        int GetX()
        {
            return x;
        }
    };
    
    int main()
    {
        //1.我们按照C++编译器提供的初始化对象和显示的初始化对象
        Test a(10);
        Test b;      //显示创建对象但是还是调用无参构造函数,之后显示调用了初始化函数
        b.init(10);
    
        //创建对象数组(使用构造函数)
        Test arr[3] = {Test(10),Test(),Test()};
        //创建对象数组 (使用显示的初始化函数)
        Test brr[3];   //创建了3个对象,默认值
        cout<<brr[0].GetX()<<endl;
        brr[0].init(10);
        cout<<brr[0].GetX()<<endl;
        return 0;
    }

    根据上面的代码, 我们得出使用显示的初始化方案: a.必须为每个类提供一个public的init函数; b. 对象创建后必须立即调用init函数进行初始化。
    优缺点分析:

    • a. init函数只是一个普通的函数,必须显示的调用;
    • b. 一旦由于失误的原因,对象没有初始化,那么结果也是不确定的。没有初始化的对象,其内部成员变量的值是不定的;
    • c. 不能完全解决问题。

    构造函数的分类以及调用

    a. 无参构造函数

    class Test
    {
      private:
           int x;
      public:
           Test()
           {
             this->x=10;
           }
    }

    无参构造函数的调用: Test a;


    b. 有参构造函数

    class Test
    {
      private:
           int x;
      public:
           Test(int x)
           {
             this->x=x;
           }
    }

    有参数构造函数的调用时机:

    • Test a(10); 调用有参数构造函数
    • Test b=(2,3); 逗号表达式的值是最后一位,调用有参数构造函数
    • Test c=Test(2); 产生一个匿名对象,直接转化成c(只会调用一次有参数构造函数)

    c. 拷贝构造函数: 使用对象a初始化对象b

    class Test
    {
       private:
              int x;
       public:
              Test(const Test& a)
              {
                 this->x=a.x;
              }
    }

    拷贝构造函数的调用时机:

    class Test
    {
    private:
        int x;
    public:
        Test(int x)
        {
            this->x = x;
            cout << "对象被创建" << endl;
        }
        Test()
        {
            x = 0;
            cout << "对象被创建" << endl;
        }
        ~Test()
        {
            cout << "对象被释放" << endl;
        }
        Test(const Test& a)
        {
            this->x = a.x;
            cout << "对象被释放(拷贝构造函数)" << endl;
        }
    };
    • 第一个场景: 用对象a初始化对象b:
    Test a(10);
    //调用的是拷贝构造函数
    Test b = a;
    • 第二个场景: 用对象a初始化对象b
    Test a(10);
    //调用的是拷贝构造函数
    Test b(a)

    第一个场景和第二个场景是一样的,用一个对象初始化另一个对象。

    • 第三个场景: 实参初始化形参的时候,会调用拷贝构造函数
        Test a(10);
        //实参初始化形参
        PrintF(a);
    • 第四个场景: 函数返回一个匿名对象
      我们分析第四个场景前,我们看看下面的这个全局函数:
    //该函数返回的是谁?
    Test p()
    {
        Test c(4);
        return c;
    }

    根据输出结果表明:
    这里写图片描述
    函数返回的是一个匿名对象。我们现在可以知道第四个调用场景是函数返回一个匿名对象的时候,会调用拷贝构造函数。
    我们接着分析下面的两种情况:(接收匿名对象),判断匿名对象的去和留
    a. 匿名对象初始化另一个对象:

    Test a=p(); 

    输出结果:
    这里写图片描述
    表明使用匿名对象初始化一个对象的时候, 匿名对象直接转化成初始化的那个对象。
    b. 匿名对象赋值时:

        Test b;
        //匿名对象赋值另一个对象
        b = p();

    输出结果:
    这里写图片描述
    表明使用匿名对象赋值另一个对象的时候,匿名对象赋值以后就会被析构。
    匿名对象去和留总结:
    a. 匿名对象初始化另一个对象时,匿名对象直接变成有名的对象(初始化的那个对象);
    b. 匿名对象赋值另一个对象时,匿名对象赋值成功会被析构。


    默认的构造函数

    两个特殊的构造函数:
    a. 默认的无参数构造函数: 当类中没有定义构造函数时,编译器会提供一个无参数构造函数,并且函数体为空;
    b. 默认的拷贝构造函数: 当类中没有定义拷贝构造函数时,编译器会提供一个默认的拷贝构造函数,简单的进行成员变量的值复制。


    构造函数调用规则

    a. 当类中没有定义一个构造函数的时候,C++编译器会提供默认的无参数构造函数和拷贝构造函数;
    b. 当类中定义了拷贝构造函数,C++编译器不会提供无参数构造函数;
    c. 当类中定义了任意的非拷贝构造函数,C++编译器不会提供默认的无参数构造函数;
    d. 默认的拷贝构造函数只是进行成员变量的简单赋值;


    构造函数和析构函数的总结

    a. 构造函数时C++中用于初始化对象状态的特殊函数;
    b. 构造函数在对象创建的时候自动调用;
    c. 构造函数和普通成员函数都遵循重载原则;
    d. 拷贝构造函数是对象正确初始化的重要保障;
    e. 必要的时候必须手工的写拷贝构造函数。

      -
    展开全文
  • 构造函数和析构函数

    2019-05-14 02:23:04
    构造函数 代码演示: #include<iostream> using std :: cout; using std :: endl; class Date { public: void SetDate(int year, int month, int day) { _year = year; _month = month; ...
  • Java中的构造函数

    2020-08-06 11:49:41
    构造函数是一种特殊的函数,也有重载,同一个类中可以拥有多个重载的构造函数,普通的函数不能调用构造函数,但是构造函数之间可以互相调用,构造函数调用其他构造函数时必须注意: 1、只能用this关键字
  • 1、构造函数也是一个普通函数,创建方式和普通函数一样,但构造函数习惯上首字母大写 2、构造函数和普通函数的区别在于:调用方式不一样。作用也不一样(构造函数用来新建实例对象) 3、调用方式不一样。  ...
  • Java构造函数

    2019-04-26 20:08:04
    构造函数是面向对象中的一员,构造函数可以叫做构造器,它的函数名与类名相同,不用定义返回值类型,也-没有具体的返回值。构造函数是在构建创造时对象时调用函数,作用是可以给对象进行初始化,创建对象都必须要...
  • C++构造函数

    2019-06-20 09:01:34
    对象初始化 在建立一个对象时,常常需要作某些初始化的工作,例如对数据成员赋初值。如果一个数据成员未被赋值,则它的值是不可预知的,因为在系统为它分配内存时,保留了这些存储单元的原状,这就成为了这些数据...
  • C++默认构造函数

    2018-02-08 13:05:19
    本文围绕3个问题来理解C++的默认构造函数: 什么是默认构造函数? 默认构造函数什么时候被调用? 编译器在什么情况下会生成默认构造函数? 一. 什么是默认构造函数? 我们一般会认为默认构造函数就是编译器...
  • C++中一般创建对象,拷贝或赋值的方式有构造函数,拷贝构造函数,赋值函数这三种方法。 构造函数就是当创建一个类的对象时,它被调用来对类的数据成员进行初始化和分配内存。拷贝构造函数是一种特殊的构造函数,用...
  • Java 构造函数的详解

    2016-07-14 15:46:42
    我们人出生的时候,有些人一出生之后再起名字的,但是有些人一旦出生就已经起好名字的。那么我们在java里面怎么在对象一旦...而构造函数定义的是,对象在调用功能之前,在建立时,应该具备的一些内容。也就是对象的初
  • C++的构造函数和默认构造函数 今天学习c++时突然感觉自己对构造函数和默认构造函数的区别有些分不清,于是查找了各大网站将资料汇总一下,供自己和其他朋友们参考。 构造函数是c++的类在构造对象时调用的函数,此...
  • 拷贝构造函数构造函数不能分开说,他们都是初始化对象的一种方法。但是我们这里用构造函数辅助说明拷贝构造函数,主要说说拷贝构造函数的声明,用途和使用注意事项。 众所周知,构造函数是一个初始化类对象的函数...
  • C++11新标准扩展了构造函数初始值的功能,所以委托构造函数就出现了,一个委托构造函数使用它所属类的其他构造函数执行它自己的初始化过程,或者说他把自己的一些(或全部)职责委托给了其他构造函数。 1.定义: ...
  • 本文主要总结了默认构造函数的相关用法和构造函数重载,旨在能够对平时的项目开发起到一定的夯实基本功的作用,言简意赅,一目了然。首先需要了解构造函数是用来做什么?该类对象被创建时,编译器为对象分配内存空间...
  • 1、默认构造函数构造函数 (1)构造函数:C++用于构建类的新对象时需要调用的函数,该函数无返回类型!(注意:是“无”! 不是空!(void))。 (2)默认构造函数:默认构造函数是在调用时不需要显示地传入实参...
  • 默认构造函数 编译器提供一个不接受任何参数,也不执行任何操作的构造函数,称之为默认构造函数 这是因为创造对象的时候总会调用默认构造函数 Klunk::Klunk() {} //定义 Klunk lunk; //声明 使用默认构造函数 ...
  • C++拷贝构造函数详解

    2012-03-28 15:16:24
    什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。 下面看一个类对象...
  • Scala之主构造函数

    2020-06-19 14:31:22
    构造函数首先,我们必须要非常清晰明确的认识到:主构造函数不是你看到class后面跟的参数列表,那怎么可能是主构造函数呢?那只是主构造函数的函数列表!那主构造函数的函数体在那里呢?答案是:class body里所有...
1 2 3 4 5 ... 20
收藏数 1,497,024
精华内容 598,809
关键字:

构造函数