




已阅读5页,还剩107页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第三章 函数、类与对象,第一节 C+的函数,1.函数原型,函数原型提供函数与编译器的界面,它告诉编译器: (1)函数返回值的类型 (2)函数参数个数和类型,函数原型的一般语法形式为: 返回类型 函数名(参数表);,例如: #include “iostream.h” int maxinum(int num1,int num2); main() int max,n1,n2; cinn1n2; max=maxinum(n1,n2);,coutn2)?n1:n2; return max; ,说明:,(1)在程序中,要求一个函数的原型出现在该函数的调用语句之前。但当一个函数的定义在前,而对它的调用在后时,则不必给出原型。,(2)函数原型的参数表中可不包含参数的名字,而只包含它们的类型。 int maxinum(int,int);,(3)注意函数说明部分和函数原型的区别:参数,分号,(4)C+的参数说明必须放在函数名后的括号内,不可放在函数说明部分与函数体之间。,(5)主函数main()不必进行原型说明。,(6)原型中没有指出返回值的函数,C+默认该函数的返回类型是int。,(7)注意C和C+的区别: int f(); C中:参数信息没有给出 C+中:表示不带任何参数,与int f(void);等价,因为有了原型,使C+容易表达函数重载。,2.内联函数(inline),C+新增加的一个特性,以提高程序执行的速度。,调用一个函数: (1)记录当前程序地址 (2)将参数拷贝到堆栈中 (3)转到存储器中记录的该函数地址 (4)执行函数,将返回值存储在一寄存器中 (5)离开该函数回到以前程序地址,C+处理对象时通过调用对象的公有成员函数来进行,函数调用比直接访问对象成员耗费更多的运行时间。,执行一个inline函数的方式是直接将该函数的程序码放入当初调用该inline函数的程序中。,例如: #include “iostream.h” #include “conio.h” inline double add (double x,double y)return (x+y); void main() cout“2+2 is:”add(2.0,2.0)endl; cout“2.2+3.134 is:”add(2.2,3.134)endl; cout“13.13+3.234 is:”add(13.13,3.234)endl; ,经编译器编译后可视同: void main() cout“2+2 is:”2.0+2.0endl; cout“2.2+3.134 is:”2.2+3.134endl; cout“13.13+3.234 is:”13.13+3.234endl; ,欲将一函数设定为inline函数,则必须完成以下两项工作: (1)在函数定义前加上关键字inline (2)该函数的定义必须在第一次被调用前出现,注意:inline函数不是宏命令 #define square(x) (x)*(x) 调用时: int x=2; square(+x); 编译器解释:(+x)*(+x),宏是属于文字替换,而inline函数是属于程序码上的替代,但观念上还是属于一般函数的用法。 inline double square(double x) return (x*x);,因此可以说inline函数的使用要比宏来的稳定可靠多了。但通常只有较短的函数才定义为inline函数。,注意的几点: (1)内联函数必须在使用之前声明或定义。,#include int add(int a, int b); int main() int x=add(1,3); coutxendl; return 0; inline int add(int x, int y) return x+y; ,#include inline int add(int x, int y) return x+y; int main() int x=add(1,3); coutxendl; return 0; ,(2)限制内联函数的大小。一般情况下,应控制在5行以内。,(3)内联函数的函数体内不能含有复杂的结构控制语句,如:switch和while,如果内联函数的函数体内有这些语句,则编译将该函数视同普通函数那样产生函数调用代码。,(4)递归函数不能被用来作为内联函数。,(5)若程序中有关键字register,则编译程序将忽略inline。,3.带缺省参数的函数,C+允许在定义函数时给其中的某个或某些形式参数指定默认值,这样,当发生函数调用时,如果省略了对应位置上的实参的值时,则在执行被调函数时,以该形参的默认值进行运算。,#include void sum(int num=10) int i,s=0; for(i=1;i=num;i+) s=s+i; cout“sum is “s“n“; ,void main() sum(100); sum(); ,注意事项:,(1)默认参数一般在函数说明中提供。如果程序中既有函数的说明又有函数的定义时,则定义函数时不允许再定义参数的默认值。如果程序中只有函数的定义,而没有说明函数,则默认参数才可出现在函数定义中。,void point(int x=10,y=20); void main() void point (int x, int y) coutxendl; coutyendl; ,(2)默认参数的顺序:如果一个函数中有多个默认参数时,则形参分布中,默认参数应从右至左逐渐定义。如: void myfunc(int a=1,float b,long c=20); /错误 void myfunc(int a,float b=2.1,long c=30); /正确,(3)缺省参数可以是常数,也可以是全局变量,甚至可以是一个函数调用,但决不能是一个局部变量。如: int a=1; int fun(int); int g(int x=fun(a);,4.函数重载,函数重载是指一个函数可以和同一作用域中的其他函数具有相同的名字,但这些同名函数的参数类型、参数个数、返回值、函数功能可以完全不同。,#include void whatitis(int i) cout“this is an integer:“ iendl; void whatitis(char c) cout“this is a string:“ cendl; ,main() int i=1; char c=“abcdef“; whatitis(i); whatitis(c); ,注意事项:,(1)重载函数间不能只是函数的返回值不同,应至少在形参的个数、参数类型或参数顺序上有所不同。,void myfun(int i) int myfun(int i) /这种重载是错误的。,(2)应使所有的重载函数的功能相同。如果让重载函数完成不同的功能,会破坏程序的可读性。,(3)用 typedef 定义的类型是一个已有类型的别名,而不是建立新的类型。,typedef int INT; void humbug(int x); void humbug(INT y); /error,(4)重载函数的使用要适度。,5.指向函数的指针,一个函数在内存中的起始地址就是该函数的指针。 在C+中,函数的名称就代表了该函数的指针。 指向函数的指针变量的一般定义形式为: 返回值类型 ( *指针变量名 )( 参数表 );,#include “iostream.h“ int max(int x,int y) int z; if(xy) z=x; else z=y; return(z); ,void main() int (*p)(int,int); int a,b,c; p=max; cinab; c=p(a,b); coutc; ,说明: (1)一个函数不能赋给一个不一致的函数指针。 例: int * fn2(char x, char y); int (*fp1) (char a, char b); fp1=fn2; / error,(2)在函数指针变量赋值时,只须给出函数名,不能带参数, 因为只是传递函数的地址。 例: int (*fp) (int s); int fn(int a); fp=fn(3); / error,通过指针调用所指向的函数: C中: (*p)(a,b); C+中: p(a,b);,(3)函数指针与其他数据类型的指针尽管都是地址,但在类型上有很大差别,两类指针之间不允许互相赋值。 例: int * ip; void (*fp1) (char a, char b); fp1=ip; / error ip=fp1; / error,(4)对指向函数的指针做象p+n, p+, p-等算数运算是无意义的。,第二节 定义类,1.类的定义,类定义的一般形式为: class 类名 private: 数据成员或成员函数 protected: 数据成员或成员函数 public: 数据成员或成员函数 ; ,class Tdate private: int month; int day; int year; public: void Set(int, int, int); int IsLeapYear(); void Print(); ;,类的成员:数据成员和成员函数,数据封装:有条件地限制类中的成员被使用的状况。,说明: (1)private、protected和public可以按任意顺序出现任意次。,(2)数据成员可以是任何数据类型,但是不能用auto、register或extern进行说明。,(3)不能在类的声明中给数据成员赋值,C+规定,只有在类的对象定义之后才能给数据成员赋初值。,(4)不要忘了在类定义的第二个大括号“”之后加上一个分号。,2.类的实现,类的实现是指成员函数的实现。有三种方式:,(1)类的定义和实现在同一个文件中,且都在类定义中完成;例1,(2)类的定义和实现在同一个文件中,函数的实现放在类外完成;,(3)类的定义和实现在不同文件中。,第一种方式是在类声明中只给出成员函数的原型,而成员函数体在类的外部定义。这种成员函数定义的一般形式是: 返回类型 类名:函数名(参数表) 函数体 详见例子,class Tdate private: int month; int day; int year; public: void Set(int m, int d, int y) month=m; day=d; year=y; int IsLeapYear() return(year%4=0 返回,class Tdate private: int month; int day; int year; public: void Set(int m, int d, int y); int IsLeapYear() ; void Print() ; ;,void Tdate:Set(int m, int d, int y) month=m; day=d; year=y; int Tdate:IsLeapYear() return(year%4=0 ,从这个例子可以看出,虽然函数Set(int, int) 在类外部定义,但它们属于类Tdate的成员函数,它们可以直接使用类Tdate中的数据成员month,day和year。,说明:,(1)在所定义的成员函数名之前应缀上类名,在类名和函数名之间应加上分隔符“:”,(2)在定义成员函数时,对函数所带的参数,不但要说明它的类型,还要指出其参数名。,(3)在定义成员函数时,其返回类型一定要与函数原型中声明的返回类型匹配。,成员函数的第二种定义方式是:将成员函数定义在类的内部,即定义为内置函数。在C+中,可以用下面两种格式定义类的内置函数:,(1)隐式定义:所谓内置函数的隐式定义,就是直接将函数定义在类内部。,(2)显式定义 在定义内置函数时,为了书写清晰,仍将它放在类定义体外。但为了使它仍然起内置函数的作用,在函数定义前冠以关键字“inline“,以此显式地说明这是一个内置函数。,inline void Tdate:Set(int m, int d, int y) month=m; day=d; year=y; ,例如:定义一个线性表类,#define elem char const int DefautListSize=100; class alist private: int maxSize, listSize; elem *listArray; public: alist(int size=DefaultListSize); alist(); void create(int); void insert(const elem,alist:alist(int size) maxSize=size; listSize=0; listArray=new elemmaxSize; ,alist:alist( ) delete listArray;,void alist: create(int n) listSize=n; for (int k=1;klistArrayk; ,void alist: insert(const elemj-) listArrayj+1=listArrayj; listArrayi=x; listSize+; ,void alist: delete(int i) int j; if (ilistSize)|(i0) cout(“error”); else for(j=i+1; j=listSize;j+) listArrayj-1=listArrayj; listSize-; ,习题: 设计一个链表类,能完成常见的初始化、建立链表、插入、删除、定位以及输出运算。,3.类的作用域,类是实现封装的工具,封装是通过public和private与成员函数实现的。private的成员构成类的内部状态,public的成员则构成与外界通信的接口,通过public的成员函数来使用private的数据成员,从而在C+中实现了封装。,类外不可见: 私有数据 私有函数原型 私有函数和公有函数的实现,类外可见: 公有数据 公有函数原型,4.对象的定义,对象是类的实例,定义对象的一般格式为: 类名 变量名表; 或 类名 对象名;,例:class Tdate private: int month; int day; int year; public: void Set(int m, int d, int y); int IsLeapYear() ; void Print() ; ; Tdate date,classDate,sleepDate; Tdate date1;,类是抽象的概念,而对象是具体的,类只是一种数据类型,而对象是属于该类(数据类型)的一个变量,占用了各自的存储单元,每个对象各自具有了该类的一套数据成员(静态成员除外),而所有成员函数是所有对象共有的。每个对象的函数成员都通过指针指向同一个代码空间。,(1)访问对象的成员包括读写对象的数据成员和调用它的成员函数,其访问格式是: 对象名.公有数据 对象名.公有成员函数名(实参表),例: date1.set(10, 22, 1980);,(2)通过说明一个指向对象的指针来访问公有成员函数,其访问格式是: 指向对象的指针-公有的成员函数名(实参表) 指向对象的指针-公有数据,5.访问对象成员,例: Tdate * p=,6.结构、联合和类,在C+中,存在三种类类型:类、结构和联合,它们分别使用三个关键字来声明和定义类:class、struct和union。,(1)在C+中,结构与类的唯一区别是: 缺省时,结构的所有成员是公有的 类的所有成员是私有的,(2)在C+中,联合也是一种类,但联合的所有成员只能为公有成员,关键字private和protected不能用于联合。,说明:,第三节 构造函数与析构函数,1.构造函数,构造函数(Constructor)定义了创建对象的方法,提供了初始化对象的一种简便手段。 构造函数的说明格式为: ();,例: class circle private: int center_x, center_y; double radius; public: circle(int x, int y, double r) radius=r; center_x=x; center_y=y; ; circle c1(0,1,5);,(4)在C+中,给对象的数据成员初始化的方法就是利用构造函数。,(5)C+规定,每个类必须有一个构造函数。如果在类中没有显式定义构造函数时,则C+编译系统在编译时为该类提供一个默认的构造函数,该默认构造函数是个无参函数,它仅负责创建对象,而不做任何初始化工作。,(2)构造函数既可在类外定义,也可作为内联函数在类内定义,也允许重载。,(3)构造函数既可定义成有参函数,也可义成无参函数,要根据问题的需要来定。构造函数也可以有缺省参数,在使用时要防止二义性。,说明: (1)构造函数与类同名,且没有返回值类型。,class circle private: int center_x, center_y; double radius; public: circle(int x, int y, double r) radius=r; center_x=x; center_y=y; circle(double r) radius=r; center_x=0; center_y=0; ;,2.析构函数,析构函数的定义方式为: 类名() 函数体 ,作用:用于执行一些清理任务。如释放分配给对 象的内存空间。,class circle private: int center_x, center_y; double radius; public: circle(int x, int y, double r); circle() cout“Destructor is active”; ;,(4)如果程序员在定义类时,没有为类提供析构函数,则系统会自动创建一个默认的析构函数,其形式为: 类名() ,(2)没有返回值,没有参数,不能随意调用,也没有重载,只是在类对象生命期结束时,系统自动调用。,(3)在一个类中只能有一个析构函数。,说明: (1)析构函数与类同名,但它前面必须加上()。,(6)对象被析构的顺序与对象建立时的顺序正好相反。即最后构造的对象先被析构。,(5)对于一个简单的类来说,大多可以直接使用系统提供的默认析构函数。但是,如果在类的对象中分配有动态内存(如:用new申请分配的内容)时,就必须为该类提供适当的析构函数,完成清理工作。,include class A public: A( ) cout“In class A.n”; A( ) cout“Destructing class A.n”; ; class B public: B( ) cout“In class B.n”; B( ) cout“Destructing class B.n”; ; void main() A a1,a2; B b1; ,如果一个类对象是另一个类的数据成员时,则各对象的构造函数和析构函数的调用顺序是怎样的?,include class Student public: Student() cout“constructing student.n”; semesHours=100; gpa=3.5; Student() cout“destructing student.n”; private: int semesHours; float gpa; ;,class Teacher public: Teacher() cout“constructing teacher.n”; Teacher() cout“destructing teacher.n”; ;,class TutorPair public: TutorPair() cout“constructing tutorpair.n”; noMeetings=0; TutorPair() cout“destructing tutorpair.n”; private: Student student; Teacher teacher; int noMeetings; ;,void main() TutorPair tp; cout“back in main.n”; ,运行结果: constructing student. constructing teacher. constructing tutorpair. back in main. destructing tutorpair. destructing teacher. destructing student.,总结:,(1)功能,构造函数便是对象用来设定本身起始值的函数;析构函数与构造函数对应,其作用是用来释放新定义一个对象时,由构造函数向系统所要求的存储空间。,(2)工作过程:自动调用,(3)使用说明,i. 构造函数和析构函数的函数名必须与该类同名,析构函数名前方还需要加一个号。,ii. 构造函数和析构函数无返回值,不可说明返回值类型,iii. 构造函数可带参数,可以重载;析构函数不可以有任何参数,一个类只允许有一个唯一的析构函数,不可重载。,iv. 当一个类已经定义好后,以后只要以该类去定义一对象,则构造函数就会自动被调用(由编译器);当对象离开其有效范围时,便会自动调用析构函数。,v. 构造函数不可显示调用,析构函数可显示调用。,vi. 构造函数和析构函数均可系统缺省。,3.带参数的构造函数与重载构造函数,与一般成员函数一样,C+允许重载构造函数。,#include class Tdate private: int month; int day; int year; public: Tdate(); Tdate(int d); Tdate(int m, int d); /Tdate(int m, int d=12); Tdate(int m, int d, int y); ;,Tdate:Tdate() month=4; day=15; year=1995; coutmonth“/”day“/”yearendl; Tdate:Tdate(int d) month=4; day=d; year=1996; coutmonth“/”day“/”yearendl; Tdate:Tdate(int m, int d) month=m; day=d; year=1997; coutmonth“/”day“/”yearendl; ,Tdate:Tdate(int m, int d, int y) month=m; day=d; year=y; coutmonth“/”day“/”yearendl; void main() Tdate aday; Tdate bday(10); Tdate cday(2,12); Tdate dday(1,2,1998); ,重载函数使用缺省参数时,谨防二义性。,例如: class x public: x(); x(int i=0); ;,void f() x a(10); x b; /二义性 ,4.拷贝构造函数,拷贝构造函数是C+中引入的一种新的构造函数。定义一个拷贝构造函数的方式是: 类名(const 类名 &形式参数) 函数体 ,由此可看出: (1)拷贝构造函数的名称与类的名称相同,且它只有一个参数,该参数就是对该类对象的引用。 (2)拷贝构造函数的功能是用于实现对象值的拷贝,通过将一个同类对象的值拷贝给一个新对象,来完成对新对象的初始化,即用一个对象去构造另外一个对象。,例:Example是一个人员信息类。用普通构造函数生成obj1,用拷贝构造函数生成obj2。 # include # include class Example private: char *name; int num; public: Example(int i, char *str ) / 构造函数定义 name=str; num=i; ,Example(const Example /显示obj2的值 /其它程序部分 ,程序的执行结果是: 数据成员num的值=215 数据成员num的值=215,说明: (1)上例中在main函数中的语句Example obj2(obj1);在执行时,系统会自动调用类Example的拷贝构造函数完成对obj2对象的构造。 (2)如果程序员没有为所设计的类提供显式的拷贝构造函数,则系统会自动提供一个默认的拷贝构造函数,其功能是:把作为参数的对象的数据成员逐个拷贝到目标变量中,这称为成员级复制(或浅拷贝)。,(3)当创建一个新对象并用一个已知对象对其初始化时,调用拷贝构造函数。,5. 类的初始化,(1)构造函数的设计,构造函数可用两种方法把值赋给其成员,方法一:在函数体里进行成员变量的赋值,class x int a,b; public: x(int i,int j)a=i;b=j; ;,方法二:使用初始值表,class x int a,b; public: x(int i,int j):a(i),b(j) ;,说明:,(i)初始值表必须位于构造函数的参数行后与其实际定义体之间,中间用:连接。,(ii)初始值表的格式:数据成员名(数值),(iii)初始值表只能出现在构造函数的定义部分而非原型位置。,class x int a,b; public: x(int i,int j); /原型 ; x:x(int i,int j):a(i),b(j) /定义,(iv)当在一个类中使用const修饰数据成员或声明了引用类型的数据成员时,这些数据成员必须在该类的对象建立的同时进行初始化,这种初始化也是通过初始值表进行的。,例如: class A const int a; int A:A(int i,int &j):a(i),b(j) ,但这时注意,A类中的一个对象的数据成员b所引用的对象的生存期应长于这个A类型的对象的生存期,由于这个原因,j被声明为引用参数,若不使用引用类型的形参,则在构造函数返回后,j将消失,b将成为悬挂引用,即引用到了无效对象上。,(v)初始值表方式大量用于派生类构造函数的初始化和具有对象作为成员的类的构造函数的初始化。,(2)类对象的初始化,对带有构造函数的类对象的初始化有两种方法:,方法一:表达式表的方法,例如: class A A a(1); A b(a); public: A(int); A(const A,方法二:赋值表达式的方法,例如: class A A a=1; A b=a; public: A(int); A(const A,注意:对象赋值及初始化中的指针悬挂问题,class string void main() unsigned len; char *string; public: string One(“Beijing”); string(const char *str) string Two=One; len=strlen(str); string=new charlen+1; strcpy(string,str); string()string=new char8; string()delete string; ;,string Three(“abc”); string Four (“qwe”); Four=Three;,解决办法:初始化时定义拷贝构造函数;赋值时定义赋值运算符重载函数。,string:string(const string,第三节 对象数组与对象指针,1. 对象数组,(1)定义,类名 数组名大小; string str10;,(2)初始化,若类中含有用户定义的带参数的构造函数,则可通过初始值表进行赋值;或通过不带参数的构造函数和带缺省参数的构造函数给数组初始化,class point int x,y; public: point(int m,int n)x=m;y=n; point()x=y=0; ; main() point data(3,4); point more_data3; /调用default constructor point more_data3=point(1,2),point(3,4),point(5,6); /初始值相当于类类型的常量,2. 对象指针,(1)指向对象的指针变量,类型名 *指针变量名; char c, *pc; pc=,注意:与其它指针变量一样,ob的地址是用地址操作符获得的;指针加1或减1时,也是指向其基类的下一个元素。,类名 *指针变量名; string ob, *p; p=,(2)指向类的数据成员和成员函数的指针变量,说明指向数据成员的指针变量的格式: 类型说明符 类名:*指针名;,说明指向成员函数的指针变量的格式: 类型说明符 (类名:*指针名)(参数表),class A int a; public: int c; A(int i)a=i; int fun(int b) return a*c+b; ;,int A:*pc=,3. this指针,this指针是一个隐含于每一个成员函数中的特殊指针。它指向正在被该成员函数操作的对象,也就是要操作该成员函数的对象。,int string:get_length()return length; x.get_length(); 对象x调用成员函数get_length(),则函数get_length()的this指针就指向对象x,说明:,(1)this指针是一个隐含的指针,不能被显示声明,它只是一个形参,一个局部变量,它在任何一个非静态成员函数里都存在,它局部于某一对象。,(2)this指针是一个常指针,可以表示为(但不能显示声明): X *const this 因此,this指针不能被修改和赋值。,(3)不管在类外还是类内访问类的成员都需要 使用 对象.成员 或 指向对象的指针成员 类内直接访问成员的方式实际上就是 this成员 的方式。,(4)this指针主要用于运算符重载和自引用以及将成员函数的返回值设定为所属类类型等场合。,例1:在一个双向链表中插入一个链 class dlink dlink *pre; dlink *suc; public: void append(dlink *p); ; void dlink:append(dlink *p) psuc=suc; ppre=this; /this的显示使用 sucpre=p; suc=p; ,例2:设计一个复数类,可完成对复数进行加减 运算并输出的功能。 #include “iostream.h” #include “stdio.h” #include “conio.h” class complex double re,im; public: complex(double r=0,double i=0); complex(const complex ,complex:complex(double r,double i) re=r;im=i; complex:complex(const complex,complex ,void main() complex ca(10,20); complex cb(-5,-10); cout“ca=“; ca.show(); cout“cb=“ cb.show(); complex cadd=ca.add(cb); complex csub=ca.sub(cb); /注意结果 cout“ca+cb=“ cadd.show(); cout“ca-cb=” csub.show(); ,(5)可以使用const说明符将this声明为指向常量的常指针(常成员函数),例如: #include class S int a; public: int g()return +a; /g的this是常指针 int h()const /h的this是指向常量的常指针 return +a; /错误 ;,h()后跟一个const,说明此时的this类型是: const S *const this h()称为const成员函数,第五节 静态成员,1.静态数据成员,在一个类中,若将一个数据成员说明为static,这种成员称为静态数据成员。与一般的数据成员不同,无论建立多少个类的对象,都只有一个静态数据的拷贝。,class x static int i; int s; ; x a1,a2,a3,a4;,例如: #include class Student static int count; int StudentNo; public: Student() count+;/设计不完善 StudentNo=count; void print() cout“student=“StudentNo; cout”count=”countendl; ; int Student:count0;,main() Student Studentl; Studentl.print(); Student Student2; Studentl.print(); Student2.print(); Student Student3; Studentl.print(); Student2.print(); Student3.print(); Student Student4; Studentl.print(); Student2.print(); Student3.print(); Student4.print(); return 0;,说明:,(1)静态数据成员属于类(准确地说,是属于类中一个对象集合),而不像普通数据成员那样属于某一对象,因此可以使用“类名:访问静态的数据成员。例如上面例子中的 Student:count。,(2)静态数据成员不能在类中进行初始化,因为在类中不给它分配内存空间,必须在类外的其它地方为它提供定义。一般在main()开始之前,类的声明之后的特殊地带为它提供定义和初始化。缺省时,静态成员被初始化为零。,(3)静态数据成员与静态变量一样,是在编译时创建并初始化。它在该类的任何对象被建立之前就存在,它可以在程序内部不依赖于任何对象被访问。,例如: #include class myclass public: static int i; ; int myclass:i;,main() myclass:i200; ,(4)C+支持静态数据成员的个主要原因是可以不必使用全局变量。依赖于全局变量的类几乎都是违反面向对象程序设计的封装原理的。静态数据成员的主要用途是定义类的各个对象所公用的数据,如统计总数、平均数等。,2.静态成员函数,在类定义中,前面有static说明的成员函数称为静态成员函数。静态成员函数属于整个类,是该类所有对象共享的成员函数,而不属于类中的某个对象。,include class small_cat double weight; static double total_weight; static double total_number; public: small_cat(double w) weightw; total_weight+w;,total_number+; void display() coutweight“n”; static void total_disp() couttotal_number; couttotal_weightendl; ;,double small_cat:total_weight0; double small_cat:total_number=0; int main() small_cat wl(1.8),w2(1.6),w3(1.5); w1.display(); w2.display(); w3.display(); small_cat:total_disp(); return 0; ,说明:,(1)静态成员函数可以定义成内嵌的,也可以在类外定义,在类外定义时,不要用static前缀。,(2)编译系统将静态成员函数限定为内部连接,也就是说,与现行文件相连接的其它文件中的同名函数不会与该函数发生冲突,维护了该函数使用的安全性,这是使用静态成员函数的一个原因。,(3)使用静态成员函数的另一个原因是,可以用它在建立任何对象之前处理静态数据成员,这是普通成员函数不能实现的功能。,(4)在一般的成员函数中都隐含有一个this指针,用来指向对象自身,而在静态成员函数中是没有this指针的,因为它不与特定的对象相联系,调用时使用如下格式较好: 类名:静态成员函数名() 当然,也可通过对象去调用: 对象名.静态成员函数名(),(5)一般而言,静态成员函数不访问类中的非静态成员。若确实需要,静态成员函数只能通过对象名(或指向对象的指针)访问该对象的非静态成员。,例如: class x int member_int; public: static void func(int i,x*p); ; void g() x obj; x:func(1, ,第六节 友元,在不放弃私有数据安全性的情况下,使得类外部的函数或类能够访问类中的私有成员,在C+中就用友元作为实现这个要求的辅助手段。友元是一扇通向私有成员的后门。,友元既可以是不属于任何类的一般函数,也可以是另一个类的成员函数,还可以是整个的一个类(这样,这个类中的所有成员函数都可以成为友元函数)。,1.友元函数,友元函数不是当前类的成员函数,而是独立于当前类的外部函数,但它可以访问该类的对象的所有成员,包括私有成员和公有成员。,在类定义中声明友元函数时,需在其函数名前加上关键字friend。此声明可以放在公有部分,也可以放在私有部分。友元函数可以定义在类内部,也可以定义在类的外部。,例如: #include #include class girl char *name; int age; public: girl(char *n,int d) name=new charstrlen(n)+1; strcpy(name,n); aged; friend void disp(girl x );/声明 girl()delete name; ;,void disp(girl x) /定义 x.ageendl; void main() girl e(”Chen”,18); disp(e); /调用 ,说明:,(1)友元函数虽然可以访问类对象的私有成员,但它毕竟不是成员函数。因此,在类的外部定义友元函数时,不必像成员函数那样,在函数名前加上“类名:”。,(2)友元函数一般带有一个该类的入口参数。因为友元函数不是类的成员,所以它不能直接引用对象成员的名字,也不能通过this指针引用对象的成员,它必须通过作为入口参数传递进来的对象名或对象指针来引用该对象的成员。,(3)当一个函数需要访问多个类时,友元函数非常有用,普通的成员函数只能访问其所属的类,但是多个类的友元函数能够访问相应的所有类的数据。,(4)友元函数通过直接访问对象的私有成员,提高了程序运行的效率。在某些情况下,如运算符被重载时,需要用到友元。但是友元函数破坏了数据的隐蔽性,降低了程序的可维护性,这与面向对象的程序设计思想是背道而驰的,因此使用友元函数应谨慎。,2.友元成员函数,一个类的成员函数也可以作为另一个类的友元,这种成员函数不仅可以访问自己所在类对象中的私有成员和公有成员,还可以访问friend声明语句所在类对象中的私有成员和公有成员。,class boy public: void member_fun(); class girl friend void boy:member_fun(); ;,例如: include include class girl; class boy char *name; int age; public: boy(char *n,int d) namenew charstrlen(n)+1; strcpy(name,n); aged; void disp(girl&); boy() delete name ;,class girl char *name; i
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 大班保健知识培训心得课件
- 大河马的口罩课件
- 2024年池州市石台县级公立医院招聘真题
- 大松树养护知识培训课件
- 家庭与社区发展协议范本
- 2024年重庆松山医院招聘真题
- 2024年永州市宁远县县直机关事业单位选调真题
- 地铁内丢东西应急预案流程(3篇)
- 1. 近五年新高考I卷AB篇分析及教学建议
- 驾驶员应急预案内容(3篇)
- 湖北省圆创高中名校联盟2026届高三第一次联合测评 语文试卷(含答案)
- 巡察整改工作课件模板
- 2025年事业单位工勤技能-河南-河南农机驾驶维修工一级(高级技师)历年参考题库含答案解析(5套)
- 医务人员职业道德准则理论试题
- 2025年幼儿园教师岗位聘任协议(含资格认证及薪酬激励)
- 成都东部集团有限公司招聘考试真题2024
- 银行收息管理办法
- 海外房产投资项目方案(3篇)
- 消防员心理健康课件
- 2024年中级注册安全工程师《安全生产技术基础》考试真题及答案
- 初中地理学科课程规划方案
评论
0/150
提交评论