C++程序设计(四)

上传人:lx****y 文档编号:243022873 上传时间:2024-09-14 格式:PPT 页数:35 大小:117.50KB
返回 下载 相关 举报
C++程序设计(四)_第1页
第1页 / 共35页
C++程序设计(四)_第2页
第2页 / 共35页
C++程序设计(四)_第3页
第3页 / 共35页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,C+程序设计(四),1,内容提要,友元,静态成员,this,指针,运算符重载,2,友元,类的客户只能直接存取类的公共成员。这有利于,信息隐藏,。,类的客户只能直接存取类的公共成员,类的客户如果要存取类的私有成员和保护成员,只能通过类提供的公共成员函数方式间接进行。在某些时侯,这既不方便,也不效率。,例子:矩阵和向量相乘,VectorMatrix.cpp,VectorMatrix.h,TestVM.cpp,函数,multiply,中反复调用类_,vector,和_,matrix,的成员函数,at(.)、size()、size_r()、size_c(),3,友元,在,C+,中,可以将客户定义为类的“朋友”,如果客户成为类的“朋友”,就可以直接存取类的保护成员和私有成员。类的“朋友”称为类的,友元,。,友元可以是一个普通函数、另一个类的成员函数或另外一个类。,把客户声明为类的友元的方法是在类的内部声明该客户,并在声明前加保留字,friend。,如果把普通函数声明为类的友元,友元函数仍然是普通函数,不是类的成员函数,其定义和普通函数没有区别,还应在类的外部进行,类中的存取权限控制指示符对友元函数无效,并不能限定谁可以调用该友元函数。不同之处在于类的友元函数可以直接存取类的所有成员。,4,友元,例子,把函数,multiply,改成类_,vector,和_,matrix,的友元函数参见:,VectorMatrix_friend.cpp VectorMatrix_friend.h,class A ,.,private:,friend int func( A,private: int m1;protected: int m2;,.,;,int func( A& a) ,.,a.m1 = 10;/,直接访问私有成员,a.m2 = 30; /,直接访问保护成员,5,成员函数作为友元,一个类的成员函数可以是另一个类的友元。,class student;,class teacher ,public:,void assign_grades(student,private:,int no_of_students;,student* plist100;,;,class student ,private:,teacher* pt;,int semester_hours;,float gpa;,friend void teacher:assign_grades(student,;,6,友类,整个类可以是另一个类的友元,此时称做类的,友类,。友类的成员函数可以存取该类的所有成员。,友元(包括友元函数、成员函数作为友元和友类)的引入对数据封装构成了破坏,应慎重使用。,class student;,class teacher ,public:,void assign_grades(student,void adjust_hours(student,private:,int no_of_students;,student* plist100;,;,class student ,private:,teacher* pt;,int semester_hours;,float gpa;,friend class teacher;,;,7,静态变量,在,C,语言中,可以定义静态(,static),变量,静态变量存储分配和全局变量类似,存在于全局数据区,在程序运行开始时分配并在程序运行结束后回收。对静态变量的存取受制于变量作用域的限制,静态变量仅在其作用域内部是可见的。静态变量在第一次进入其作用域时被初始化,其后再次进入其作用域时不再初始化。,在,C+,中,仍然可以使用静态变量,其定义和存取方法与,C,语言的规定相同。,.,void f() ,static int i = 0;,couti=+iendl;,.,.,void main() ,for(int x= 0; x10; +x),f();,.,8,静态成员,在,C+,中可以为类定义,静态成员,,仍然使用保留字,static,,但含义和静态变量不同。,类的静态成员可以分为:,静态数据成员,和,静态成员函数,。,为什么需要静态数据成员?在,C+,中一旦定义了一个类,可以建立该类的多个对象,但各个对象都拥有自己的数据成员,对应不同的存储空间,各个对象相互独立。换句话说,同一个类的不同对象之间无法拥有占据相同存储空间的公共数据成员。当然可以把需要共享的数据成员定义成全局变量,但破坏了类的封装特性,不利于信息隐藏。,9,获取对象个数,class student ,public:,student();,student(char*, char*,int);,student();,private:,char name20;,char id20;,int score;,;,void main() ,student a(,王二,10023009, 98 );,student b(,陈清扬,10023010, 63 );,student c(,罗小四, 85 );,.,希望时刻知道当前内存中有几个,student,类的对象?如何办?,10,全局变量,全局变量要在类的外部定义,不但类的成员函数可以改变,任何程序均可以改变,破坏了封装和信息隐藏。客户程序要负责维护该变量。,int count = 0,void main() ,student * ps;,student a(,王二,10023009, 98 );,count+;,student b(,陈清扬,10023010, 63 );,count+;,ps = new student(,罗小四,10023011, 85 );,count+,.,delete ps;,count-;,.,count-;,count-;,11,静态数据成员,静态数据成员是类的数据成员,在声明时,使用保留字,static。,如:,class A ,.,static int sm;/sm,是类,A,的静态数据成员,.,;,一个类的静态数据成员被该类的所有对象共享。对所有同类对象的同一个静态数据成员占据同一存储空间。,12,静态数据成员,class student ,public:,student(char*, char*,int);,student();,private:,char name20;,char id20;,int score;,static int count,;,;,student:student(char* pn, char* pid, int sc ) ,strcpy(name, pn );,strcpy(id, pid );,score = sc;,count+;,student:student() ,count-;,13,静态数据成员,void main() ,student a(,王二,10023009, 98 );,student b(,陈清扬,10023010, 63 );,student c(,罗小四, 85 );,.,14,静态数据成员,静态数据成员的存储分配并非在创建对象时进行,对象创建时仅为非静态数据成员分配存储。,静态数据成员的存储分配和初始化要在类的外部进行(初始化不在构造函数内进行),通常和成员函数的定义放在一起。对其初始化时应使用作用域指示符。例如:,int student:count = 0;,为一个类定义了静态数据成员,一定要记住对其进行初始化。,有关静态数据成员的存取权限和普通数据成员一致。,a.count = 1;/,错误,,count,是私有成员,15,静态数据成员,静态数据成员和类发生联系,而不是和各个对象发生联系。,可以象存取普通数据成员那样通过对象存取静态数据成员,也可以不通过对象直接存取类的静态数据成员,此时需要使用作用域指示符。例如:,student:count=10;/,前提:,count,是类的静态公有数据成员,16,静态成员函数,除了定义静态数据成员外,还可以为类定义,静态成员函数,。,静态成员函数,只能存取类的静态数据成员,,不能存取类的非静态成员。,静态成员函数可以在类的内部进行定义,也可以在类的外部进行定义,不同之处在于要在返回类型前加保留字,static。,17,静态成员函数,class student ,public:,student(char*, char*,int);,student();,static int get_count(),;,private:,char name20;,char id20;,int score;,static int count,;,;,student:student(char* pn, char* pid, int sc ) ,strcpy(name, pn );,strcpy(id, pid );,score = sc;,count+;,student:student() ,count-;,int student:get_count(),return count;,int student:get_count(),coutnameendl;,return count;,18,静态成员函数,同样,静态成员函数和类发生联系,而不是和各个对象发生联系。,可以象存取普通成员函数那样通过对象调用静态成员函数,也可以不通过对象直接调用类的静态成员函数。客户无论以那种方式调用静态成员函数都必须遵照类中对该静态成员函数指定的权限,即客户只能调用公有静态成员函数。,若客户直接调用类的静态成员函数,应使用作用域指示符。,19,静态成员函数,void main() ,student a(,王二,10023009, 98 );,student b(,陈清扬,10023010, 63 );,student c(,罗小四, 85 );,coutstudent:get_count()endl;/,正确,couta.get_count()endl; /,正确,coutb.get_count()endl; /,正确,coutc.get_count(),month = m;,this-,day = d;,this-,year = y;,TDate d1, d2;d1.Set(,&d1, 9, 27, 2003);d2.Set(,&d2, 10, 17, 2003);,23,this,指针,为什么静态成员函数不能存取类的非静态数据成员?,因为编译程序在编译静态成员函数时,并不产生,this,指针这个隐参数。如果访问了非静态数据成员,由于静态成员函数没有指向对象的,this,指针,静态成员函数不能区分是访问哪一个对象的非静态数据成员。,由于静态数据成员隶属于所有对象,被所有对象共享,因此即使没有,this,指针,静态成员函数也可以无歧义的正确存取,所以静态成员函数可以存取类的静态数据成员。,在类的成员函数内部,程序员可以直接存取,this,指针,就象存取一个被定义了的指针一样。,void TDate:Set( int m, int d, int y ) ,this-,month = m;,this-,day = d;,this-,year = y;,24,运算符重载,无论在,C,语言中还是,C+,语言中,都定义了很多运算符。如+ - * / %等等,使用起来直观方便。,实际上,计算包含运算符的表达式本质上是进行函数调用:一元运算符是有一个参数的函数,二元运算符是带两个参数的函数。,int a, b;-a,operatot-(a)a+b,operator+(a, b)a+b+10,operator+(operator+(a,b),10)a=boperator=(a,b),可以设想,,C+,编译器为我们定义了下列函数:,int operator-( int );,int operator+( int, int);int,25,运算符重载,使用运算符使得程序易读、易写。但运算符只对基本数据类型有定义,,对程序员自定义的类无效,。例如:,_,vector a,b;,a+b/,错误,_,vector a;,_matrix b;,a*b;/,错误,C+,允许程序员对运算符重载,使之适用于程序员自定义的数据类型,重载后就可以像对待基本数据类型那样对程序员自定义的数据类型使用运算符。,在,C+,中重载一个运算符有两种形式,以,普通函数方式重载,和,以成员函数方式重载,。,26,以普通函数形式重载运算符,以普通函数形式重载运算符,形式上如同定义一个普通函数,函数名称比较特殊,函数名是保留字,operator,加要重载的运算符。,返回类型,operator,运算符号(参数表);,_vector operator*( _matrix& m, _vector& v ) ,_,vector r(m.size_r(); /,存放结果,if ( m.size_c() = v.size() & v.size() != 0) ,for( int i = 0; i m.size_r(); i+ ) ,r.at(i) = 0;,for ( int j = 0; j m.size_c(); j+ ),r.at(i) += m.at(i,j) * v.at(j);,return r;,void main() ,_matrix ma(4, 3);,_vector ve(3); _vector vb = ma * ve;/,正确,_vector vx = ve * ma; /,错误 .,27,以普通函数形式重载运算符,可以把运算符重载函数声明为类的友元函数,简化对数据成员的存取。见:,TestVM_operator_overload.cppVectorMatrix_operator_overload.hVectorMatrix_operator_overload.cpp,由于+、-两个运算符有前缀和后缀的区分,前缀式重载形式和一般一元运算符没有区别,后缀式重载时提供,哑参数,(函数体内不使用的参数),哑参数的存在知识为了帮助编译程序调用正确的代码。,_matrix operator+( _matrix&,int,);/,后缀,28,以成员函数形式重载运算符,C+,中也允许以成员函数形式重载运算符,此时运算符重载函数是类的一个成员函数。,运算符以成员函数形式重载时,类本身是运算符的第一个操作数。程序员只需要在参数列表中列出其余的参数。,29,以成员函数形式重载运算符,class _vector,public:,_vector( int );,_vector( _vector,void display();,int size();,int,_vector();,_vector operator*( _matrix,private:,int sz;,int* v;,;,_vector _vector:operator*( _matrix& ma ) ,_vector r(ma.size_c();,if ( ma.size_r() = sz & sz != 0) ,for( int i = 0; i ma.size_c(); i+ ) ,r.vi = 0;,for ( int j = 0; j ,operator(),operator-*,程序员只能重载,C+,中已有的运算符,不能发明新的运算符。,operator*(int,int)/,错误,*不是,C+,的运算符,并非所有运算符都可以重载,下面的运算符不允许重载:,operator.,operator.*,32,运算符重载,运算符重载不能改变原有运算符在基本数据类型上的语义,如:,int operator+(int,int)/,不允许程序员自行定义,运算符重载不能改变运算符的参数个数。,_vector operator+(_vector, _vector, _vector) /,不允许,运算符重载不改变运算符的优先级。,_,matrix a(4, 4),b(4, 3),c(3, 4);,_matrix d = a + b * c;,33,赋值运算符重载,赋值运算符,operator=,只能以成员函数形式重载,每个类必须有赋值运算符重载函数。,赋值运算符重载函数在把一个对象赋值给另外一个对象时被调用。,_,matrix mf(2,3), mf(2,3);,mf = ma;/,调用赋值运算符重载函数,mf.operator=(ma),在定义类时,如果没有定义赋值运算符重载函数,,C+,提供,默认赋值运算符重载函数,。,默认赋值运算符重载函数的语义是逐个数据成员赋值,通常是正确的,但如果类中数据成员指向动态分配存储空间时会发生错误,道理和默认拷贝构造函数相同,此时程序员负责定义正确的赋值运算符重载函数。,赋值运算符的返回类型为什么必须是对象引用?,34,上机练习内容,C+,程序设计教程,p.347,练习15.1 、15.2、15.3,C+,程序设计教程,p.414,练习18.1、18.2、 18.3、18.4,分析程序,stash.h,和,stash.cpp,为其重载可能的运算符。,35,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 大学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!