美文网首页
构造函数 constructor和复制构造函数 copy con

构造函数 constructor和复制构造函数 copy con

作者: 波洛的汽车电子世界 | 来源:发表于2019-05-03 21:19 被阅读0次

    注:以下大部分内容来源于 coursera 课程《C++程序设计》

    构造函数

    成员函数的一种,有以下特点:

    1. 名字与类名相同,可以有参数,但是不能有返回值(void也不行)。
    2. 作用:给对象进行初始化。这样就不需要写初始化函数和调用初始化,它会自动被调用。
    3. 如果没有写构造函数,编译器会生成默认的构造函数。
    4. 对象生成时构造函数自动被调用。
    class Complex{
    private:double real,imag;
    public :
    Complex(double r, double i=0);
    };
    Complex::Complex(double r, double i)
    {
    real = r; 
    imag = i;
    }
    Complex r2;//报错,构造函数需要初始化,没有给参数,所以没法初始化,出错
    Complex r2(0);//正确,第二个参数可以缺省
    
    1. 可以有多个构造函数,参数个数和参数类型都可以不同。这些构造函数是重载的关系。调用时根据参数个数和类型自动匹配。
    class Complex{
    private:double real,imag;
    public :
    Complex(double r, double i=0);
    Complex(double r);
    Complex(Complex c1,Complex c2);
    };
    Complex::Complex(double r, double i)
    {
    real = r; 
    imag = i;
    }
    Complex::Complex(double r)
    {
    real = r; 
    imag = 0;
    }
    Complex::Complex(Complex c1,Complex c2)
    {
    real = c1.real+c2.real; 
    imag = c1.imag+c2.imag;
    }
    Complex c1(3);
    Complex c2(0,5);
    Complex c3(c1,c2);
    
    
    1. 构造函数在数组中的使用
      例子1:
    class CSample{
    int x;
    public:
    CSample(){cout<<"Constructor 1 called"<<endl;}
    CSample(int n){ x = n;
    cout<<"Constructor 2 called"<<endl;}
    };
    int main(){
    CSample array1[2]; //定义了一个 对象数组array 1,这个数组里面有两个元素。
    // 每个元素都是CSample对象
    //这两个对象初始化的时候所用的参数没有做任何交代,
    //编译器就认为 这个对象应该是用无参的构造函数初始化的。
    cout<<"step 1"<<endl;
    CSample array2[2] = {4,5};
    cout<<"step 2"<<endl;
    CSample array3[2] = {3};
    cout<<"step 3"<<endl;
    CSample *array4 = new CSample[2];
    //动态分配了一个数组,这个数组里边有两个 对象,
    //这两个对象如何初始化呢,我们对参数没有做任何交代
    //那这么两个对象都是用无参的构造函数 初始化的
    delete []array4;
    return 0;
    }
    
    输出:
    
    Constructor 1 called
    Constructor 1 called
    step 1
    Constructor 2 called
    Constructor 2 called
    step 2
    Constructor 2 called
    Constructor 1 called
    step3
    Constructor 1 called
    Constructor 1 called
    

    例子2:

    class Test{
    public:
    Test(int n){}; //(1)
    Test(int n, int m){};//(2)
    Test(){}//(3)
    };
    Test array1[3] = {1,Test(1,2)} //(1)(2)(3)
    Test array2[3] = {Test(2,3),Test(1,2),1} //(2)(2)(1)
    Test *pArray2[3] = {new Test(4),new Test(1,2)} //(1)(2)(3)
    //
    
    

    难点:
    Test *pArray2[3] = {new Test(4),new Test(1,2)} //(1)(2)(3)定义了这样的一个pArray数组,会不会导致对象生成,会不会引发test的构造函数被调用?
    不会,因为这是一个指针数组,它里面的每一个元素都是一个指针,不是一个对象,不会引发任何对象的生成,这个指针可以不初始化的。现在对这个指针数组进行了初始化,而且对它的前两个元素进行 了初始化:new出来两个对象,这个new这个表达式的返回值是指针test *。
    所以使用new出来的对象的地址去初始化这个数组里面的元素。

    这条语句一共生成了几个对象?
    生成了2个对象,而不是3个,为什么呀?因为pArray2的最后这个元素, 我们没有初始化,没有初始化它的话呢,它只不过是一个指针,而且也不知道指向哪,pArray2这个元素生成并不会导致任何对象的生成,所以这条语句, 只是生成了两个对象,这两个对象呢,分别用1,2进行初始化,这个 pArray2呢这个元素,它就是一个未经初始化的指针。

    复制构造函数

    1. 格式:
    X::X(X&)
    X::X(const X&)
    

    只有一个参数,即对同类对象的引用。

    1. 如果没有写,编译器会默认生成。这时候主要完成复制工作。
    class Complex{
    private:
    double real, double imag;
    };
    Complex c1;//调用缺省的无参构造函数
    Complex c1(c2);//调用缺省的复制构造函数,将c2复制给c1,c1与c2完全相等。
    

    这里编译器会生成至少两个构造函数,一个是无参构造函数,一个是复制构造函数。

    1. 也可以定义自己的复制构造函数,这时候的功能
    class Complex{
    private:
    double real, double imag;
    Complex(){}
    Complex(Complex &c){
    real = c.real;
    imag = c.imag;
    cout<<"Copy Constructor called";
    
    }
    };
    Complex c1;//
    Complex c1(c2);//
    

    c2这个对象就是用复制构造函数初始化的。

    1. 复制构造函数的三种作用:
      1) 用一个对象去初始化同类的另一个对象
    Complex c2(c1)
    Complex c2 = c1//初始化语句
    c2 = c1//赋值
    

    2)如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用。

    class A{
    public:
    A(){};
    A(A&a){// 复制构造函数
    cout<<"Copy Constructor called"<<endl;
    }
    };
    void Func(A a1){}
    int main(){
    A a2;
    Func(a2);
    return 0;
    }
    

    void Func(A a1){}函数,形参是类A的对象,如果进到这个函数里面,形参就会被生成。这个形参是用什么构造函数初始化的呢?用复制构造函数初始化的。复制构造函数的时候是需要参数的,这个参数就是a2。
    也就是说,形参a1是用复制构造函数初始化的,初始化a1的时候,那个复制构造函数的参数就是实参a2。
    以前说过,一个函数的形参和实参是相等的。那么这里,形参a1的值还会等于实参a2吗?不一定。因为a1是用自己编写的复制构造函数去初始化的,这里这个函数并没有做复制的工作,而而仅仅是输出Copy Constructor called。
    3) 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数将被调用。

    class A{
    public:
    int v;
    A(int n){v = n};
    A(const A&a){ // 复制构造函数
    v = a.v;
    cout<<"Copy Constructor called"<<endl;
    }
    };
    A Func(){
    A b(4); //定义局部对象b
    return b
    }
    int main(){
    cout<<Func().v<<endl;} //
    

    函数Func()的返回值类A,是一个class A的对象,在生成这个对象的时候,调用了复制构造函数初始化。
    这儿复制构造函数进行了赋值工作,所以在 return b执行完了以后,作为返回值存在的这个对象被初始化,它的值和b一模一样。
    这个函数的返回值一定就跟这个b相等吗? 那不一定了。就取决于你这个复制构造函数是怎么写的了。 因为这个函数的返回值是用复制构造函数初始化的,所以你那个复制构造函数里面如果没有执行复制的工作, 那么这个返回值的对象它的值当然就未必跟这个b相等了。

    1. 为什么要写自己的复制构造函数?

    相关文章

      网友评论

          本文标题:构造函数 constructor和复制构造函数 copy con

          本文链接:https://www.haomeiwen.com/subject/dzbznqtx.html