C++面向对象程序设计第六章数据共享和成员特性陈春丽CCL@cugb.edu.cn第六章数据共享和成员特性•6.1this指针•6.2类的友元•6.3类的静态成员•6.4const成员6.1this指针•隐含于每一个类的成员函数中的特殊指针•识别成员函数当前操作的对象–类的每个非静态成员函数都含有一个指向当前对象的指针,即this指针–类的非静态成员函数中访问数据成员时,隐含形式是“this-数据成员名”this指针的使用classPoint{public:Point(intx=0,inty=0){xPos=x;yPos=y;}voidadd(Pointtwo){xPos+=two.xPos;yPos+=two.yPos;}voidprint(){coutxPos“,“yPos;}private:intxPos,yPos;};//xPos等价于this-xPos//yPos等价于this-yPosvoidmain(){CPointpt(1,2),pt2(3,4);pt.add(pt2);pt.print();}pt.add(pt2);add(&pt,pt2);voidadd(Point*this,Pointtwo)this-xPos+=two.xPos;6.2类的友元•友元是C++提供的一种破坏数据封装和数据隐藏的机制–外界只能访问类的public成员,通过friend修饰符,将一个模块声明为另一个模块的友元,则该友元能够引用到另一个模块中隐藏的信息–可以使用友元函数和友元类–为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元友元函数•友元函数是在类声明中说明的非成员函数,由关键字friend修饰,该友元函数体中能够通过对象名访问private和protected成员–作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择–访问对象中的成员必须通过对象名例:计算两点距离(不用友元函数)#includeiostream#includecmathusingnamespacestd;classPoint{public:Point(intx=0,inty=0){xPos=x;yPos=y;}intgetX(){returnxPos;}intgetY(){returnyPos;}private:intxPos,yPos;};doubleDistance(Point&a,Point&b){doubledx=a.getX()-b.getX();doubledy=a.getY()-b.getY();returnsqrt(dx*dx+dy*dy);}intmain(){Pointp1(3.0,5.0),p2(4.0,6.0);doubled=Distance(p1,p2);coutThedistanceisdendl;}例:使用友元函数计算两点距离classPoint{public:……frienddoubleDistance(Point&a,Point&b);private:intxPos,yPos;};doubleDistance(Point&a,Point&b){doubledx=a.xPos-b.xPos;doubledy=a.yPos-b.yPos;returnsqrt(dx*dx+dy*dy);}intmain(){……}友元类•若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员•声明语法:将友元类名在另一个类中使用friend修饰说明•友元关系是单向的–若声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据classA{friendclassB;public:voidDisplay(){coutxendl;}private:intx;}classB{public:voidSet(inti){a.x=i;}voidDisplay();{a.Display();}private:Aa;};6.3类的静态成员•静态成员:解决同一个类的不同对象之间数据和函数的共享–例如:雇员总数这个值为雇员类的所有对象所共享–静态数据成员•用关键字static声明•该类的所有对象维护该成员的同一个拷贝•必须在类外初始化,用(::)来指明所属的类。例:具有静态数据成员的Point类classPoint{public:Point(intx=0,inty=0){xPos=x;yPos=y;countP++;}……voidgetC(){coutObjectid=countPendl;}private:intxPos,yPos;staticintcountP;};intPoint::countP=0;voidmain(){PointA(4,5),B(3,2);coutPointA,A.getX(),A.getY();A.getC();coutPointB,B.getX(),B.getY();B.getC();}程序的运行结果为:PointA,4,5Objectid=1PointB,3,2Objectid=2•静态成员函数–静态成员函数是专门引用属于该类的静态数据成员或静态成员函数的函数•例如:定义了静态数据成员:雇员总数,但是该成员为私有,必须定义公有函数成员来实现雇员总数加一、输出值等功能–类外代码可以使用类名和作用域操作符来调用静态成员函数静态成员函数举例#includeiostreamusingnamespacestd;classApplication{public:staticvoidf();staticvoidg();private:staticintglobal;};intApplication::global=0;voidApplication::f(){global=5;}voidApplication::g(){coutglobalendl;}intmain(){Application::f();Application::g();return0;}classA{public:staticvoidf(Aa);private:intx;};voidA::f(Aa){coutx;//对x的引用是错误的couta.x;//正确}静态成员函数举例:访问非静态数据成员必须通过参数传递方式得到对象名,然后通过对象名访问具有静态数据、函数成员的Point类classPoint{public:Point(intx=0,inty=0){xPos=x;yPos=y;countP++;}……staticvoidgetC(){cout“id=countPendl;}private:intxPos,yPos;staticintcountP;};intPoint::countP=0;intmain()//主函数实现{PointA(4,5);//声明对象AA.getC();//输出对象号,对象名引用Point::getC();//输出对象号,类名引用}6.4const成员•常类型的对象必须进行初始化,而且不能被更新–常引用:被引用的对象不能被更新。•const类型说明符&引用名–常对象:该对象的数据成员值在对象的整个生存期间内不能被改变。即必须进行初始化,且不能被更新•类名const对象名例:常引用作形参#includeiostream.hvoiddisplay(constdouble&r);intmain(){doubled(9.5);display(d);return0;}voiddisplay(constdouble&r)//常引用作形参,在函数中不能更新r所引用的对象。{coutrendl;}常对象举例classA{public:A(inti,intj){x=i;y=j;}...private:intx,y;};Aconsta(3,4);//a是常对象,不能被更新用const修饰的对象成员•常成员函数:使用const关键字说明的函数–常成员函数不更新对象的数据成员–只能调用const常成员函数–常成员函数说明格式:类型说明符函数名(参数表)const;这里,const是函数类型的一个组成部分,因此在实现部分也要带const关键字。–const关键字可以被用于参与对重载函数的区分•如voidprint();和voidprint()const;重载•常数据成员–使用const说明的数据成员例:常成员函数举例#includeiostreamusingnamespacestd;classR{public:R(intr1,intr2){R1=r1;R2=r2;}voidprint();voidprint()const;private:intR1,R2;};voidR::print(){coutR1:R2endl;}voidR::print()const{coutR1;R2endl;}intmain(){Ra(5,4);a.print();//调用voidprint()constRb(20,52);b.print();//调用voidprint()const}例:常数据成员举例#includeiostreamusingnamespacestd;classA{public:A(inti);voidprint();constint&r;private:constinta;staticconstintb;};constintA::b=10;A::A(inti):a(i),r(a){}voidA::print(){couta:b:rendl;}intmain(){/*建立对象a和b,并以100和0作为初值,分别调用构造函数,通过构造函数的初始化列表给对象的常数据成员赋初值*/Aa1(100),a2(0);a1.print();a2.print();}