zoukankan      html  css  js  c++  java
  • C++ 对象的构造

    在类里面成员函数的初始值是多少了?(取决于创建对象的位置,是在堆、栈、还是在静态存储区中创建。)

      例如:  

    #include <stdio.h>
    
    class Test
    {
        private:
        int i;
        int j;
        public :
        int get_i(void)    {return i;}
        int get_j(void)    {return j;}
    };
    
    Test Ta;//在静态存储区中定义 Test类
    
    int main(int argc, char *argv[])
    {
        printf("Ta.i = %d
    ",Ta.get_i());//Ta.i = 0
        printf("Ta.j = %d
    ",Ta.get_j());//Ta.j = 0
    
        Test Tb;//在栈上定义类
        printf("Tb.i = %d
    ",Tb.get_i());//Tb.i = 随机数
        printf("Tb.j = %d
    ",Tb.get_j());//Tb.j = 随机数
        
        Test *Tc = new Test;//在堆上定义类
        printf("Tc->i = %d
    ",Tc->get_i());//Tc.i = 随机数
        printf("Tc->j = %d
    ",Tc->get_j());//Tc.i = 随机数
        
        return 0;
    }

      运行结果:  

    Ta.i = 0
    Ta.j = 0
    Tb.i = 1808322352
    Tb.j = 32766
    Tc->i = 0
    Tc->j = 0

      可以看出,对象只是变量,所以在不同的地方定义变量,所的到的初始值也不同。

      在堆上定义:为随机数

      在栈上定义:为随机数

      在静态存储区上定义:因为静态存储区中变量默认为0 ,所以为0

    这样在不同地方定义初始值就会不同,这样是不允许的所以我们需要对变量进行初始化。这就引入了类的构造函数。

    构造函数:

      构造函数特点:

        1、构造函数没有任何返回类型的声明。

        2、构造函数在定义的时候被自动调用。

        例如:    

    #include <stdio.h>
    
    class Test
    {
        private:
        int i;
        int j;
        public :
        int get_i(void)    {return i;}
        int get_j(void)    {return j;}
        Test()
        {
            printf("Test()
    ");
            i = 5; j = 10;
        }
    };
    
    Test Ta;
    
    int main(int argc, char *argv[])
    {
        printf("Ta.i = %d
    ",Ta.get_i());
        printf("Ta.j = %d
    ",Ta.get_j());
    
        Test Tb;
        printf("Tb.i = %d
    ",Tb.get_i());
        printf("Tb.j = %d
    ",Tb.get_j());
        
        Test *Tc = new Test;
        printf("Tc->i = %d
    ",Tc->get_i());
        printf("Tc->j = %d
    ",Tc->get_j());
        
        return 0;
    }

      在类中加入构造函数。

      运行结果:  

    Test()
    Ta.i = 5
    Ta.j = 10
    Test()
    Tb.i = 5
    Tb.j = 10
    Test()
    Tc->i = 5
    Tc->j = 10

      可以看出每次定义都调用了一次构造函数。

    一个类中可以有多个构造函数构成重载,重载的概念在类中同样适用。

      例如:

      

    #include <stdio.h>
    
    class Test
    {
        private:
        int i;
        int j;
        public :
        int get_i(void)    {return i;}
        int get_j(void)    {return j;}
        Test()
        {
            printf("Test()
    ");
            i = 5; j = 10;
        }
        Test(int v)
        {
            printf("Test(int v);v = %d
    ",v);
            i = 20; j = 30;
        }
    };
    
    
    
    int main(int argc, char *argv[])
    {
        Test Ta;
        printf("Ta.i = %d
    ",Ta.get_i());
        printf("Ta.j = %d
    ",Ta.get_j());
    
        Test Tb(10);
        printf("Tb.i = %d
    ",Tb.get_i());
        printf("Tb.j = %d
    ",Tb.get_j());
        
        Test *Tc = new Test(30);
        printf("Tc->i = %d
    ",Tc->get_i());
        printf("Tc->j = %d
    ",Tc->get_j());
        
        
        return 0;
    }

      运行结果:  

    Test()
    Ta.i = 5
    Ta.j = 10
    Test(int v);v = 10
    Tb.i = 20
    Tb.j = 30
    Test(int v);v = 30
    Tc->i = 20
    Tc->j = 30

    从结果中可以看出:

     Test Ta;调用的是 Test() 这个构造函数。
    Test Tb(10);和 Test *Tc = new Test(30);调用的是   Test(int v) 这个构造函数。

    注意:对象的定义与对象的声明是不同的。例如变量的定义与变量的声明也是不同的。
      对象定义:声明对象的空间并调用构造函数。
      对象的声明:告诉编译器存在这样的一个变量。
    构造函数的手动调用:
      一般来说构造函数在定义对象的时候被自动调用,但是在一些特殊情况下需要手动调用。
      例如构造对象数组。
    实验:创建一个数组类解决数组的安全性问题。
      1、创建Intarray.h
        
    #ifndef __INTARRAY_H
    #define __INTARRAY_H
    class intArray
    {
        private:
        int arrayLenght;
        int *Parray;
        public:
        intArray (int lenght);//构造函数
        bool changeArray(int index,int val);//修改数组中的元素
        int getLenght(void);//获取数组长度
        bool getArrayData(int index,int& val);//获取数组中的元素
        void free();
    };
    
    
    #endif 
      2、创建Intarray.cpp
      
    #include "intArray.h"
    
    intArray::intArray (int lenght)//构造函数
    {
        Parray = new int[lenght];//创建数组空间
        for(int i=0; i<lenght; i++)//初始化
        Parray[i] = 0;
        arrayLenght = lenght;
    }
    bool intArray::changeArray(int index,int val)//修改数组中的元素
    {
        bool ret = (index>=0)&&(index < arrayLenght);//判断是否越界
        if(ret)
        {
            Parray[index] = val;
        }
        return ret;
    }
    int intArray::getLenght(void)//获取数组长度
    {
        return arrayLenght;
    }
    bool intArray::getArrayData(int index, int& val)//获取数组中的元素
    {
        bool ret = (index>=0)&&(index < arrayLenght);//判断是否越界
        if(ret)
        {
            val =  Parray[index] ;
        }
        return ret;
    }
    
    void intArray::free()//
    {
        delete[] Parray;
    }

       3、创建main.cpp

    #include <stdio.h>
    #include "intArray.h"
    
    
    int main(int argc, char *argv[])
    {
        int temp ;
        intArray TestArray(6);
        for(int i=0; i<TestArray.getLenght();i++)
            TestArray.changeArray(i,i);
        for(int i=0; i<TestArray.getLenght();i++)
        {
            if(TestArray.getArrayData(i,temp))
    printf(
    "getArrayData(%d) = %d ",i,temp); } TestArray.free(); return 0; }

    运行结果:

    getArrayData(0) = 0
    getArrayData(1) = 1
    getArrayData(2) = 2
    getArrayData(3) = 3
    getArrayData(4) = 4
    getArrayData(5) = 5
    类中的特殊构造函数:
      1、无参构造函数。(当类中没有定义任何构造函数时,编译器会默认的提供一个无参构造函数,函数体为空
        class_name(){}
      2、拷贝构造函数。参数为const class_name& 的构造函数 (当类中没有定义任何拷贝构造函数时,编译器为默认提供一个拷贝构造函数,其功能为进行成员变量的赋值。)
        例如:定义一个对象的时候使用另外一个对象对其进行初始化。
        class_name class1;
        class_name class2=class1;或者(
    class_name class2(class1);
    )
        通过以上使用就需要用到拷贝构造函数,编译器默认的拷贝构造函数保证的是两个对象的物理状态相同(浅拷贝)。也就是说这是一种 浅拷贝。那么有浅拷贝就必然有深拷贝(其作用是保证两个对象在逻辑状态上相同)。
      例如代码:  
    #include <stdio.h>
    
    class Test
    {
        private:
        int i;
        int j;
        public :
        int get_i(void)    {return i;}
        int get_j(void)    {return j;}
        
    };
    
    
    
    int main(int argc, char *argv[])
    {
        Test Ta;
        Test Tb(Ta);
        printf("Ta.i = %d	",Ta.get_i());
        printf("Ta.j = %d
    ",Ta.get_j());    
        printf("Tb.i = %d	",Tb.get_i());
        printf("Tb.j = %d
    ",Tb.get_j());    
        return 0;
    }
    
    

    运行结果:  

    Ta.i = -1553435232    Ta.j = 22062
    Tb.i = -1553435232    Tb.j = 22062

      从运行结果中可以看出,对象Tb 与对象Ta中的变量i,j值完全相同。

    修改代码:添加拷贝构造函数。

      

    #include <stdio.h>
    
    class Test
    {
        private:
        int i;
        int j;
        public :
        int get_i(void)    {return i;}
        int get_j(void)    {return j;}
        Test(){};
        Test(const Test& t)
        {
          i = t.i;
          j = t.j;
        }
    };
    
    
    
    int main(int argc, char *argv[])
    {
        Test Ta;
        Test Tb(Ta);
        printf("Ta.i = %d	",Ta.get_i());
        printf("Ta.j = %d
    ",Ta.get_j());    
        printf("Tb.i = %d	",Tb.get_i());
        printf("Tb.j = %d
    ",Tb.get_j());    
        return 0;
    }

    运行结果:从结果中可以看出结果同上面没有加入拷贝构造函数时一致。也就是说编译器给我们默认构造了一个拷贝构造函数。内容与下面代码一致  

    Test(const Test& t)
        {
          i = t.i;
          j = t.j;
        }
    Ta.i = 688973216    Ta.j = 22083
    Tb.i = 688973216    Tb.j = 22083

    其中类中成员没有指代系统中的资源。所以看起来没有什么问题。

      修改代码:增加int *p = new int;并打印出p的地址

      

    #include <stdio.h>
    
    class Test
    {
        private:
        int i;
        int j;
        int *p ;
        public :
        int get_i(void)    {return i;}
        int get_j(void)    {return j;}
        int* get_p(void){return p;}
        void free(void){delete p;}
        Test(int v)
        {
            i=1;
            j =2;
            p = new int;
            *p = v;
        };
        Test(const Test& t)
        {
          i = t.i;
          j = t.j;
          p = new int;
         *p = *t.p;
        }
    };
    
    
    
    int main(int argc, char *argv[])
    {
        Test Ta(2);
        Test Tb(Ta);
        printf("Ta.i = %d	,Ta.j = %d	,Ta.p = %p
    ",Ta.get_i(),Ta.get_j(),Ta.get_p());
        printf("Tb.i = %d	,Tb.j = %d	,Tb.p = %p
    ",Tb.get_i(),Tb.get_j(),Tb.get_p());
        Ta.free();
        Tb.free();
        return 0;
    }

    运行结果:  

    Ta.i = 1    ,Ta.j = 2    ,Ta.p = 0x55d66fe34e70
    Tb.i = 1    ,Tb.j = 2    ,Tb.p = 0x55d66fe34e90

    如果在拷贝构造函数中去掉  p = new int;   *p = *t.p;

      运行结果:  

    Ta.i = 1    ,Ta.j = 2    ,Ta.p = 0x55dbf6d60e70
    Tb.i = 1    ,Tb.j = 2    ,Tb.p = (nil)

    申请的 p 指针为空。这显然是不对的。

      打印p所指向空间的值运行结果:  

    Ta.i = 1    ,Ta.j = 2    ,Ta.p = 0x563d1529ee70    ,*Ta.p=2
    Tb.i = 1    ,Tb.j = 2    ,Tb.p = 0x563d1377d9fd    ,*Ta.p=29590344
    munmap_chunk(): invalid pointer
    Aborted (core dumped)

      指针在释放的过程中出现了错误。

    在拷贝构造函数中 增加 p = new int;   *p = *t.p;

      运行结果:  

    Ta.i = 1    ,Ta.j = 2    ,Ta.p = 0x55b993806e70    ,*Ta.p=2
    Tb.i = 1    ,Tb.j = 2    ,Tb.p = 0x55b993806e90    ,*Ta.p=2

    关于深拷贝的说明:  ——自定义拷贝函数,必然需要使用到深拷贝 

      到底什么时候需要用到深拷贝?    ——对象中有成员指代了系统资源。

      1、成员指向了动态内存空间。

      2、成员打开了外部文件。

      3、成员使用了系统中的网络端口

    我们上面的实验使用到了动态内存空间。所以也会出现问题。需要给它加上自定义拷贝函数。
    修改代码如下:
    intArray.cpp 
    intArray::intArray (const intArray& obj)
    {
        Parray = new int[obj.arrayLenght];
        arrayLenght =     obj.arrayLenght;
        for(int i=0;i<obj.arrayLenght;i++)
        Parray[i] = obj.Parray[i];
    }
    
    

    main.cpp

      

    #include <stdio.h>
    #include "intArray.h"
    
    
    int main(int argc, char *argv[])
    {
        int temp ;
        intArray TestArray(6);
        for(int i=0; i<TestArray.getLenght();i++)
            TestArray.changeArray(i,i);
        for(int i=0; i<TestArray.getLenght();i++)
        {
            if(TestArray.getArrayData(i,temp))
            printf("getArrayData(%d) = %d
    ",i,temp);
        }
        intArray TestArray1(TestArray);
        for(int i=0; i<TestArray1.getLenght();i++)
            TestArray1.changeArray(i,i);
        for(int i=0; i<TestArray1.getLenght();i++)
        {
            if(TestArray1.getArrayData(i,temp))
            printf("getArrayData1(%d) = %d
    ",i,temp);
        }
        if(TestArray.getArrayData(100,temp))
        printf("getArrayData(%d) = %d
    ",100,temp);
        TestArray.free();
        TestArray1.free();
        return 0;
    }

      运行结果:

      

    getArrayData(0) = 0
    getArrayData(1) = 1
    getArrayData(2) = 2
    getArrayData(3) = 3
    getArrayData(4) = 4
    getArrayData(5) = 5
    getArrayData1(0) = 0
    getArrayData1(1) = 1
    getArrayData1(2) = 2
    getArrayData1(3) = 3
    getArrayData1(4) = 4
    getArrayData1(5) = 5
      
     


  • 相关阅读:
    django上传下载大文件
    ssh隧道技术
    防止网站被抓
    lvm在线扩容
    Python之配置文件模块 ConfigParser
    Oracle常用查询
    Oracle_where子句
    Oracle_单行函数
    Oracle_多行函数
    Oracle_SQL92_连接查询
  • 原文地址:https://www.cnblogs.com/hjxzjp/p/11651330.html
Copyright © 2011-2022 走看看