拷贝构造
零初始化:类型名(),对于基本类型而言是数值0,对于类或者结构类型而言是匿名对象。
当用一个同类对象初始化一个同类新对象时,调用的自然是拷贝构造函数。一个类如果没有定义拷贝构造函数,编译器会自动产生一个构造函数,内容是逐个复制对于的成员。这一般可以满足程序的需求。如果其中有指针成员指向动态内存的时候两个对象指针成员都会指向相同地方,两个对象释放时都会delete这块内存 从而导致错误。要避免这个问题需要自己来写拷贝构造函数,让每个对象的指针成员各自指向一片动态内存,把旧对象中的数据复制过去。让两片动态内存中的数据相同。
#include<iostream> using namespace std; typedef int T; class A{//数组类,封装和增强数组的功能 T* a; int len; public: A(int n,T init = T()):a(new T[n]){ //零初始化 for (int i = 0;i<n;i++) a[i] = init; len = n; cout<<"创建数组:"<<a <<","<< len << "个元素。" << init <<endl; } ~A(){ cout<<"释放数组:"<< a <<endl; delete[] a; a =NULL; } T& at(int idx){//返回引用 if(idx<0||idx>=len) { cout<<idx<<"超出范围!"<<endl; throw idx;//越界异常结束程序 } else return a[idx]; } int size(){return len;} void resize(int newsize,const T& val=T()){ if (newsize<=len) len = newsize;//缩短在原地就够 else{//加长得换地方 T* np = new T[newsize];//申请新空间 for (int i = 0;i<len;i++) np[i]=a[i];//复制旧数据 for(int i = len;i<newsize;i++) np[i]=val;//给新增元素赋值 delete[] a;//释放旧空间 a = np;//a指向新空间 len = newsize;//记录新大小 } } void print(){ for (int i = 0;i<len;i++) cout<<a[i]<<" "; cout<<endl; } void fill(const T& start,const T& step=T()){//step填充从start开始,步长为step(默认0) for (int i=0;i<len;i++) a[i] = start + step*i; } //过滤数组中的偶数显示出来,返回原来的数组 A filter(A arr){//filter(x) 新建对象arr,用x来初始化arr,调用拷贝构造函数A(const A& r),参数为x for(int i = 0;i<arr.size();i++) if (arr.at(i)%2 == 0) cout << arr.at(i) << " "; cout<< endl; return arr;//返回值对象用arr初始化 } /*编译器自动产生的构造函数样式,会有同一片内存Delete两次的问题 A (const A& r){//r是x的引用(同一体) //拷贝构造函数:实参是个A类型的旧对象 a=r.a;//新对象的a跟x的a指向同一片内存 len=r.len; } */ A (const A& r){//r是x的引用(同一体) //拷贝构造函数:实参是个A类型的旧对象 len = r.len; a = new T[len]; for(int i = 0;i<len;i++) a[i] = r.a[i]; cout<<a<<"创建数组对象复制"<<r.a<<endl; } }; int main() { A x(10);//创建数组对象 x.fill(11,1);//填充11~20 x.print();//显示11~20 x.filter(x).print();//显示偶数 //print 里有个 A arr() system("pause"); return 0; }
运行结果:
复习
小点心:各自增强(强类型,重载,引用//复制)
面向对象:封装、抽象,类(定义.h,实现.cpp) 类型 ,对象,构造函数(可以有参,可以重载),析构函数(一定不能重载)没写编译器会自动产生一个什么都不干的。成员函数。一般而言私有数据,公开函数。成员函数中有this指针指向用来调用这个成员函数的对象。静态成员函数/变量属于真个类,访问时不需要通过对象,直接用 类名::成员,没有this。静态成员变量在类外面初始化(类似用全局变量单要用 类名::成员 格式
初始化列表:在类的构造函数的定义的参数表之后函数体之前,冒号开头,若干对“成员(初始值)”,逗号隔开。成员如果是常量或引用只能用初始化列表。
匿名对象:不取名的对象,同样调用构造函数和析构函数。编译器容易对它进行优化,提倡使用。
一个参数的匿名对象可以看成类型转换,编译器可以自动完成这样的类型转换。用explicit修饰构造函数可以禁止编译器通过它来完成自动类型转换。
new/delete在堆空间创建对象,优点用它创建的对象不会自动释放,必须人为释放。注意配对:new与delete new[]与delete[]配对,特别注意new/delete不要跟malloc/free交叉配对
拷贝构造函数...