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