类的构造函数和析构函数
构造函数在类中声明的一种特殊的成员函数
——与所属类名相同
——无返回值
——创建对象时有系统自动调用
——被声明为公有函数
——由new运算符动态创建对象系统自动调用
具有一般成员函数所有的特性
可以访问类的所有数据成员
可以是内联函数
可以无参 可以带参:定义有参的时候 是可以设置形参默认值的
可以重载:一个类 中构造函数可以有多个 以便针对对象不同的特性进行初始化
1)
#include <instream.h>
class CMyclass
{ int a,b;
public:
CMyclass(int x=3,int y=3)
//设置了默认参数
{ a=x;b=y;
}
.....
};
//对于带默认参数的构造函数 函数声明写在类的里面 函数实现写在类的外面的时候 一定要把它的**初始值**放在**类的内部**来写
CMyclass c1(2,4);
CMyclass c2(4);
CMyclass c3;
只有调用构造函数才能完成对象的初始化
如果用户未定义构造函数 调用西东提供的缺省构造函数
<类名>::<缺省构造函数名>(){ }
一个类只有一个缺省的构造函数
[Example] 当调用无参构造函数时
CMyclass c1;//正确
CMyclass c2();//错误
理解:实例化类的对象要调用构造函数 对于错误的那个理解为是对c2函数来进行声明 这个函数不带参 返回类型是CMyclass
所以存在二义性 你可以理解为是构造类的对象 也可以理解为是函数的声明
故为了避免二义性 不要写括号
2)
比较不错的例子
#include <instream.h>
class CMyclass
{ int a,b;
public:
CMyclass()
{
}
CMyclass(int x=3,int y=3)
//设置了默认参数
{ a=x;b=y;
}
.....
};
//定义类对象
CMyclass c2(2,4);
CMyclass c;
//同样具有二义性 是调用无参构造函数还是调用存在缺省值的构造函数呢?
//故具有二义性
另外显示调用构造函数注意调用的正确方法(语法要求) 这在析构函数一节写了。
——————————————————————————
复制构造函数:利用已经生成的一个类对象对将要生成的一个类对象进行初始化
int a1=0;
int a2(a1); //a2=a1 C++特殊语法
CMyclass obj1;
CMyclass obj2(obj1);
//利用复制构造函数来使用
① 复制构造函数是一种特殊的函数
用一个已知的对象(!也就是说作为参!)去创建另一个同类对象
故用一个已经产生的同类的对象作为参数
class class_name
{ public:
class_name(形参表);//构造函数
class_name(class_name &obj_name);//声明
//参是类对象的引用
说明:
//也不是必须写类的复制构造函数
//如果没声明的话 系统会自动生成一个缺省复制构造函数
//可以把**已有对象的每个数据成员的值**都复制到**新建立对象**中
...
}
class :: class_name(class_name &obj_name);
{函数体}
//复制构造函数的实例
**//逐域复制**
class CPoint
{ int x,y;
public:
CPoint(int xx=0,int yy=0){x=xx,y=yy;}
CPoint(CPoint &p){x=p.x;y=p.y}//复制构造函数
int getx(){return x;}
int gety(){return y;}
void main()
{ CPoint a(1,2),d;
CPoint b(a);
CPoint c=a;//C++这行和上面那行同
//复制构造函数是在类对象初始化的时候调用的
d=a;//不会调用复制构造函数 因为d已经是对象了
**//会调用运算符重载函数 以后学**
}
结:其实可以认为复制构造函数和构造函数是重载的
② 需要简单理解一下
void f(CPoint p)
{ ... }
void main()
{ CPoint a(1,2);
f(a);//函数的形参作为类的对象
//会调用复制构造函数
//这么理解:需要把实参a的数据成员复制到形参b中 所以会调用
但是
void f(CPoint &p)
{ ... }
//不会调用复制构造函数
//这么理解 p只是a的引用
③
CPoint g()
{ CPoint a(7,33);
return a;**//这时候要调用复制构造函数**
//?????
通过函数返回知识理解这块
函数返回系统分配的一个临时空间 用来存放函数返回的值 再将这个临时变量赋值给接收返回值的变量 然后把临时空间释放掉
说明:编译系统为了实现返回会在主函数中建立一个无名临时对象
该对象的生存周期只在函数调用所处的表达式b=g()中 **执行return,实际上是调用复制构造函数将a的值复制给临时对象。**
}
void main()
{ CPoint b;
b=g();//不会调用复制构造函数 因为b已经是对象了
**//会调用运算符重载函数 以后学**
结:
什么时候会调用复制构造函数
①利用已经生成的一个类对象对将要生成的一个类对象进行初始化
②类对象作为函数的参数 但是接收它的形参不是引用
③类对象作为函数返回值
—————————————————————————
析构函数
复习:对象的初始化是在对象定义的时候进行数据成员的设置 由构造函数完成
那么对象的清除呢?用析构函数:在撤销对象时做一些内存清理工
作
特征:
—析构函数与类名相同 类名前加**~**
—无参数,但可以是虚函数
—无返回类型
—不能重载(一个类中只能有一个析构函数)
—析构函数定义在公有的部分
如果没定义 系统自动分配个缺省的析构函数。该析构函数是一个空函数
调用:(显示调用 隐式调用)
① 隐式调用:对象定义在函数体内,当这个函数结束时,该对象的析构函数被自动调用。new运算符动态创建的对象,在使用delete运算符释放对象时,也会自动调用析构函数。
#include <instream.h>
class CPoint{
public:
CPoint(int x,int y)
{ X=x;Y=y;cout<<"constructor called."<<endl;}
**~CPoint()**
{....//函数体 一般其实没啥东西 便于理解的话可以加条语句。。}
private:
int X,Y;
}
void main()
{CPoint A(10,20);
CPoint B(5,0);
//通过输出结果我们发现
....
//在同一个有效区(这块是在main中),
//析构函数的调用顺序与构造函数的调用顺序是相反的
}
②显示调用:主动调用析构函数
此时析构函数的作用是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。当对象的生命期结束,程序再自动调用析构函数完成内存清除
class CMyclass
{
public:
int a;
CMyclass(int x=0){a=x;cout<<"constructor"<<endl;}
~CMclass(){cout<<"destructor"<<;}
};
void main()
{CMyclass obj;
obj.CMyclass::CMyclass();//显示调用构造函数必须这么写
cout<<obj.a<<endl;
obj.~CMclass();//显示调用,但是并没销毁对象
cout<<obj.a<<endl;
}
猜猜输出结果是什么呢?????根据析构函数的特点
————————————————————————
构造函数与析构函数综合实例!!!
#include <instream.h>
class CPoint
{ int x,y;
public:
CPoint(int xx=0,int yy=0)//构造函数
{x=xx,y=yy;
cout<<"构造函数被调用"<<endl;}
CPoint(CPoint &p);//复制构造函数
~CPoint()//析构函数
{cout<<"析构函数被调用"<<endl;}
//私有成员通过公有函数间接调用(类似Java)
int getx(){return x;}
int gety(){return y;}
};
CPoint::Point(CPoint &p)
{x=p.x;y=p.y;
cout<<"复制构造函数被调用"<<endl;}
void f(CPoint p)
{cout<<p.getx()<<""<<p.gety()<<endl;}
CPoint g()
{CPoint a(7,23);
return a;}
void main()
{CPoint a(15,3);
CPoint b(a);
cout<<p.getx()<<""<<p.gety()<<endl;
CPoint c=a;
f(b);
b=g();
cout<<b.getx()<<""<<b.gety()<<endl;
}
哈哈哈 有点乱
Output:
构造函数被调用
复制构造函数被调用
15 3
复制构造函数被调用
复制构造函数被调用
15 3
析构函数被调用
构造函数被调用
复制构造函数被调用
析构函数被调用
析构函数被调用
7 33
析构函数被调用
析构函数被调用
析构函数被调用
End:
不过觉得这块不用理解太深 合理这三种函数使用就好
总结
1.首先要明白这三种函数都有一个自动性(系统会自动调用)
2.对于构造函数 比较容易使用 注意在已实例化的对象后调用构造函数前面加类名 其它的几乎同其他语言
3.对于复制构造函数 算是新接触的吧~~注意使用就好了 新创建对象时将已有对象的数据成员复制到新对象中
4.析构函数 这个隐式调用呢?恩.新知识点,其实就是系统自动调用,节省内存我觉得,不用这个对象了系统直接调用它的析构函数 这个显示调用呢?人为的,但要注意即使你人为调用它的,只是在完成一些清理工作(这些清理工作是什么呢。。)当你不用这个对象了系统再直接调用它的析构函数完成内存清除。
~为什么人为调用析构函数。。用途不大吧。。
End
Peace!