关于类与对象的进一步讨论.docx
《关于类与对象的进一步讨论.docx》由会员分享,可在线阅读,更多相关《关于类与对象的进一步讨论.docx(19页珍藏版)》请在冰豆网上搜索。
![关于类与对象的进一步讨论.docx](https://file1.bdocx.com/fileroot1/2022-11/17/5e9d89a9-4156-4e8c-9e5b-e3daa28f8ed2/5e9d89a9-4156-4e8c-9e5b-e3daa28f8ed21.gif)
关于类与对象的进一步讨论
第3章关于类和对象的进一步讨论
请注意,这一章内容是C++的重点,要专门注意!
第2章咱们介绍了关于类的一些大体内容,关于类对象的数据成员的初始化咱们始终是通过成立成员函数来实现的。
如:
类Time确实是通过set_time那个成员函数来实现的。
而且一样都是用赋值语句给数据成员赋值,或通过cin来为数据成员从键盘输入值来实现。
然后手工挪用该函数对数据成员进行赋值的。
3Boxbox1Boxbox2rint();
}Boxbox1#include
usingnamespacestd;
classBox
{
public:
Box(inth=10,intw=10,intl=10):
height(h),width(w),length(l){}
intvolume();
private:
intheight,width,length;
};
intBox:
:
volume()
{
returnheight*width*length;
}
intmain()
{
Boxbox1;
cout<<()<Boxbox2(15);
cout<<()<Boxbox3(15,20);
cout<<()<Boxbox4(15,20,30);
cout<<()<}
在构造函数中利用默许参数是方便有效的,这相当于提供了多个重载的构造函数。
说明:
(1)构造函数的默许值要在声明中指定。
(2)声明时能够省略形参名,如:
Box(int=10,int=10,int=10);
(3)当构造函数的参数全数指定为默许值时,能够给出一个或多个参数,也能够不给参数,这时就不能再概念重载构造函数了。
_str());_str());
day=atoi(8,2).c_str());
}2005-12-28<}
~Student()
{cout<<"Destructorcalled."<voiddisplay()
{cout<<"num:
"<cout<<"name:
"<cout<<"sex:
"<}
private:
intnum;
stringname;
charsex;
};
intmain()
{Studentstud1(10010,"Wang_li",'f');
();
Studentstud2(10011,"Zhang_fun",'m');
();
return0;
}
运行结果为:
Constructorcalled.
num:
10010
name:
Wang_li
sex:
f
Constructorcalled.
num:
10011
name:
Zhang_fun
sex:
m
Destructor
Destructor
挪用构造函数和析构函数的顺序
从例的结果能够明白:
先构造的后析构,后构造的先析构。
在一个大程序中,各类作用域的对象很多,有些对象包括在别的对象里面,有些对象早在主函数开始运行之前就已经成立。
创建对象的唯一途径是挪用构造函数。
构造函数是一段程序,因此构造对象的前后顺序不同,直接阻碍程序执行的前后顺序,致使不同的运行结果。
C++给构造对象的顺序作了专门的规定。
一、局部对象
当程序执行到局部对象的概念的地方时,挪用构造函数创建该对象;当程序退出概念该对象所在的函数体时,挪用析构函数释放该对象。
二、静态对象
当程序第一次执行到静态对象的概念的地方时,挪用构造函数创建该对象;当程序终止时挪用析构函数释放该对象。
三、全局对象
当程序开始执行时,挪用构造函数创建该对象;当程序终止时挪用析构函数释放该对象。
和全局变量一样,所有全局对象在主函数开始运行之前,全数已被构造。
因为构造进程是程序语句的执行进程,因此这会给调试带来问题。
当要开始调试时,所有全局对象的构造函数都已被执行,若是它们中的一个有致命错误,那么你可能永久也得不到操纵权。
这种情形下,该程序在它开始执行之前就死机了。
有两种方式能够解决那个问题:
一是将全局对象先作为局部对象来调试;二是在所有疑心有错的构造函数的开头,增加输出语句,如此在程序开始调试时,你能够看到来自这些对象的输出信息。
全局对象不像局部对象的构造顺序那么简单,全局对象是没有如此的操纵流向来指明其顺序的。
关于简单应用的单文件程序来讲,全局对象能够依照它们显现的顺序依次进行构造。
可是,单文件程序只是出此刻实验室或教室里,真正有效的程序都是由多个文件组成的,这些文件被别离编译、连接。
因为编译器不能操纵文件的连接顺序,因此它不能决定不同文件中全局对象之间的构造顺序。
一旦main函数开始启动,那么运行顺序是可控,但全局对象并非依托于从main函数以后的顺序,它早在main运行之前就创建完毕了。
因此全局对象的创建顺序在标准C++中没有规定,也无法规定,一切视编译器的内在特性而定。
下面通过一个实例来看不同对象的作用域和生命期
"<}
~Student()
{cout<<"Destructorcalled."<voiddisplay()
{cout<<"num:
"<}
private:
intnum;
};
intmain()
{
Studentstud[5]={1,2,3,4,5};
return0;
}
运行结果:
Constructorcalled.1
Constructorcalled.2
Constructorcalled.3
Constructorcalled.4
Constructorcalled.5
Destructor
Destructor
Destructor
Destructor
Destructor
Pressanykeytocontinue
若是构造函数有多个参数,那么不能用在概念数组时直接提供所有实参的方式,因为一个数组有多个元素,对每一个元素要提供多个实参,若是再考虑到构造函数有默许参数的情形,很容易造成实参与形参的对应关系不确信,显现二义性。
那么,在概念对象数组时应当如何实现初始化呢?
看下例:
#include
#include
usingnamespacestd;
classStudent
{public:
Student(intn,stringnam,chars)
{num=n;
name=nam;
sex=s;
cout<<"Constructorcalled."<}
~Student()
{cout<<"Destructorcalled."<voiddisplay()
{cout<<"num:
"<cout<<"name:
"<cout<<"sex:
"<}
private:
intnum;
stringname;
charsex;
};
intmain()
{
StudentStud[3]={Student(1001,"wang",'f'),Student(1002,"li",'m'),Student(1003,"zhang",'f')};
return0;
}
运行结果:
Constructorcalled.1001
Destructor
Constructorcalled.1002
Destructor
Constructorcalled.1003
Destructor
Destructor
Destructor
Destructor
再来看一下书中P82例
#include
usingnamespacestd;
classBox
{public:
Box(inth=10,intw=12,intlen=15):
height(h),width(w),length(len){}
intvolume();
~Box()
{cout<<"析构"<private:
intheight;
intwidth;
intlength;
};
intBox:
:
volume()
{return(height*width*length);}
intmain()
{
Boxa[3]={Box(),Box(15,18,20),Box(16,20,26)};
cout<<"volumeofa[0]is"<cout<<"volumeofa[0]is"<cout<<"volumeofa[0]is"<return0;
}
volumeofa[0]is1800
volumeofa[0]is5400
volumeofa[0]is8320
析构162026
析构151820
析构101215
3.5对象指针
指向对象的指针
对象空间的起始地址确实是对象的指针,能够概念一个指针变量,用来寄存对象的指针。
若是有一个类:
#include
usingnamespacestd;
classTime
{
public:
inthour,minute,sec;
Time(int,int,int);
voidget_time();
};
Time:
:
Time(inth,intm,ints)
{
hour=h;minute=m,sec=s;
}
voidTime:
:
get_time()
{
cout<"<"<}
intmain()
{
Time*pt;et_time();p)();
return0;
}
从上例能够明白,概念指向类中成员函数的指针一样形式如下:
返回类型名(类名:
:
指针变量名)(参数列表)
概念好后,就能够够把成员函数名赋值给指针变量名了。
指针变量名=&类名:
:
成员函数名
this指针
在第二章提到过,每一个对象中的数据成员都别离占有存储空间,若是对同一个类概念了n个对象,那么有n组一样大小的空间以寄存n个对象中的数据成员。
可是,不同的对象都挪用同一个函数代码段。
那么,当不同对象的成员函数相用数据成员时,怎么能保证引用的是所指定的对象的数据成员呢?
事实上是每一个成员函数中都包括一个特殊指针,那个指针的名字确实是this。
#include
usingnamespacestd;
classTime
{
public:
Time(int,int,int);
voidget_time();
pri