关于 C++深复制和浅复制(2)

  str这样的野指针是多么的霸道!在有的系统里,这样的行为是被接受的,可以想到其有多危险。有些系统中,不允许这样的事情发生的。于是,上面的程序在codeblock中调试会出错。这个错来的好。

  解决这样的问题的方法,就是在构造函数中,要为指针类型的成员,分配专门的空间。以这条规则构建的复制,称作为深复制!

  上面的程序,改写为:

#include <iostream> 
#include <cstring> 
using namespace std; 
class Test 

private: 
    int a; 
    char *str; 
public: 
    Test(int b, char *s) 
    { 
        a=b; 
        str=new char[strlen(s)+1];  //分配str指向的空间,其长度根据s指向的字符串定。为何加1?字符串结束要用\0 
        strcpy(str,s);  //前一程序的肇事地点,祸端已经由上一句摘除 
    } 
    Test(const Test& C) 
    { 
        a=C.a; 
        str=new char[strlen(C.str)+1];  //同上,这样str就不是野指针了 
        strcpy(str,C.str); 
    } 
    ~Test() 
    { 
        delete []str; 
    } 
    void show () 
    { 
        cout<<a<<","<<str<<endl; 
    } 
}; 

int main() 

    Test a(100,"hello"); 
    Test b(a); 
    a.show(); 
    b.show(); 
    return 0; 

```  
        好了,a和b对象的str成员,明确地给分配了空间,他们再不是野指针了。因为明确地分配了空间,析构函数中要释放对应的空间。我们不能用野指针,当然,也不能对象要撤销了,还占着空间不放,做事不能这样不厚道。
        深复制就体现在第13和第19行分配指针指向的空间,这段空间的地址,也将是指针的值(分清指针的值和指针指向的值)。

下面再给一个例子,类A的数据成员可以保存len个整型数据。类中的数据成员arrayAddr是指向整型的指针,可以作为一个一元数组的起始地址。这个类有指针数据成员,构造函数的定义中,必须要采用深复制的方法,第16行体现了这一点。另外,析构函数中完成了对分配的空间的释放

#include<iostream>
using namespace std;
class A
{
private:
int arrayAddr;//保存一个有len个整型元素的数组的首地址
int len; //记录动态数组的长度
public:
A(int a, int n);
~A();
int sum();
};
A::A(int *a, int n)
{
len=n;
arrayAddr=new int[n]; //为指针数据成员分配空间,注意,没有上面例子中加1那回事
for(int i=0; i<n; i++) //逐个地将a指向的值逐个地复制过来
{
arrayAddr[i]=a[i];
}
}
//析构函数的类外定义,释放指针型数据a所指向的空间
A::~A()
{
delete [] arrayAddr;
}
int A::sum() //获得a指向的数组中下标为i的元素的值
{
int s=0;
for(int i=0; i<len; i++) //逐个地将a指向的值逐个地复制过来
{
s+=arrayAddr[i];
}
return s;
}

int main(){
int b[10]= {75, 99, 90, 93, 38, 15, 5, 7, 52, 4};
A r1(b,10);
cout<<"和:"<<r1.sum()<<endl;
int c[15] = {18,68,10,52,3,19,12,100,56,96,95,97,1,4,93};
A r2(c,15);
cout<<"和:"<<r2.sum()<<endl;
return 0;
}

Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/746a01d7127712dee9a65ed2eec2589b.html