精华内容
下载资源
问答
  • JAVA构造函数(方法)

    万次阅读 多人点赞 2019-06-03 21:56:24
    一、什么是构造函数 java构造函数,也叫构造方法,是java中一种特殊的函数。函数名与相同,无返回值。 作用:一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象了属性和方法。 在现实生活中,...

    一、什么是构造函数

    Java构造函数,也叫构造方法,是JAVA中一种特殊的函数。与函数名相同,无返回值。

    作用:一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象的属性和方法。

    在现实生活中,很多事物一出现,就天生具有某些属性和行为。比如人一出生,就有年龄、身高、体重、就会哭;汽车一出产,就有颜色、有外观、可以运行等。

    这些,我们就可以将这些天然的属性和行为定义在构造函数中,当new实例化对象时,也就具有这些属性和方法,不用再去重新定义,从而加快编程效率。

    构造函数是对象一建立就运行,给对象初始化,就包括属性,执行方法中的语句。

    而一般函数是对象调用才执行,用 ".方法名" 的方式,给对象添加功能。

     一个对象建立,构造函数只运行一次。

     而一般函数可以被该对象调用多次。  

     

    二、构造函数的特点

    1、函数名与类名相同

    2、不用定义返回值类型。(不同于void类型返回值,void是没有具体返回值类型;构造函数是连类型都没有)

    3、不可以写return语句。(返回值类型都没有,故不需要return语句)

    注:一般函数不能调用构造函数,只有构造函数才能调用构造函数。

     

     三、示例

    1、无参构造函数类中只定义一个方法。构造器总是伴随着new操作一起调用. 

    new对象时,就调用与之对应的构造函数,执行这个方法。不必写“.方法名”。

    package javastudy;
    
    public class ConfunDemo {
        public static void main(String[] args) {
            //输出Hello World。new对象一建立,就会调用对应的构造函数Confun(),并执行其中的println语句。
            Confun c1=new Confun();            
            
        }
    }
    class Confun{        
        Confun(){        
            //定义构造函数,输出Hello World
            System.out.println("Hellow World");
        }
    }

    输出:

    Hellow World 

     

     2、有参构造函数,在new对象时,将实参值传给private变量,相当于完成setter功能。

    package javastudy;
    
    public class ConfunDemo3 {
        public static void main(String[] args){
            //实例化对象时,new Person()里直接调用Person构造函数并转转实参,相当于setter功能
            Person z = new Person("aerchi",18); 
            z.show();
        }
    }
    
    class Person{
        private String name;
        private int age;
        //有参数构造函数,实现给private成员变量传参数值的功能
        public Person(String n,int m){ 
            name=n;
            age=m;        
        }
        //getter                                      
        //实例化对象时,完成了sett功能后,需要getter,获取实参值。
        public String getName(){
            return name;
        }
        public int getAge(){
            return age;
        }
    
        //获取private值后,并打印输出
        public void show(){
            System.out.println(name+"\n"+age);
        }
    }

    输出:

    aerchi
    18

     以上代码,我们也可以将show()方法中的输出语句直接放在构造函数中,new对象时,即可直接输出值,如下

    package javastudy;
    
    public class ConfunDemo3 {
        public static void main(String[] args){
            //实例化对象时,new Person()里直接调用Person构造函数并转转实参,同时执行输出语句
            Person z=new Person("aerchi", 18);
        }
    }
    
    class Person{
        private String name;
        private int age;
        //有参数构造函数,实现给private成员变量传参数值的功能,同时直接输出值
        public Person(String n,int m){  
            name = n;
            age = m;
            System.out.println(name+"\n"+age);
        }
    }

    输出:

    aerchi
    18

     或

    class ConFun
    {
        public static void main(String[] args){
            Person a=new Person(18,"aerchi");
            System.out.println(a.getAge() +", " + a.getName());
        }
    }
    
    class Person
    {
        private int age;
        private String name;
        public Person(int x,String y){
            age=x;
            name=y;
        }
        public int getAge(){
            return age;
        }
        public String getName(){        
            return name;
        }
    }

     

    3、一个对象建立后,构造函数仅只运行一次。

    如果想给对象的值再赋新的值,就要使用set和get方法,此时是当做一般函数使用

    如下:

    package javastudy;
    
    public class ConfunDemo4 {
        public static void main(String[] args) {
                PersonDemo s=new PersonDemo("张三",18);  //new对象时,即调用对应的构造函数,并传值。同时,不能new同一个对象多次,否则会报错。
                s.setName("李四");                       //对象建立后,想变更值时,就要用set/get方法,重新设置新的值
                s.setName("王二麻子");    //并可调用对象多次。
                s.print();
        }
    }
    class PersonDemo{
        private String name;
        private int age;
        PersonDemo(String n,int m){       //建立有参构造函数,用于给两个private变量name、age赋值,同时输出值
            name=n;
            age=m;
            System.out.println("姓名:"+name+"\n"+"年龄:"+age);
        }
        public void setName(String x){     //set方法,用于再次给name赋值
            name=x;        
        }
        public String getName(){          //get方法,用于获取name的赋值
            return name;
        }
        public void print(){
            System.out.println(name);
        }
    }

    输出结果:

    姓名:张三
    年龄:18
    王二麻子

     

    四、默认构造函数

    当一个类中没有定义构造函数时,系统会给该类中加一个默认的空参数的构造函数,方便该类初始化。只是该空构造函数是隐藏不见的。

    如下,Person(){}这个默认构造函数是隐藏不显示的。

    class Person
    {  
        //Person(){}
    }

    当在该类中自定义了构造函数,默认构造函数就没有了。

    如果仍要构造函数,需要在类中手动添加。

     

    五、构造函数的重载

    构造函数也是函数的一种,同样具备函数的重载(Overloding)特性。

    class Person
    {  
        private String name;
        private int age;
     
        Person()
        {
            System.out.println("A:name="+name+", age="+age);
        }
     
        Person(String n)
        {
            name = n;
            System.out.println("B:name="+name+", age="+age);
        }
     
        Person(String n,int a)
        {  
            name=n;
            age=a;
            System.out.println("C:name="+name+", age="+age);
        }
     
    }
     
    class PersonDemo2
    {
        public static void main(String[] args)
        {
            Person p1=new Person();
            Person p2=new Person("aerchi");
            Person p3=new Person("aerchi",18);
        }
    }

    输出结果:

    A:name=null, age=0
    B:name=aerchi, age=0
    C:name=aerchi, age=18

     

    class Person
    {  
        private String name;
        private int age;
     
        Person()
        {
            System.out.println("A:name="+name+", age="+age);
            cry();
        }
     
        Person(String n)
        {
            name = n;
            System.out.println("B:name="+name+", age="+age);
            cry();
        }
     
        Person(String n,int a)
        {  
            name=n;
            age=a;
            System.out.println("C:name="+name+", age="+age);
            cry(); 
        }
        void cry()
        {
            System.out.println("Haha ...............");
        }
     
    }
     
    class PersonDemo2
    {
        public static void main(String[] args)
        {
            Person p1=new Person();
            Person p2=new Person("aerchi");
            Person p3=new Person("aerchi",18);
        }
    }

    输出结果:

    A:name=null, age=0
    Haha ...............
    B:name=aerchi, age=0
    Haha ...............
    C:name=aerchi, age=18
    Haha ...............

     

    六、构造函数的使用

     1、子类所有的 构造函数 默认调用父类的无参构造函数(构造函数不会被继承,只是被子类调用而已),父类参数是private的,无法直接访问。需要在父类中使用get方法来调用私有变量值。

    package javastudy;
    
    public class ConfunDemo5 {
        public static void main(String[] args) {
            Pupil z=new Pupil();
            z.show();
        }
    }
    class Student{                //父类Student
        private String name;
        private int height;
        public Student()
        {
            this.name="";
            this.height=0;
        }
        public String getName(){
            return name;
        }
        public int getHeight(){
            return height;
        }
    }
    class Pupil extends Student{    //子类Pupil
        private int score;
        public Pupil(){                //无参构造函数Pupil()直接继承了父类中的无参构造函数Student(),但是父类中的name、height是private的
            score=0;
        }
        public void show(){
            System.out.print("姓名:"+getName()+"\n身高:"+getHeight()+"\n分数:"+score);  //输出时,直接用get方法名。
        }
    }

    2、使用super调用父类的构造函数

     super 必须写在方法的首行

    package javastudy;
    
    public class ConfunDemo5 {
        public static void main(String[] args) {
            Pupil z=new Pupil("王二麻子",100,200);
            z.show();
            
            Pupil w=new Pupil();
            w.show();
        }
    }
    class Student{                //父类Student
        public String name;
        public int height;
        public Student()
        {
            this.name="";
            this.height=0;
        }
        public Student(String n,int m)
        {
            name=n;
            height=m;
        }
    }
    class Pupil extends Student{    //子类Pupil
        private int score;
        public Pupil(){                
            super("刘德花",501);    //使用super调用父类Student(String n,int m)方法,同时传递实际数值。super必须写在方法的首行。如果这里写super(),则调用的是父类中的Student()方法。
            score=0;
        }
        public Pupil(String x,int y,int z){        //
            super(x,y);              //使用super调用父类Student(String n,int m)方法,其中super中的参数名称必须与构造函数中的参数名称一致。
            score=z;
        }
        public void show(){
            System.out.println("姓名:"+name+"\n身高:"+height+"\n分数:"+score);
        }
    }

     输出:

    姓名:王二麻子
    身高:100
    分数:200
    姓名:刘德花
    身高:501
    分数:0

    打杂人

    展开全文
  • c++ 子类构造函数初始化及父类构造初始化

    万次阅读 多人点赞 2018-08-30 15:58:50
    我们知道,构造方法是用来初始化类对象的。如果在类中没有显式地声明构造函数,那么编译器会自动创建一个默认的构造函数;并且这个默认的构造函数仅仅在没有显式地声明构造函数的情况下才会被创建创建。 构造函数...

     我们知道,构造方法是用来初始化类对象的。如果在类中没有显式地声明构造函数,那么编译器会自动创建一个默认的构造函数;并且这个默认的构造函数仅仅在没有显式地声明构造函数的情况下才会被创建创建。

           构造函数与父类的其它成员(成员变量和成员方法)不同,它不能被子类继承。因此,在创建子类对象时,为了初始化从父类中继承来的成员变量,编译器需要调用其父类的构造函数。如果子类的构造函数没有显示地调用父类的构造函数,则默认调用父类的无参构造函数,至于什么事显式调用,在下面会详细说明!关于子类中构造函数的构造原则,总结如下,欢迎大家指导与批评。

             1.父类没有声明构造函数

             (1)子类也没有声明自己的构造函数,则父类和子类均由编译器生成默认的构造函数。

             (2)子类中声明了构造函数(无参或者带参),则子类的构造函数可以写成任何形式,不用顾忌父类的构造函数。在创建子类对象时,先调用父类默认的构造函数(编译器自动生成),再调用子类的构造函数。

             2.父类只声明了无参构造函数

             如果子类的构造函数没有显式地调用父类的构造,则将会调用父类的无参构造函数。也就是说,父类的无参构造函数将会被隐式地调用。

             3.父类只声明了带参构造函数

             在这种情况下,要特别注意。因为父类只有带参的构造函数,所以如果子类中的构造函数没有显示地调用父类的带参构造函数,则会报错,所以必需显示地调用。

    关于构造函数的显示调用,参见下例。

    class animal
    {
    protected:       //成员变量,声明为protected或者public,这里选择protected
    	int height;  //若声明为private,则不能被子类继承访问,会报错
    	int weight;
    public:
    	animal(int height,int weight)   //带参的构造函数
    	{
    		this->height=height;
    		this->weight=weight;
    		cout<<"animal的带参构造函数被调用"<<endl;
    	}
    	virtual ~animal()
    	{
    		cout<<"animal的析构函数被调用"<<endl;
    	}
    };
    //子类
    class fish:public animal
    {
    public:
    	fish():animal(20, 10) //显示调用父类的构造函数
    	{
    		cout<<"fish的构造函数被调用"<<endl;
    	}
    	virtual ~fish()
    	{
    		cout<<"fish的析构函数被调用"<<endl;
    	}
    };
    

    在子类fish的构造函数中,加上一个冒号(:),然后加上父类的带参构造函数,这就是父类构造函数的显式调用。这样,在子类的构造函数被调用时,系统就会去调用父类的带参构造函数,从而实现初始化父类的成员变量。运行结果如下:

    注意

    如果父类只有带参的构造函数,且该带参的构造函数的参数有默认值,此时在子类中也可以不用显示的调用父类的构造函数。

    // 父类的构造函数,改成带有默认值的参数, 这样在子类中就可以不用显示调用了
            animal(int height=19 ,int weight=20)   //带参的构造函数
            {
                    this->height=height;
                    this->weight=weight;
                    cout<<"animal的带参构造函数被调用"<<endl;
            }
    

     

    4.父类同时声明了无参和带参构造函数

             在这种情况下,子类只需要实现父类的一个构造函数即可,不管是无参的还是带参的构造函数。如果子类的构造函数没有显示地调用父类的构造函数(无参或带参),则默认调用父类的无参构造函数。

    //父类
    class animal
    {
    protected:       //成员变量,声明为protected或者public,这里选择protected
    	int height;  //若声明为private,则不能被子类继承访问,会报错
    	int weight;
    public:	
    	animal()
    	{
    		height=0;
    		weight=0;
    		cout<<"animal的无参构造函数被调用"<<endl;
    	}
    	animal(int height,int weight)   //带参的构造函数
    	{
    		this->height=height;
    		this->weight=weight;
    		cout<<"animal的带参构造函数被调用"<<endl;
    	}
    	virtual ~animal()
    	{
    		cout<<"animal的析构函数被调用"<<endl;
    	}
    };
    //子类
    class fish:public animal
    {
    public:
    	fish()     //没有显示地调用父类的构造函数(无参或带参),则默认调用父类的无参构造函数
    	{
    		cout<<"fish的构造函数被调用"<<endl;
    	}
    	virtual ~fish()
    	{
    		cout<<"fish的析构函数被调用"<<endl;
    	}
    };
    

    运行结果如下:

    总结以上几条,可以归纳出C++中子类继承父类时构造函数的写法的规律:当父类有显式地声明了构造函数时,子类最低限度的实现父类中的一个;当父类没有声明构造函数时,子类可以不声明构造函数或者任意地书写构造函数。

    展开全文
  • C++拷贝构造函数详解

    万次阅读 多人点赞 2011-02-23 13:39:00
    什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a = 100; int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。 下面看一个类对象...

    一. 什么是拷贝构造函数

    首先对于普通类型的对象来说,它们之间的复制是很简单的,例如:


    而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。
    下面看一个类对象拷贝的简单例子。

    运行程序,屏幕输出100。从以上代码的运行结果可以看出,系统为对象 B 分配了内存并完成了与对象 A 的复制过程。就类对象而言,相同类型的类对象是通过拷贝构造函数来完成整个复制过程的

    下面举例说明拷贝构造函数的工作过程。


    CExample(const CExample& C) 就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量


    二. 拷贝构造函数的调用时机

    在C++中,下面三种对象需要调用拷贝构造函数!
    1. 对象以值传递的方式传入函数参数


    调用g_Fun()时,会产生以下几个重要步骤:
    (1).test对象传入形参时,会先会产生一个临时变量,就叫 C 吧。
    (2).然后调用拷贝构造函数把test的值给C。 整个这两个步骤有点像:CExample C(test);
    (3).等g_Fun()执行完后, 析构掉 C 对象。

    2. 对象以值传递的方式从函数返回


    当g_Fun()函数执行到return时,会产生以下几个重要步骤:
    (1). 先会产生一个临时变量,就叫XXXX吧。
    (2). 然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);
    (3). 在函数执行到最后先析构temp局部变量。
    (4). 等g_Fun()执行完后再析构掉XXXX对象。

    3. 对象需要通过另外一个对象进行初始化;

    后两句都会调用拷贝构造函数。


    三. 浅拷贝和深拷贝

    1. 默认拷贝构造函数

        很多时候在我们都不知道拷贝构造函数的情况下,传递对象给函数参数或者函数返回对象都能很好的进行,这是因为编译器会给我们自动产生一个拷贝构造函数,这就是“默认拷贝构造函数”,这个构造函数很简单,仅仅使用“老对象”的数据成员的值对“新对象”的数据成员一一进行赋值,它一般具有以下形式:

     
        当然,以上代码不用我们编写,编译器会为我们自动生成。但是如果认为这样就可以解决对象
    的复制问题,那就错了,让我们来考虑以下一段代码:

      这段代码对前面的类,加入了一个静态成员,目的是进行计数。在主函数中,首先创建对象rect1,输出此时的对象个数,然后使用rect1复制出对象rect2,再输出此时的对象个数,按照理解,此时应该有两个对象存在,但实际程序运行时,输出的都是1,反应出只有1个对象。此外,在销毁对象时,由于会调用销毁两个对象,类的析构函数会调用两次,此时的计数器将变为负数。

    说白了,就是拷贝构造函数没有处理静态数据成员。

    出现这些问题最根本就在于在复制对象时,计数器没有递增,我们重新编写拷贝构造函数,如下

    2. 浅拷贝

        所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。大多情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么浅拷贝就会出问题了,让我们考虑如下一段代码:

        在这段代码运行结束之前,会出现一个运行错误。原因就在于在进行对象复制时,对于动态分配的内容没有进行正确的操作。我们来分析一下:

        在运行定义rect1对象后,由于在构造函数中有一个动态分配的语句,因此执行后的内存情况大致如下:

     

     

        在使用rect1复制rect2时,由于执行的是浅拷贝,只是将成员的值进行赋值,这时 rect1.p = rect2.p,也即这两个指针指向了堆里的同一个空间,如下图所示:

     

    当然,这不是我们所期望的结果,在销毁对象时,两个对象的析构函数将对同一个内存空间释放两,这就是错误出现的原因。我们需要的不是两个p有相同的值,而是两个p指向的空间有相同的值,解决办法就是使用“深拷贝”。


    3. 深拷贝

        在“深拷贝”的情况下,对于对象中动态成员,就不能仅仅简单地赋值了,而应该重新动态分配空间,如上面的例子就应该按照如下的方式进行处理:

    此时,在完成对象的复制后,内存的一个大致情况如下:

     

    此时rect1的p和rect2的p各自指向一段内存空间,但它们指向的空间具有相同的内容,这就是所谓的“深拷贝”。


    3. 防止默认拷贝发生

        通过对对象复制的分析,我们发现对象的复制大多在进行“值传递”时发生,这里有一个小技巧可以防止按值传递——声明一个私有拷贝构造函数。甚至不必去定义这个拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类对象,将得到一个编译错误,从而可以避免按值传递或返回对象。

    四. 拷贝构造函数的几个细节

    1. 拷贝构造函数里能调用private成员变量吗?
    解答:
    这个问题是在网上见的,当时一下子有点晕。其时从名子我们就知道拷贝构造函数其时就是
    一个特殊的构造函数,操作的还是自己类的成员变量,所以不受private的限制。


    2. 以下函数哪个是拷贝构造函数,为什么?


    解答:对于一个类X, 如果一个构造函数的第一个参数是下列之一:
    a) X&
    b) const X&
    c) volatile X&
    d) const volatile X&
    且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.


    3. 一个类中可以存在多于一个的拷贝构造函数吗?
    解答:
    类中可以存在超过一个拷贝构造函数。


    注意,如果一个类中只存在一个参数为 X& 的拷贝构造函数,那么就不能使用const X或volatile X的
    对象实行拷贝初始化.


    如果一个类中没有定义拷贝构造函数,那么编译器会自动产生一个默认的拷贝构造函数。
    这个默认的参数可能为 X::X(const X&)X::X(X&),由编译器根据上下文决定选择哪一个。

    展开全文
  • c++ 构造函数详解

    万次阅读 多人点赞 2019-05-31 17:20:58
    c++构造函数详解。(构造函数的分类、拷贝构造函数)

    c++ 构造函数详解

    构造函数是干什么的

    • 该类对象被创建的时候,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作,故:构造函数的作用:初始化对象的数据成员

    构造函数的分类

    • 无参构造函数
    • 带默认值的构造函数
    • 有参(无默认值)的构造函数
    • 复制构造函数(拷贝构造函数)
      • 一种特殊的构造函数,当对象之间复制时会自动调用拷贝构造函数
      • 若类中没有显示定义拷贝构造函数,则系统会自动生成默认拷贝构造函数
    	#include <iostream>
    	using namespace std;
    	
    	class Coordinate
    	{
    	public:
    		// 无参构造函数
    		// 如果创建一个类你没有写任何构造函数,则系统自动生成默认的构造函数,函数为空,什么都不干
    		// 如果自己显示定义了一个构造函数,则不会调用系统的构造函数
    		Coordinate()
    		{
    			c_x = 0;
    			c_y = 0;
    		}     
    	
    		// 一般构造函数
    		Coordinate(double x, double y):c_x(x), c_y(y){}   //列表初始化
    		// 一般构造函数可以有多个,创建对象时根据传入的参数不同调用不同的构造函数
    	
    		Coordinate(const Coordinate& c)
    		{
    			// 复制对象c中的数据成员
    			c_x = c.c_x;
    			c_y = c.c_y;
    		}
    	
    		// 等号运算符重载
    		Coordinate& operator= (const Coordinate& rhs)
    		{
    			// 首先检测等号右边的是否就是等号左边的对象本身,如果是,直接返回即可
    			if(this == &rhs)
    				return* this;
    			// 复制等号右边的成员到左边的对象中
    			this->c_x = rhs.c_x;
    			this->c_y = rhs.c_y;
    			return* this;
    		}
    	
    		double get_x()
    		{
    			return c_x;
    		}
    	
    		double get_y()
    		{
    			return c_y;
    		}
    	
    	private:
    		double c_x;
    		double c_y;
    	};
    	
    	int main()
    	{
    		// 调用无参构造函数,c1 = 0,c2 = 0
    		Coordinate c1, c2;
    		// 调用一般构造函数,调用显示定义构造函数
    		Coordinate c3(1.0, 2.0);
    		c1 = c3;    //将c3的值赋值给c1,调用"="重载
    		Coordinate c5(c2);
    		Coordinate c4 = c2;    // 调用浅拷贝函数,参数为c2
    		cout<<"c1 = "<<"("<<c1.get_x()<<", "<<c1.get_y()<<")"<<endl
    			<<"c2 = "<<"("<<c2.get_x()<<", "<<c2.get_y()<<")"<<endl
    			<<"c3 = "<<"("<<c3.get_x()<<", "<<c3.get_y()<<")"<<endl
    			<<"c4 = "<<"("<<c4.get_x()<<", "<<c4.get_y()<<")"<<endl
    			<<"c5 = "<<"("<<c5.get_x()<<", "<<c5.get_y()<<")"<<endl;
    		return 0;
    	}
    
    	c1 = (1, 2)
    	c2 = (0, 0)
    	c3 = (1, 2)
    	c4 = (0, 0)
    	c5 = (0, 0)
    	请按任意键继续. . .
    

    拷贝构造函数

    • 拷贝构造函数是一种特殊的构造函数,具有单个形参,该形参(常用const修饰)是对该类型的引用。当定义一个新对象并用同一类型的对象都它进行初始化时,将显示使用拷贝构造函数,当该类型的对象传递给函数返回该类型的对象时,将隐式调用拷贝构造函数
    • 当类中有一个数据成员是指针时,或者有成员表示在构造函数中分配的其他资源,必须显示定义拷贝构造函数
    • 构造函数的使用情况
      • 一个对象以值传递的方式传入函数体
      • 一个对象以值传递的方式从函数体返回
      • 一个对象需要通过另一个对象进行初始化
    	#include <iostream>
    	using namespace std;
    	
    	class Test
    	{
    	public:
    		// 构造函数
    		Test(int a):t_a(a){
    		cout<<"creat: "<<t_a<<endl;
    		}
    	
    		// 拷贝构造函数
    		Test(const Test& T)
    		{
    			t_a = T.t_a;
    			cout<<"copy"<<endl;
    		}
    	
    		// 析构函数
    		~Test()
    		{
    			cout<<"delete: "<<t_a<<endl;
    		}
    	
    		// 显示函数
    		void show()
    		{
    			cout<<t_a<<endl; 
    		}
    	
    	private:
    		int t_a;
    	};
    	
    	// 全局函数,传入的是对象
    	void fun(Test C)
    	{
    		cout<<"test"<<endl;
    	}
    	
    	int main()
    	{
    		Test t(1);
    		// 函数中传入对象
    		fun(t);
    		return 0;
    	}
    
    	creat: 1
    	copy
    	test
    	delete: 1
    	delete: 1
    	请按任意键继续. . .
    

    浅拷贝与深拷贝

    • 浅拷贝
      • 所谓浅拷贝,指的是在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。也就是增加了一个指针,指向原来已经存在的内存。 正常情况下,“浅拷贝”已经能很好的工作,但是一旦对象存在动态成员,浅拷贝就会出问题。让我们考虑下面一段代码:
    	#include <iostream>
    	#include <assert.h>    
    	using namespace std;
    	
    	class Test
    	{
    	public:
    		Test(){
    			p = new int(10);
    		}
    	
    		~Test(){
    			assert(p != NULL);     // assert()作用是如果他的条件返回错误,则终止程序执行 
    			delete p;
    		}
    	private:
    		int x;
    		int y;
    		int* p;
    	};
    	
    	int main()
    	{
    		Test t1;
    		Test t2(t1);    // 调用默认拷贝构造函数
    		return 0;
    	}
    

    上述程序崩溃。在使用t1复制t2时,进行的是浅拷贝,只是将成员的值进行赋值。此时,t1.p = t2.p, 即两个指针指向了堆里的同一个空间。这样,析构函数会被调用两次,这就是错误出现的原因。此问题的解决方法是“深拷贝”。

    • 深拷贝
      • 深拷贝就是对于对象中的动态成员,并不只是简单的赋值,而是重新分配空间,即资源重新分配。上述代码处理如下:
    	#include <iostream>
    	#include <assert.h>    
    	using namespace std;
    	
    	class Test
    	{
    	public:
    		Test(){
    			x = 0;
    			y = 0;
    			p = new int(10);
    		}
    	
    		Test(const Test& t)
    		{
    			x = t.x;
    			y = t.y;
    			p = new int(10);
    			*p = *(t.p);
    		}
    	
    		~Test(){
    			assert(p != NULL);     // assert()作用是如果他的条件返回错误,则终止程序执行 
    			delete p;
    		}
    	
    		int get_x(){return x;}
    		int get_y(){return y;}
    	private:
    		int x;
    		int y;
    		int* p;
    	};
    	
    	int main()
    	{
    		Test t1;
    		Test t2(t1);    // 调用默认拷贝构造函数
    		cout<<"("<<t1.get_x()<<", "<<t1.get_y()<<")"<<endl
    			<<"("<<t2.get_x()<<", "<<t2.get_y()<<")"<<endl;
    		return 0;
    	}
    
    (0, 0)
    (0, 0)
    请按任意键继续. . .
    

    此时t1与t2的p各自指向一段内存空间,但他们指向的内容相同,这就是“深拷贝”。

    展开全文
  • 构造方法 构造构造函数

    千次阅读 2017-04-03 05:26:29
    类中可以生命:成员变量,方法,构造器 成员变量包括:实例变量,静态变量 实例变量:用于声明对象的结构的,在创建对象的时候分配对象每个对象有一份 静态变量: 方法:是用于对当前数据进行算法计算,实现业务...
  • C++的构造函数和默认构造函数详解

    万次阅读 多人点赞 2019-04-07 15:19:45
    C++的构造函数和默认构造函数 今天学习c++时突然感觉自己对构造函数和默认构造函数的区别有些分不清,于是查找了各大网站将资料汇总一下,供自己和其他朋友们参考。 构造函数是c++的类在构造对象时调用的函数,此...
  • 构造方法

    万次阅读 多人点赞 2019-05-21 15:54:08
    构造方法是专门用来创建对象的方法,当我们通过关键字new来创建对象时,其实就是调用构造方法。 格式 public 类名称(参数类型 参数名称){ 方法体 } 注意事项 构造方法的名称必须和所在的类名称完全一样,就连大...
  • C++拷贝构造、赋值构造详解

    万次阅读 多人点赞 2018-06-02 00:09:55
    写一个用到指针的程序时,被拷贝、赋值、析构函数坑了一波,网上查相关博客,发现关于拷贝、赋值构造函数调用时机大多都有错误,因此决定自己总结撸一发博客。 A (A&amp; a); //拷贝构造函数 A (const A&...
  • 构造器 与构造方法的关系

    万次阅读 2020-06-28 22:48:42
    构造器的作用: 构造器的产生过程实际上是一个**代码收敛的过程**,**编译器会把语句块**(对于实例构造器而言是“{}”块,对于类构造器而言是“static{}”块)、**变量初始化**(实例变量和类变量)、**调用父类的...
  • Java有参构造方法和无参构造方法

    万次阅读 多人点赞 2018-10-29 11:16:29
    Java有参构造方法和无参构造方法 1**、定义:** 编写一个类时没有添加无参构造方法,那么编译器会自动添加无参构造方法;(如果自己添加构造函数,无论有参数或是没参数,默认构造函数都将无效) 编写时添加了有参...
  • C++默认构造函数

    万次阅读 多人点赞 2018-02-08 12:43:51
    本文围绕3个问题来理解C++的默认构造函数: 什么是默认构造函数? 默认构造函数什么时候被调用? 编译器在什么情况下会生成默认构造函数? 一. 什么是默认构造函数? 我们一般会认为默认构造函数就是编译器...
  • 构造函数与拷贝构造函数

    千次阅读 2019-04-03 09:07:15
    拷贝构造函数和构造函数不能分开说,他们都是初始化对象的一种方法。但是我们这里用构造函数辅助说明拷贝构造函数,主要说说拷贝构造函数的声明,用途和使用注意事项。 众所周知,构造函数是一个初始化类对象的函数...
  • 隐式构造、显示构造

    千次阅读 2018-11-05 21:07:46
    隐式构造的临时对象 class A { public: A(int a) //构造 :_a(a) { } A(A &amp;src) //拷贝构造 { _a = src._a; } operator=(A &amp;src) { } private: ...
  • 构造函数分为三类 一:无参数构造函数; 二:带参数的构造函数 三:赋值构造函数*/ 四:默认构造函数 #include<iostream> using namespace std; class test { public: test()//无参构造函数 { n_a=0;...
  • 构造函数

    千次阅读 2019-06-02 21:32:29
    构造函数 一、定义:每个类都分别定义了它的对象被初始化的方式。类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数就叫构造函数。(构造函数的任务就是初始化类对象的数据成员,无论何时只要类的...
  • [Java基础]-- 有参构造方法和无参构造方法

    万次阅读 多人点赞 2016-03-03 15:06:44
    java构造方法:有参构造方法和无参构造方法   一、无参构造方法 1、定义: 如果编写一个javaBean时没有添加无参构造方法,那么编译器会自动添加无参构造方法; 但是如果编写时添加了有参构造方法而未添加无参...
  • java构造方法:有参构造方法和无参构造方法 一、无参构造方法 1、定义: 如果编写一个javaBean时没有添加无参构造方法,那么编译器会自动添加无参构造方法; 但是如果编写时添加了有参构造方法而未添加无参...
  • Java构造方法和子类构造方法

    千次阅读 2019-07-21 23:50:09
    Java构造方法 构造方法是用于初始化一个新建的对象。 普通构造方法 方法名与类名相同 无返回类型 子类不能继承父类的构造方法 不能被static、final、abstract修饰(有final和abstract修饰的是不能被子类继承的,...
  • java学习—构造器(构造方法)

    万次阅读 多人点赞 2018-02-09 00:58:30
    java中的构造方法是一种特殊的方法,用于初始化对象。java构造函数在对象创建时被调用。它构造值,即提供对象的数据。 创建java构造函数的规则 构造函数基本上定义了两个规则。分别如下: 构造函数名必须与其...
  • Java构造方法

    千次阅读 多人点赞 2019-09-09 19:26:39
    Java构造方法 当新对象被创建的时候,构造方法会被调用。每一个类都有构造方法。当类中没有定义构造函数时,系统会指定给该类加上一个空参数的构造函数。这个是类中默认的构造函数。当类中如果自定义了构造函数,...
  • 构造方法——空参构造、有参构造

    千次阅读 2019-04-24 19:09:37
    1.给对象的数据或属性进行初始化 2.特点:一、方法名与类名相同 ... 四、构造方法不能用对象调用,在创建对象时,系统会自动调用 public class play { public static void main(String[] arg...
  • 一直搞不懂什么是构造函数,为什么要用构造函数,构造函数有什么用,逃避这个问题,今天做了简单的总结: 1.构造函数有什么用? 当你需要大批量的写对象的时候,就需要用到构造函数,它可以方便创建多个对象的实例...
  • Java之构造器和构造方法的使用和意义

    万次阅读 多人点赞 2018-01-03 21:36:21
    java中构造方法是一个重要的概念,初学时有人会对此构造方法的使用特别是其作用不清楚,下面我就来谈谈我对java中构造方法的理解,有不对或不清楚的地方希望各位看官提出意见,谢谢! 一.构造方法的定义声明 ...
  • 有参构造和无参构造

    千次阅读 2019-03-27 13:16:54
    ###构造方法(构造器) ##无参构造 #使用公有的public修饰,方法名与类名一致,无返回值 #连viod都没有 #没有参数 #是默认存在的 ##有参构造 #参数列表必须是本类 的属性 #如果类中写了有参构造,则不在自动生成无参...
  • * 无参数构造函数 系统默认会给每个类创建的构造函数。 * 如果额外写了有参构造函数,要想再用无参构造函数,必须自己再写一遍。 * Test.java文件调用Person,可以测试。 * 若是改为private,是私有化,只要...
  • 默认构造函数和构造函数重载

    万次阅读 多人点赞 2017-09-29 08:15:52
    本文主要总结了默认构造函数的相关用法和构造函数重载,旨在能够对平时的项目开发起到一定的夯实基本功的作用,言简意赅,一目了然。首先需要了解构造函数是用来做什么?该类对象被创建时,编译器为对象分配内存空间...
  • C++ 赋值构造函数 复制构造函数

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

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 558,909
精华内容 223,563
关键字:

构造