本文共 2317 字,大约阅读时间需要 7 分钟。
类的构造函数和析构函数的一个典型应用就是:在构造函数中用new为指针成员开辟独立的动态内存空间,而在析构函数中用delete来释放它们。
一个类的成员的数据类型可以是任何有效的合法类型,当数据类型为指针时,这样的成员称为指针成员,注意有潜在的危险性。
class CName
{
public:
CName() // A:显式默认构造函数
{
strName = NULL;
}
CName(char *str) // B:
{
strName = str;
}
~CName() { } //显式默认析构函数
char *getName()
{
return strName;
}
private:
char *strName;
};
int main()
{
char *p = new char[5]; // 为p开辟内存空间
strcpy(p, "DONG"); // p指向的内存空间值为 "DONG"
CName one(p); // 对象初始化
delete []p; // 释放P的内存空间
cout<<one.getName()<<endl;
return 0;
}
以上代码会出现问题,由于 ” CName one(p) “,调用的是B重载构造函数,从而使得私有指针成员 strName指向等于p的指向,而p指向的是new开辟的内存空间,其内容是”DONG“,一旦p指向的内存空间删除,p的指向就不确定了,此时,strName指向也不确定。
为了保证类的封装性,类中的指针成员指向的内存空间必须在类中自行独立开辟和释放。
改进后的代码:
class CName { public: CName() // A:显式默认构造函数 { strName = NULL; } CName(char *str) // B: { //strName = str; //在类的内部自行开辟内存空间 strName = (char *)new char[strlen(str)+1]; strcpy(strName,str); } ~CName() { if (strName) { delete []strName; strName = NULL; } } //显式默认析构函数 char *getName() { return strName; } private: char *strName; }; int main() { char *p = new char[5]; // 为p开辟内存空间 strcpy(p, "DONG"); // p指向的内存空间值为 "DONG" CName one(p); // 对象初始化 delete []p; // 释放P的内存空间 cout<<one.getName()<<endl; return 0; }
对象赋值和拷贝
class CName;
CName o1("DONG"); // A:通过构造函数设定初值
CName o2(o1); //B:通过指定对象设定初值
B语句通过将o1作为o2的初值,o2的初始化形式要调用相应的构造函数,事实上,CName隐含一个特殊的默认构造函数,其原型为:CName (const CName &);这种特殊的默认构造函数称为:默认拷贝构造函数。在C++中,每个类总有一个默认拷贝构造函数,目的是保证B语句中对象初始化形式的合法化,功能等价于:CName o2=o1;
没有指针成员时的情况是:
class CData
{
public:
CData( int data=0 )
{
m_nData = data;
}
~CData() { }
int getData()
{
return m_nData;
}
private:
int m_nData; //非指针型成员变量
};
下面的对象初始化形式是合法的
CData c1(3); // 通过重载构造函数设定初值
CData c2(c1); // 通过默认拷贝构造函数设定初值
//等价于 CData c2=c1;
同类型的变量可以直接用 ” = “ 来赋值,对于CData c2=c1; C++中赋值运算符的操作就是:将右操作对象的内容拷贝到左操作对象的内存空间中去。
有无 指针成员的区别在哪里?
CName的数据成员strName是一个” char * “指针,其自身内存空间存放的是指针的地址,因而其数据的存储还需另外开辟一个不依附于外部的独立的内存空间,由于m_nData自身的内存空间就是用来存储数据的,因此CData对象初始化所进行的数值拷贝是有效的。
浅拷贝
定义:每一个C++类都有一个隐式的默认拷贝构造函数,目的是保证类对象拷贝初始化方式的合法性,其功能是将一个已定义的对象所在的内存空间的内容依次拷贝到被初始化的对象的内存空间中去,这种内存空间内容的拷贝方式称为--浅拷贝。
深拷贝
定义:对于数据成员有指针类型的类来说,都会出现上述CName的问题,由于默认拷贝构造函数无法解决,必须自己定义一个拷贝构造函数,在数值拷贝之前,需要为指针类型的数据成员另辟一个独立的内存空间,因而称为--深拷贝
对于类CName的拷贝构造函数,可以有的合法声明方式有:
CName (CName &x);
CName (const CName &x);
CName (CName &x, ...);
CName (const CName &x, ...);
一旦类中定义了拷贝构造函数,隐式的默认拷贝构造函数和隐式的默认构造函数就失效了!因为拷贝构造函数也是构造函数一种。
转载地址:http://nazqi.baihongyu.com/