第19课 对象的构造(下)

1. 两个特殊的构造函数

 

无参构造函数

拷贝构造函数

参数形式

没有参数的构造函数

参数const class_name&构造函数

默认情况

当类中没有定义构造函数时编译器默认提供一个无参构造函数,并且其函数体为空

当类中没有定义拷贝构造函数时编译器默认提供一个拷贝构造函数简单的进行成员变量的值复制

注意:

定义了构造函数含带参、不带参、或拷贝构造函数,则系统就不再提供默认的无参构造函数。而拷贝构造函数只有在我们定义时,系统才不提供

 

 

 

 

 

 

 

 

 

 

【编程实验】特殊的构造函数(无参构造函数拷贝构造函数)  19-1.cpp

#include <stdio.h>

 

class Test

{

private:

    int i;

    int j;

 

public:

    int getI(){return i;}

 

    int getJ(){return j;}

 

    /*

    //拷贝构造函数

    Test(const Test& t)

    {

        i = t.i;

        j = t.j;

    }

    */

 

   

    //无参构造函数

    Test()

    {

    }

   

};

 

int main()
{

    //调用无参构造函数,注意如果我们定义了构造函数(含无参、带参或拷贝

    //构造函数时)系统就不再提供默认的,需自己定义无参构造函数。

    Test t1; //调用Test()

 

    Test t2 = t1; //调用拷贝构造函数,如果我们不定义,系统会提供默认的

 

    printf("t1.i = %d, t1.j = %d\n",t1.getI(),t1.getJ());

    printf("t2.i = %d, t2.j = %d\n",t2.getI(),t2.getJ());

 

    return 0;

}

运行结果:

  

 

2. 拷贝构造函数

(1)拷贝构造函数意义

  ①兼容C语言的初始化方式,即利用己经存在的对象去创建新的对象。(因为C++中初始化会涉及到拷贝构造函数的调用。注意初始化与赋值是不同的,赋值时“=”运算符会被调用)

    如:int a = b;  //C中,用一个变量来初始化另一个变量;

      Student s2 = s1;//利用己经存在的s1对象来初始化,很像C的初始化方式

  ②初始化行为能够符合预期的逻辑

 

(2)浅拷贝深拷贝

  ①拷贝后对象物理状态相同------->编译器提供的拷贝构造函数只进行浅拷贝

  ②拷贝后对象逻辑状态相同

 

(3)什么时候需要进行深拷贝

  • 对象中有成员指代系统中的资源如:成员指向了动态内存空间打开了外存中的文件使用了系统中的网络端口

  • 一般性原则:自定义拷贝构造函数必然需要实现深拷贝

        

 

深拷贝和浅拷贝的区别

1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组。新对象、新数组只是原对象的一个引用

2.深拷贝创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

 

为什么要使用深拷贝

我们希望在改变新的数组(对象)的时候,不改变原数组(对象)

 

深拷贝的要求程度:

我们在使用深拷贝的时候,一定要弄清楚我们对深拷贝的要求程度:是仅“深”拷贝第一层级的对象属性或数组元素,还是递归拷贝所有层级的对象属性和数组元素?

 

怎么检验深拷贝成功:

改变任意一个新对象/数组中的属性/元素,都不改变原对象/数组

 

【编程实验】对象的初始化  19-2.cpp

#include <stdio.h>

 

class Test

{

private:

    int i;

    int j;

    int* p;

 

public:

    int getI(){return i;}

 

    int getJ(){return j;}

 

    int* getP(){return p;}

 

    /*

    //拷贝构造函数
    Test(const Test& t)

    {

        i = t.i;

        j = t.j;

        p = new int;

 

        *p = *t.p;

    }

    */

 

   

    //带参构造函数

    Test(int v)

    {

        i = 1;

        j = 2;

        p = new int;

       

        *p = v;

    }

 

    ~Test(){delete p;}

   

};

 

int main()
{

    Test t1(3);  //调用Test(int v);

    Test t2(t1); //调用Test(const Test& t)---浅拷贝

 

    printf("t1.i = %d, t1.j = %d, *t1.p = %d\n", t1.getI(), t1.getJ(), *t1.getP());

    printf("t2.i = %d, t2.j = %d, *t2.p = %d\n", t2.getI(), t2.getJ(), *t2.getP());

 

    return 0;

}

运行结果:

  

 

【编程实验】数组类的改进  IntArray

//IntArray.h

#ifndef _INTARRAY_H_

#define _INTARRAY_H_

 

class IntArray

{

private:

    int m_length;

    int* m_pointer;

 

public:

    IntArray(int len);

    IntArray(const IntArray& obj);

    ~IntArray();

 

    int length();

    bool get(int index, int& value);

    bool set(int index, int value);

};

 

#endif

 

//IntArray.cpp

#include "IntArray.h"

 

IntArray::IntArray(int len)

{

    m_pointer = new int[len];

 

    for(int i = 0; i<len; i++)

    {

        m_pointer[i] = 0;

    }

 

    m_length = len;

}

 

IntArray::IntArray(const IntArray& obj)

{

    m_length = obj.m_length;

 

    m_pointer = new int[obj.m_length];

 

    for (int i = 0;i < obj.m_length; i++)

    {

        m_pointer[i] = obj.m_pointer[i];

    }

}

 

IntArray::~IntArray()

{

    if(m_pointer)

    {

        delete[] m_pointer;

    }

}

 

int IntArray::length()

{

    return m_length;

}

 

bool IntArray::get(int index, int& value)

{

   bool bRet = (0 <= index) && (index <m_length);

 

   if(bRet)

   {

        value = m_pointer[index];

   }

 

   return bRet;

}

 

bool IntArray::set(int index, int value)

{

 

   bool bRet = (0 <= index) && (index <m_length);

 

   if(bRet)

   {

        m_pointer[index] = value;

   }

 

   return bRet;

}

 

//main.cpp

#include <stdio.h>

#include "IntArray.h"

 

int main()

{

    IntArray a(5);//调用带参构造函数

   

    for(int i=0; i<a.length(); i++)

    {

        a.set(i, i + 1);

    }

 

    for(int i=0; i<a.length(); i++)

    {

        int value = 0;

 

        if(a.get(i, value))

        {

            printf("a[%d] = %d\n", i, value);

        }

    }

 

    IntArray b = a; //调用拷贝构造函数

   

    for(int i=0; i<b.length();i++)

    {

        int value = 0;

 

        if(b.get(i, value))

        {

            printf("b[%d] = %d\n", i, value);

        }

    }

    return 0;

}

 

3. 小结

(1)C++编译器默认提供构造函数

(2)无参构造函数用于定义对象默认初始状态

(3)拷贝构造函数创建对象拷贝对象的状态

(4)对象的拷贝浅拷贝深拷贝两种方式

  ①浅拷贝使得对象的物理状态相同------->编译器提供的拷贝构造函数只进行浅拷贝

  ②深拷贝使得对象的逻辑状态相同

posted @ 2018-12-09 15:55  梦心之魂  阅读(151)  评论(0编辑  收藏  举报