没有网站怎么做seo,淘宝代运营,怎样买网站建设,眼睛网站开发本篇文章旨在阐述C类的构造#xff0c;拷贝构造#xff0c;析构机制#xff0c;以及指针成员变量指针悬空问题的解决。需要读者有较好的C基础#xff0c;熟悉引用#xff0c;const的相关知识。 引言#xff1a; 类作为C语言的一种数据类型#xff0c;是对C语言结构体的一… 本篇文章旨在阐述C类的构造拷贝构造析构机制以及指针成员变量指针悬空问题的解决。需要读者有较好的C基础熟悉引用const的相关知识。 引言 类作为C语言的一种数据类型是对C语言结构体的一种扩展。由于C是面向过程与面向对象的混合语言因此在使用面向对象思想解决现实问题模型时设计好类是很重要的跑题了。关于类这篇blog中有很好的介绍链接http://blog.csdn.net/zqixiao_09/article/details/51474556。我要介绍的是关于创建一个空类类体内都包含哪些成员函数呢看下面例子 。 class MyClass { //创建一个空类MyClass};
void main()
{MyClass c; //创建该类的对象c此处会自动调用默认构造函数MyClass d(c); //创建一个对象d并且用已经存在的同类对象c去初始化d此处调用了默认拷贝构造函数MyClass e; //创建一个对象ee c; //此处是对象赋值调用了默认赋值运算符成员函数
} 那么我们来运行一下 可以看到是成功的。 以上实例说明对于用户定义的空类该类会自动包含六个成员函数分别是 l 默认构造函数 A(){//空函数体} l 默认拷贝构造函数本次讲解重点Aconst A {//简单的对象成员变量赋值操作} l 默认析构函数 ~A{//空函数体} l 赋值运算符重载成员函数本次讲解重点 A operator const A {//也是简单的对象成员变量赋值操作} l 取地址操作符重载成员函数 l Const修饰的取地址操作符重载成员函数 前四个是本次讲解的内容重点放在拷贝构造赋值运算符重载这两个成员函数 拷贝构造函数 拷贝构造函数是一种特殊的构造函数具有单个形参该形参常用const修饰是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时将显示使用拷贝构造函数。归结来说。有三个场合要用到拷贝构造函数 l 对象作为函数的参数以值传递的方式传给函数 l 对象作为函数的返回值以值传递的方式从函数返回调用处 l 使用一个对象去初始化一个新建的对象 即有拷贝构造函数的调用一定会有新对象生成。 还有一点需要注意的是拷贝构造函数必须以引用的方式传递参数。这是因为在值传递的方式传递给一个函数的时候会调用拷贝构造函数生成函数的实参。如果拷贝构造函数的参数仍然是以值的方式就会无限循环的调用下去直到函数的栈溢出。 例子 #includeiostream.h
#includestring.h
class Person{
public : Person(); //无参构造函数 Person(int age,char na[]); //重载一般构造函数 Person(const Person p);//拷贝构造函数 ~Person(); // 析构函数 void disp(); private : int age; char *name; }; Person::Person(){ age0; namenew char[2]; strcpy(name,\0); coutdefault constructor\n;} Person::Person(int age,char na[]) { this-ageage; namenew char[strlen(na)1]; //为指针变量动态分配空间 strcpy(name,na); //赋值 coutconstructor\n; } Person::Person(const Person p) { this-agep.age; this-namenew char[strlen(p.name)1]; strcpy(name,p.name); coutcopy constructor\n; } Person::~Person() { delete [] name; coutdestroy\n; } void Person::disp() { coutage age name nameendl; } void f(Person p) { coutenter f \n; p.disp(); return ; } Person f1() { coutenter f \n; Person p; coutnext is return object of Person\n; return p; } void main() { Person p1(21,xiaowang);//调用一般构造函数 p1.disp(); Person p2(p1);//调用拷贝构造函数 p2.disp(); Person p3p1;//调用拷贝构造函数 p3.disp(); couttrue\n; cout拷贝构造函数调用在函数形参是对象且值传递\n; f(p1); //① cout拷贝构造函数调用在函数返回值是对象且值传递\n; f1(); //② cout主函数结束调用三次析构函数销毁对象\n; } 运行结果 我们来分析一下源程序①②处以及运行结果的画线处 ① 处是函数形参是对象且是值传递的情况下调用了拷贝构造函数我们可以看到该形参对象的生存期是只在函数f里面当函数调用结束后就自动被析构函数清理了。但是不会引起指针悬空问题因为如下图所示。 其中p对象是f的形参它由主函数调用f开始存在由函数f调用结束而撤销但是析构p时不会将p1的name所指空间析构因此最终主函数main救赎后析构p1时不会引起指针悬空问题 ② 函数返回值是对象且值传递返回方式时会调用靠宝贝构造函数。 分析结果会看到有两次对象创建在子函数f1里面先创建默认对象p然后返回对象p到调用处会自动调用拷贝构造创建一个匿名的对象记为pi调用结束后会先析构p在析构pi 赋值运算符重载成员函数 拷贝构造函数和赋值运算符的行为比较相似都是将一个对象的值复制给另一个对象但是其结果却有些不同拷贝构造函数使用传入对象的值生成一个新的对象的实例而赋值运算符是将对象的值复制给一个已经存在的实例。这种区别从两者的名字也可以很轻易的分辨出来拷贝构造函数也是一种构造函数那么它的功能就是创建一个新的对象实例赋值运算符是执行某种运算将一个对象的值复制给另一个对象已经存在的。调用的是拷贝构造函数还是赋值运算符主要是看是否有新的对象实例产生。如果产生了新的对象实例那调用的就是拷贝构造函数如果没有那就是对已有的对象赋值调用的是赋值运算符。 实例 #includeiostream.h
const int MAX6;
class Array{double * data;
public:Array();Array(const Array a);~Array();double operator [](int i); //下标重载运算符Array operator (Array a); //重载赋值运算符Array operator (Array a); //运算符重载成员函数Array operator -(Array a); //-运算符重载成员函数void disp(); //输出一个数组
};
Array::Array()
{int i;datanew double[MAX];for(i0;iMAX;i)data[i]0;coutconstructendl;
}
Array::Array(const Array a)
{dataa.data;coutcopy construct \n;
}
Array::~Array()
{delete [] data;coutdestroyendl;
}
double Array::operator [](int i) //返回引用类型可以是左值
{return *(datai);
}
Array Array::operator (Array a) //重载赋值运算符
{int i;for(i0;iMAX;i)data[i]a.data[i];cout对象赋值调用赋值运算符重载函数\n;return *this;
}
Array Array::operator (Array a)
{int i;static Array tmp;for(i0;iMAX;i)tmp.data[i]data[i]a.data[i];return tmp;
}
Array Array::operator -(Array a)
{for(int i0;iMAX;i)data[i]-a.data[i];return *this;
}
void Array::disp()
{for(int i0;iMAX;i)coutdata[i] ;coutendl;
}void main()
{Array a,b,c,d;cout创建四个数组对象\n;cout给数组a赋部分值\n;a[0]1;a[1]2;a[2]3;a[3]4;couta;a.disp();cout执行ba\n;ba;coutb;b.disp();cout执行cab\n;cab;coutc;c.disp();cout执行cab之后ab结果:\n;couta;a.disp();coutb;b.disp();cout执行da-b\n;da-b;coutd;d.disp();cout执行da-b之后ab结果:\n;couta;a.disp();coutb;b.disp();cout主函数执行完毕销毁四个对象和静态成员对象\n;
} 运行结果 分析 从结果可以看出如果函数的形参是对象或者返回值是对象但是是以引用传递的方式那么靠诶构造函数就不会被调用这也是引用的作用即对同一个对象起别名。但要注意在赋值运算符重载成员函数中对象的定义为静态变量这是为了防止子函数调用已结束就将析构该对象导致指针悬空问题。 深拷贝与浅拷贝 深拷贝和浅拷贝主要是针对类中的指针和动态分配的空间来说的因为对于指针只是简单的值复制并不能分割开两个对象的关联任何一个对象对该指针的操作都会影响到另一个对象。这时候就需要提供自定义的深拷贝的拷贝构造函数消除这种影响。通常的原则是 含有指针类型的成员或者有动态分配内存的成员都应该提供自定义的拷贝构造函数在提供拷贝构造函数的同时还应该考虑实现自定义的赋值运算符对于拷贝构造函数的实现要确保以下几点 对于值类型的成员进行值复制对于指针和动态分配的空间在拷贝中应重新分配分配空间对于基类要调用基类合适的拷贝方法完成基类的拷贝拷贝构造函数和赋值运算符的行为比较相似却产生不同的结果拷贝构造函数使用已有的对象创建一个新的对象赋值运算符是将一个对象的值复制给另一个已存在的对象。区分是调用拷贝构造函数还是赋值运算符主要是否有新的对象产生。关于深拷贝和浅拷贝。当类有指针成员或有动态分配空间都应实现自定义的拷贝构造函数。提供了拷贝构造函数最后也实现赋值运算符。总结 拷贝构造函数和赋值运算符的行为比较相似却产生不同的结果拷贝构造函数使用已有的对象创建一个新的对象赋值运算符是将一个对象的值复制给另一个已存在的对象。区分是调用拷贝构造函数还是赋值运算符主要是否有新的对象产生。关于深拷贝和浅拷贝。当类有指针成员或有动态分配空间都应实现自定义的拷贝构造函数。提供了拷贝构造函数最后也实现赋值运算符。 转载于:https://www.cnblogs.com/gaochaochao/p/8370762.html