类和对象的进一步讨论.ppt

上传人:小飞机 文档编号:6329513 上传时间:2023-10-17 格式:PPT 页数:109 大小:600.50KB
返回 下载 相关 举报
类和对象的进一步讨论.ppt_第1页
第1页 / 共109页
类和对象的进一步讨论.ppt_第2页
第2页 / 共109页
类和对象的进一步讨论.ppt_第3页
第3页 / 共109页
类和对象的进一步讨论.ppt_第4页
第4页 / 共109页
类和对象的进一步讨论.ppt_第5页
第5页 / 共109页
点击查看更多>>
资源描述

《类和对象的进一步讨论.ppt》由会员分享,可在线阅读,更多相关《类和对象的进一步讨论.ppt(109页珍藏版)》请在三一办公上搜索。

1、第三章 关于类和对象的进一步讨论,构造函数和析构函数是在类体中说明的两种特殊的成员函数。,构造函数是在创建对象时,使用给定的值来将对象初始化。,析构函数的功能正好相反,是在系统释放对象前,对对象做一些善后工作。,构造函数是类的成员函数,系统约定构造函数名必须与类名相同。构造函数提供了初始化对象的一种简单的方法。构造函数自动执行。,构造函数可以带参数、可以重载,同时没有返回值。构造函数不具有任何类型,不要用void说明。,例3.1 70页Time类的构造函数Timeclass Timeprivate:int hour,mimute,sec;public:Time()hour=0;minute=0

2、;sec=0;/构造函数,初始化对象 void set_time();/函数声明 void show_time();,对构造函数,说明以下几点:1.构造函数的函数名必须与类名相同。构造函数的主要作用是完成初始化对象的数据成员以及其它的初始化工作。2.在定义构造函数时,不能指定函数返回值的类型,也不能指定为void类型。3.一个类可以定义若干个构造函数。当定义多个构造函数时,必须满足函数重载的原则。,4.构造函数可以指定参数的缺省值。,5.若定义的类要说明(产生,建立)该类的对象时,构造函数必须是公有的成员函数。如果定义的类仅用于派生其它类(不直接产生该类型的对象)时,则可将构造函数定义为保护的

3、成员函数。6.构造函数不需用户调用,也不能被用户调用,是系统自动调用的。例如:t1.Time();/非法,7.如果用户没有定义构造函数,系统会自动生成一个构造函数。由于构造函数属于类的成员函数,它对私有数据成员、保护的数据成员和公有的数据成员均能进行初始化。,class Afloat x,y;public:A(float a,float b)x=a;y=b;/构造函数,初始化对象float Sum(void)return x+y;void Set(float a,float b)x=a;y=b;Print(void)coutx=xty=yendl;void main(void)A a1(2.0

4、,3.0);/定义时调用构造函数初始化A a2(1.0,2.0);a2.Set(10.0,20.0);/利用成员函数重新为对象赋值 a1.Print();a2.Print();,例子3.2 72页 长方柱Box类的构造函数class Boxint height,width,length;public:Box(int,int,int);/声明带参数的构造函数 int volume()return(height*width*length;Box:Box(int h,int w,int len)height=h;width=w;length=len;,class Afloat x,y;public:

5、A(float a,float b=10)x=a;y=b;A()x=0;y=0;void Print(void)coutxtyendl;void main(void)A a1,a2(20.0),a3(3.0,7.0);a1.Print();a2.Print();a3.Print();,00201037,带缺省参数的构造函数,不带参数的构造函数,每一个对象必须要有相应的构造函数,每一个对象必须要有相应的构造函数,若没有显式定义构造函数,系统默认缺省的构造函数。,class Afloat x,y;public:A()void Print(void)coutxtyendl;,隐含的缺省的构造函数,A

6、 a1,a2;,只允许这样定义对象,对象开辟了空间,但没有初始化,对局部对象,静态对象,全局对象的初始化对于局部对象,每次定义对象时,都要调用构造函数。对于静态对象,是在首次定义对象时,调用构造函数的,且由于对象一直存在,只调用一次构造函数。对于全局对象,是在main函数执行之前调用构造函数的。,class A int x,y;public:A(int a)x=a;cout“1n”;A(int a,int b)x=a,y=b;cout“2n”;A a1(3);void f(void)A b(2,3);void main(void)A a2(4,5);f();f();,1,2,2,2,class

7、 Afloat x,y;public:A(float a,float b)x=a;y=b;cout初始化自动局部对象n;A()x=0;y=0;cout初始化静态局部对象n;A(float a)x=a;y=0;cout初始化全局对象n;void Print(void)coutxtyendl;A a0(100.0);/定义全局对象void f(void)cout 进入f()函数n;A a2(1,2);static A a3;/初始化局部静态对象 void main(void)cout进入main函数n;A a1(3.0,7.0);/定义局部自动对象 f();f();,初始化全局对象,进入main函

8、数,初始化自动局部对象,进入f()函数,初始化局部静态变量,进入f()函数,初始化自动局部对象,初始化自动局部对象,缺省的构造函数,在定义类时,若没有定义类的构造函数,则编译器自动产生一个缺省的构造函数,其格式为:className:className()缺省的构造函数并不对所产生对象的数据成员赋初值;即新产生对象的数据成员的值是不确定的。,class Afloat x,y;public:A()/缺省的构造函数,编译器自动产生,可以不写float Sum(void)return x+y;void Set(float a,float b)x=a;y=b;void Print(void)coutx

9、=xty=yendl;void main(void)A a1,a2;/产生对象时,自动调用缺省的构造函数,不赋值a1.Set(2.0,4.0);couta1:;a1.Print();couta1.sum=a1.Sum()endl;a2.Print();/打印随机值,关于缺省的构造函数,说明以下几点:1、在定义类时,只要显式定义了一个类的构造函数,则编译器就不产生缺省的构造函数,2、所有的对象在定义时,必须调用构造函数,不存在没有构造函数的对象!,class Afloat x,y;public:A(float a,float b)x=a;y=b;void Print(void)coutxtyen

10、dl;void main(void)A a1;A a2(3.0,30.0);,显式定义了构造函数,不产生缺省的构造函数,error,定义时,没有构造函数可供调用,3、在类中,若定义了没有参数的构造函数,或各参数均有缺省值的构造函数也称为缺省的构造函数,缺省的构造函数只能有一个。,4、产生对象时,系统必定要调用构造函数。所以任一对象的构造函数必须唯一。,class Afloat x,y;public:A(float a=10,float b=20)x=a;y=b;A()void Print(void)coutxtyendl;void main(void)A a1;A a2(3.0,30.0);,

11、两个函数均为缺省的构造函数,两个构造函数均可供调用,构造函数不唯一,用参数初始化表对数据成员初始化:,Box:Box(int h,int w,int len)height=h;width=w;length=len;等同与下面的程序:Box:Box(int h,int w,int len):height(h),width(w),length(len)即在原来函数”)”后加一个冒号”:”,然后列出参数的初始化表。,析构函数,析构函数的作用与构造函数正好相反,是在对象的生命期结束时,释放系统为对象所分配的空间,即要撤消一个对象。,析构函数也是类的成员函数,定义析构函数的格式为:ClassName:C

12、lassName()./函数体;,析构 函数的特点如下:1、析构函数是成员函数,函数体可写在类体内,也可写在类体外。,2、析构函数是一个特殊的成员函数,函数名必须与类名相同,并在其前面加上字符“”,以便和构造函数名相区别。,3、析构函数不能带有任何参数,不能有返回值,不指定函数类型。,在程序的执行过程中,当遇到某一对象的生存期结束时,系统自动调用析构函数,然后再收回为对象分配的存储空间。,4、一个类中,只能定义一个析构函数,析构函数不允许重载。,5、析构函数是在撤消对象时由系统自动调用的。,class Afloat x,y;public:A(float a,float b)x=a;y=b;co

13、ut调用非缺省的构造函数n;A()x=0;y=0;cout调用缺省的构造函数n;A()cout调用析构函数n;void Print(void)coutxtyendl;void main(void)A a1;A a2(3.0,30.0);cout退出主函数n;,调用缺省的构造函数,调用非缺省的构造函数,退出主函数,调用析构函数,调用析构函数,例子3.5 7880页 student类 class Student Student()/定义析构函数 cout“Destructor called.”endl;析构次序与构造次序相反。见80页的执行结果。80页图3.1,构造函数与new运算符,可以使用ne

14、w运算符来动态地建立对象。建立时要自动调用构造函数,以便完成初始化对象的数据成员。最后返回这个动态对象的起始地址。,用new运算符产生的动态对象,在不再使用这种对象时,必须用delete运算符来释放对象所占用的存储空间。,用new建立类的对象时,可以使用参数初始化动态空间。,class Afloat x,y;public:A(float a,float b)x=a;y=b;A()x=0;y=0;void Print(void)coutPrint();pa2-Print();delete pa1;/用delete释放空间 delete pa2;/用delete释放空间,500,在程序的执行过程中

15、,对象如果用new运算符开辟了空间,则在类中应该定义一个析构函数,并在析构函数中使用delete删除由new分配的内存空间。因为在撤消对象时,系统自动收回为对象所分配的存储空间,而不能自动收回由new分配的动态存储空间。,class Strchar*Sp;int Length;public:Str(char*string)if(string)Length=strlen(string);Sp=new charLength+1;strcpy(Sp,string);else Sp=0;void Show(void)coutSpendl;Str()if(Sp)delete Sp;void main(v

16、oid)Str s1(Study C+);s1.Show();,在构造函数中将成员数据指针指向动态开辟的内存,用初值为开辟的内存赋值,析构函数,当释放对象时收回用new开辟的空间,string,Length=strlen(string);,Sp=new charLength+1;,Sp,new开辟的空间,strcpy(Sp,string);,用new运算符为对象分配动态存储空间时,调用了构造函数,用delete删除这个空间时,调用了析构函数。当使用运算符delete删除一个由new动态产生的对象时,它首先调用该对象的析构函数,然后再释放这个对象占用的内存空间。,可以用new运算符为对象分配存储

17、空间,如:,A*p;p=new A;,这时必须用delete才能释放这一空间。,delete p;,class Afloat x,y;public:A(float a,float b)x=a;y=b;coutPrint();delete pa1;/调用析构函数 cout退出main()函数n;,进入main()函数,调用了构造函数,35,调用了析构函数,退出main()函数,不同存储类型的对象调用构造函数及析构函数,1、对于全局定义的对象(在函数外定义的对象),在程序开始执行时,调用构造函数;到程序结束时,调用析构函数。,2、对于局部定义的对象(在函数内定义的对象),当程序执行到定义对象的地方

18、时,调用构造函数;在退出对象的作用域时,调用析构函数。,3、用static定义的局部对象,在首次到达对象的定义时调用构造函数;到程序结束时,调用析构函数,4、对于用new运算符动态生成的对象,在产生对象时调用构造函数,只有使用delete运算符来释放对象时,才调用析构函数。若不使用delete来撤消动态生成的对象,程序结束时,对象仍存在,并占用相应的存储空间,即系统不能自动地调用析构函数来撤消动态生成的对象。,class Afloat x,y;public:A(float a,float b)x=a;y=b;cout初始化自动局部对象n;A()x=0;y=0;cout初始化静态局部对象n;A(

19、float a)x=a;y=0;cout初始化全局对象n;A()cout“调用析构函数”endl;A a0(100.0);/定义全局对象void f(void)cout 进入f()函数n;A ab(10.0,20.0);/定义局部自动对象 static A a3;/初始化局部静态对象 void main(void)cout进入main函数n;f();f();,初始化全局对象,进入main函数,初始化自动局部对象,进入f()函数,初始化静态局部对象,进入f()函数,初始化自动局部对象,调用析构函数,调用析构函数,调用析构函数,调用析构函数,举例:建立一个类NUM,求指定数据范围内的所有素数。如:

20、定义类NUM的对象test,查找范围为100200,正确的输出结果:num=21101 103 107 109 113127 131,动态构造及析构对象数组,用new运算符来动态生成对象数组时,自动调用构造函数,而用delete运算符来释放p1所指向的对象数组占用的存储空间时,在指针变量的前面必须加上,才能将数组元素所占用的空间全部释放。否则,只释放第0个元素所占用的空间。,pa1=new A3;.delete pa1;,class Afloat x,y;public:A(float a=0,float b=0)x=a;y=b;cout调用了构造函数n;void Print(void)cout

21、xtyendl;A()cout调用了析构函数n;void main(void)cout进入main()函数n;A*pa1;pa1=new A3;/开辟数组空间coutn完成开辟数组空间nn;delete pa1;/必须用删除开辟的空间 cout退出main()函数n;,进入main()函数,调用了构造函数,调用了构造函数,调用了构造函数,完成开辟数组空间,调用了析构函数,调用了析构函数,调用了析构函数,退出main()函数,缺省的析构函数,若在类的定义中没有显式地定义析构函数时,则编译器自动地产生一个缺省的析构函数,其格式为:ClassName:ClassName();,任何对象都必须有构造函

22、数和析构函数,但在撤消对象时,要释放对象的数据成员用new运算符分配的动态空间时,必须显式地定义析构函数。,实现类型转换的构造函数,同类型的对象可以相互赋值,相当于类中的数据成员相互赋值;如果直接将数据赋给对象,所赋入的数据需要强制类型转换,这种转换需要调用构造函数。,class Afloat x,y;public:A(float a,float b)x=a;y=b;cout调用构造函数n;A()cout调用析构函数n;void Print(void)coutxtyendl;void main(void)A a1(1.0,10.0);a1.Print();a1=A(3.0,30.0);a1.P

23、rint();cout退出主函数n;,调用构造函数,产生临时对象,初始化并赋值后立即释放,1 10,调用构造函数,调用析构函数,330,退出主函数,调用析构函数,注意:当构造函数只有一个参数时,可以用=强制赋值。,class Bfloat x;public:B(float a)x=a;cout调用构造函数n;B()cout调用析构函数n;void Print(void)coutxendl;void main(void)B b1(1.0);b1.Print();B b2=100;b2.Print();b1=10;b1.Print();cout退出主函数n;,调用构造函数,单参数可以这样赋值,1,

24、调用构造函数,100,调用构造函数,调用析构函数,10,退出主函数,调用析构函数,调用析构函数,b1=B(10),产生一个临时对象,完成拷贝功能的构造函数,可以在定义一个对象的时候用另一个对象为其初始化,即构造函数的参数是另一个对象的引用,这种构造函数常为完成拷贝功能的构造函数。,完成拷贝功能的构造函数的一般格式为:ClassName:ClassName(ClassName&)./函数体完成对应数据成员的赋值,class Afloat x,y;public:A(float a=0,float b=0)x=a;y=b;A(A;,void main(void)A a1(1.0,2.0);A a2(

25、a1);,形参必须是同类型对象的引用,实参是同类型的对象,class Afloat x,y;public:A(float a=0,float b=0)x=a;y=b;cout调用了构造函数n;A(A,调用了构造函数调用了完成拷贝功能的构造函数1212调用了析构函数调用了析构函数,用已有的对象中的数据为新创建的对象赋值,如果没有定义完成拷贝功能的构造函数,编译器自动生成一个隐含的完成拷贝功能的构造函数,依次完成类中对应数据成员的拷贝。,A:A(A,隐含的构造函数,class Afloat x,y;public:A(float a=0,float b=0)x=a;y=b;cout调用了构造函数n;

26、void Print(void)coutxtyendl;A()cout调用了析构函数n;void main(void)A a1(1.0,2.0);A a2(a1);A a3=a1;/可以这样赋值 a1.Print();a2.Print();a3.Print();,调用了构造函数121212调用了析构函数调用了析构函数调用了析构函数,隐含了拷贝的构造函数,由编译器为每个类产生的这种隐含的完成拷贝功能的构造函数,依次完成类中对应数据成员的拷贝。,但是,当类中的数据成员中使用new运算符,动态地申请存储空间进行赋初值时,必须在类中显式地定义一个完成拷贝功能的构造函数,以便正确实现数据成员的复制。,c

27、lass Str int Length;char*Sp;public:Str(char*string)if(string)Length=strlen(string);Sp=new charLength+1;strcpy(Sp,string);else Sp=0;void Show(void)coutSpendl;Str()if(Sp)delete Sp;void main(void)Str s1(Study C+);Str s2(s1);s1.Show();s2.Show();,隐含的拷贝构造函数为:Str:Str(Str,s1.Sp,s2.Sp,new开辟的空间,同一空间释放两次,造成运行错

28、误。,在这种情况下,必须要定义完成拷贝功能的构造函数。,Str:Str(Str,s1.Sp,原来s1开辟的空间,s2.Sp,拷贝函数中用new开辟的空间,构造函数与对象成员,对类A的对象初始化的同时还要对其成员数据类B的对象进行初始化,所以,类A的构造函数中要调用类B的构造函数。,class B.;,class A int x,y;B b1,b2;;,在类A中包含类B的对象,class A float x,y;public:A(int a,int b)x=a;y=b;void Show()cout x=xty=yn;class Cfloat z;A a1;/类C的数据成员为类A 的对象a1pu

29、blic:C(int a,int b,int c):a1(b,c)z=a;/类C的对象初始化 void Show()cout“z=an;a1.Show();void main(void)C c1(1,2,3);/对类C的对象初始化c1.Show();,在类C中调用类A的成员函数,利用类A的构造函数对类A的对象初始化,a1,A,C,a1(b,c),ClassName:ClassName(args):c1(args1),.,cn(agrsn)./对其它成员的初始化 初始化对象成员的参数(实参)可以是表达式。,也可以仅对部分对象成员进行初始化。,class A float x,y;public:A(

30、int a,int b)x=a;y=b;void Show()cout x=xty=yn;class Bfloat x1,y1;public:B(int a,int b)x1=a;y1=b;void Show()cout“x1=“x1t“y=“yn;class Cfloat z;A a1;B b1;public:C(int a,int b,int c,int d,int e):a1(a+b,c),b1(a,d)z=e;void Show()cout“z=an;a1.Show();b1.Show();void main(void)C c1(1,2,3,4,5);/对类C的对象初始化,对象初始化的

31、参数可以是表达式,对对象成员的构造函数的调用顺序取决于这些对象成员在类中说明的顺序,与它们在成员初始化列表中的顺序无关。当建立类ClassName的对象时,先调用各个对象成员的构造函数,初始化相应的对象成员,然后才执行类ClassName的构造函数,初始化类ClassName中的其它成员。析构函数的调用顺序与构造函数正好相反。,class Afloat x;public:A(int a)x=a;cout“调用了A的构造函数n”;A()cout“调用了A的析构函数n”;class Bfloat y;public:B(int a)y=a;cout“调用了B的构造函数n”;B()cout“调用了B的

32、析构函数n”;class Cfloat z;B b1;A a1;public:C(int a,int b,int c):a1(a),b1(b)z=c;cout“调用了C的构造函数n”;C()cout“调用了C的析构函数n”;void main(void)C c1(1,2,3);,调用了B的构造函数,调用了A的构造函数,调用了C的构造函数,调用了C的析构函数,调用了A的析构函数,调用了B的析构函数,通常,每当说明一个对象时,把该类中的有关成员数据拷贝到该对象中,即同一类的不同对象,其成员数据之间是互相独立的。,静态成员,class A int x,y;public:void Setxy(int

33、a,int b)x=a;y=b;A a1,a2;,a1.x,a1.y,a2.x,a2.y,a1.Setxy(),a2.Setxy(),a1.Setxy(1,2);a2.Setxy(3,4);,this-x=a;,this-y=b;,当我们将类的某一个数据成员的存储类型指定为静态类型时,则由该类所产生的所有对象,其静态成员均共享一个存储空间,这个空间是在编译的时候分配的。换言之,在说明对象时,并不为静态类型的成员分配空间。在类定义中,用关键字static修饰的数据成员称为静态数据成员。,class A int x,y;static int z;public:void Setxy(int a,in

34、t b)x=a;y=b;A a1,a2;,z,a1.z,a2.z,不同对象,同一空间,有关静态数据成员的使用,说明以下几点:1、类的静态数据成员是静态分配存储空间的,而其它成员是动态分配存储空间的(全局变量除外)。当类中没有定义静态数据成员时,在程序执行期间遇到说明类的对象时,才为对象的所有成员依次分配存储空间,这种存储空间的分配是动态的;而当类中定义了静态数据成员时,在编译时,就要为类的静态数据成员分配存储空间。,2、必须在文件作用域中,对静态数据成员作一次且只能作一次定义性说明。因为静态数据成员在定义性说明时已分配了存储空间,所以通过静态数据成员名前加上类名和作用域运算符,可直接引用静态数

35、据成员。在C+中,静态变量缺省的初值为0,所以静态数据成员总有唯一的初值。当然,在对静态数据成员作定义性的说明时,也可以指定一个初值。,class Aint i,j;static int x,y;/定义静态成员public:A(int a=0,int b=0,int c=0,int d=0)i=a;j=b;x=c;y=d;void Show()cout i=itj=jt;cout x=xty=yn;int A:x=0;/必须对静态成员作一次定义性说明 int A:y=0;void main(void)A a(2,3,4,5);a.Show();A b(100,200,300,400);b.Sh

36、ow();a.Show();,a.x 和b.x在内存中占据一个空间a.y 和b.y在内存中占据一个空间,i=2j=3x=4y=5,i=100j=200 x=300y=400,i=2j=3x=300y=400,class Aint i,j;public:static int x;public:A(int a=0,int b=0,int c=0)i=a;j=b;x=c;void Show()cout i=itj=jt;cout x=xn;int A:x=500;/int A:xvoid main(void)A a(20,40,10),b(30,50,100);a.Show();b.Show();c

37、out“A:x=”A:xn;/可以直接用类名引用,在类外重新定义,3、静态数据成员具有全局变量和局部变量的一些特性。静态数据成员与全局变量一样都是静态分配存储空间的,但全局变量在程序中的任何位置都可以访问它,而静态数据成员受到访问权限的约束。必须是public权限时,才可能在类外进行访问。,4、为了保持静态数据成员取值的一致性,通常在构造函数中不给静态数据成员置初值,而是在对静态数据成员的定义性说明时指定初值。,class Aint i;static int count;public:A(int a=0)i=a;count+;cout Number of Objects=countn;A()c

38、ount-;cout Number of Objects=countn;void Show()cout i=in;cout count=countn;int A:count;void main(void)A a1(100);A b2;a1.Show();,Number of Objects=1,Number of Objects=2,Number of Objects=3,i=100count=3,Number of Objects=2,Number of Objects=1,Number of Objects=0,静态成员函数可以将类的成员函数定义为静态的成员函数。即使用关键字static来

39、修饰成员函数。,class A float x,y;public:A()static void sum(void).;,对静态成员函数的用法说明以下几点:1、与静态数据成员一样,在类外的程序代码中,通过类名加上作用域操作符,可直接调用静态成员函数。,2、静态成员函数只能直接使用本类的静态数据成员或静态成员函数,但不能直接使用非静态的数据成员(可以引用使用)。这是因为静态成员函数可被其它程序代码直接调用,所以,它不包含对象地址的this指针。,class Tc private:int A;static int B;/静态数据成员public:Tc(int a)A=a;B+=a;static vo

40、id display(Tc c)/Tc的对象为形参 coutA=c.A,B=Bendl;int Tc:B=2;void main(void)Tc a(2),b(4);Tc:display(a);Tc:display(b);,非静态成员,用对象名来引用,静态成员,直接引用,直接用类名来调用静态成员函数,A=2,B=8,A=4,B=8,3、静态成员函数的实现部分在类定义之外定义时,其前面不能加修饰词static。这是由于关键字static不是数据类型的组成部分,因此,在类外定义静态成员函数的实现部分时,不能使用这个关键字4、不能把静态成员函数定义为虚函数。静态成员函数也是在编译时分配存储空间,所以

41、在程序的执行过程中不能提供多态性。5、可将静态成员函数定义为内联的(inline),其定义方法与非静态成员函数完全相同。,class Tc private:int A;static int B;/静态数据成员public:Tc(int a)A=a;B+=a;static void display(Tc c);/Tc的对象为形参;void Tc:display(Tc c)/不用static修饰 coutA=c.A,B=Bendl;int Tc:B=2;void main(void)Tc a(2),b(4);Tc:display(a);Tc:display(b);,函数原型,类外定义,静态变量,在

42、变量声明前面加上关键字static,就使该变量成为静态的。对于非静态变量,每个类对象都有自己的拷贝;而静态变量对每个类只有一个拷贝,静态变量可被该类的所有对象共享访问。还有,静态变量即使在它所属于的函数执行完后还是保留他们的值,这意味着:静态变量在整个程序内一直保留着它的值。,静态变量必须在其类体内声明,但不能在类体内初始化,只能在成员函数或类定义之外(类体外)被初始化。静态变量的声明和初始化,举例:class SExample public:static int svar;/静态变量声明 int SExample:svar=0;/静态变量初始化,在类的成员函数中可以直接访问该类的静态变量而不

43、必使用成员访问操作符:SExample:cout()svar=svar+1;cout”Now,The total is:”svar;但是,在非成员函数中我们必须以以下两种方式之一访问静态变量:,a.可以使用成员访问操作符:int SExample:svar=0;int main()SExample s1;s1.svar=1;b.因为类静态变量只有一个拷贝,所以不一定要通过对象或指针来访问,访问静态变量的另一种方法是用被类名限定修饰的名字直接访问它:int SExample:svar=0;int main()SExample:svar=1;当不通过类的成员访问操作符访问静态变量时,必须指定类名以

44、及紧跟其后的域操作符“:”。,静态函数,静态函数的声明就是在类体中的函数声明前加上关键字static。因为静态成员在对象创建之前就已经存在了,所以,静态函数只能访问静态变量,不能够访问非静态变量。静态函数声明举例:class SExample public:static int svar;static void display()/静态函数声明 coutThe static variable is:svar;int SExample:svar=0;,与静态变量同理,也有两种方式访问静态函数。a.可以用成员访问操作符点“.”和箭头“-”,为一个类对象或指向类对象的指针调用静态函数。b.也可以用类

45、限定修饰名直接访问或调用静态函数,而无需声明类对象。举例:SExample:display();/访问方式a SExample s;s.display();/访问方式b,6.静态成员(Static Members),静态数据成员 在类作用域中声明,在类定义作用域中定义(一般是在main函数启动之前定义),每个该类对象都共享描述任何对象的共性状态 在多文件程序结构中,一般放在类的实现编译单元中,例如:class Student string name;public:static int num;void set(string/访问静态成员,静态成员函数,调用时,不捆绑对象,所以,不能直接操作对象

46、和其成员,若需访问该类对象,必须以参数传递之.静态成员函数一般设计为公有的,以访问私有静态数据成员为目的.调用方式是以类名加域操作符:后跟静态成员函数,例如:class Student static int num;/静态私有成员/.public:/.static void showNum()coutnum“n”;/访问静态私有成员;int Student:num=0;/静态数据成员初始化int main()Student s;s.showNum();/可行,但非标准 Student:showNum();/静态成员函数调用,友元函数,类中私有和保护的成员在类外不能被访问。,友元函数是一种定义在

47、类外部的普通函数,其特点是能够访问类中私有成员和保护成员,即类的访问权限的限制对其不起作用。,友元函数需要在类体内进行说明,在前面加上关键字friend。一般格式为:friend FuncName();,friend float Volume(A,关键字,返回值类型,函数名,函数参数,友元函数不是成员函数,用法也与普通的函数完全一致,只不过它能访问类中所有的数据。友元函数破坏了类的封装性和隐蔽性,使得非成员函数可以访问类的私有成员。,一个类的友元可以自由地用该类中的所有成员。,class Afloat x,y;public:A(float a,float b)x=a;y=b;float Sum

48、()return x+y;friend float Sum(A,友元函数,成员函数,友元函数的调用,直接调用,成员函数的调用,利用对象名调用,友元函数只能用对象名引用类中的数据。,私有数据,有关友元函数的使用,说明如下:,友元函数不是类的成员函数,友元函数近似于普通的函数,它不带有this指针,因此必须将对象名或对象的引用作为友元函数的参数,这样才能访问到对象的成员。,友元函数与一般函数的不同点在于:友元函数必须在类的定义中说明,其函数体可在类内定义,也可在类外定义;它可以访问该类中的所有成员(公有的、私有的和保护的),而一般函数只能访问类中的公有成员。,class Afloat x,y;pu

49、blic:A(float a,float b)x=a;y=b;float Getx()return x;float Gety()return y;float Sum()return x+y;friend float Sum(A,成员函数,友元函数,可以直接调用类中私有成员,普通函数,必须通过公有函数访问私有成员,对象调用成员函数,调用友元函数,调用一般函数,友元函数,友元函数不受类中访问权限关键字的限制,可以把它放在类的私有部分,放在类的公有部分或放在类的保护部分,其作用都是一样的。换言之,在类中对友元函数指定访问权限是不起作用的。,友元函数的作用域与一般函数的作用域相同。,谨慎使用友元函数通

50、常使用友元函数来取对象中的数据成员值,而不修改对象中的成员值,则肯定是安全的。,大多数情况是友元函数是某个类的成员函数,即A类中的某个成员函数是B类中的友元函数,这个成员函数可以直接访问B类中的私有数据。这就实现了类与类之间的沟通。,注意:一个类的成员函数作为另一个类的友元函数时,应先定义友元函数所在的类。,class A.void fun(B,class B.friend void fun(B,既是类A的成员函数,又是类B的友元函数,class B;/先定义类A,则首先对类B作引用性说明class A./类A的成员定义 public:void fun(B/定义友元函数;void A:fun(

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号