版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第4章类和对象(二)
4.1自引用指针this
例4.1this指针的引例。#include<iostream.h>classA{public:A(intx1){x=x1;}voiddisp(){cout<<"x="<<x<<endl;}private:intx;};
main(){Aa(1),b(2);cout<<"a:";a.disp();cout<<"b:";b.disp();return0;}
a.disp()与b.disp()在存储时是同一个函数,它怎么区分是a调用还是b调用它呢?1.什么是this指针this指针是由系统在编译时自动产生的一个指向对象自身的指针。
this是一个隐含于每一个类的非静态成员函数中的特殊指针。用于指向正在操作该成员函数的对象。当一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,然后调用成员函数。成员函数存取数据成员时,由隐含的this指针引用,通常不显式地使用this指针来引用数据成员。
例4.2显示this指针的值。#include<iostream.h>classA{public:A(intx1){x=x1;}voiddisp(){cout<<"\nthis="<<this<<"whenx="<<this->x;}private:intx;};main(){Aa(1),b(2),c(3);a.disp();b.disp();c.disp();return0;}为了帮助大家更深一步了解this指针是如何在“幕后”工作的,我们再看一个例子。假设有一段程序如下:classabc{private:chara;intb;public:voidinit(charma,intmb){a=ma;b=mb;}};main(){absob;ob.init(‘x’,12);return0;}ob.init(‘x’,12);
那么C++如何使用this指针指向对象ob呢?实际上,C++在编译过程中做些了简单的工作,将上述调用init()函数的语句转换成如下形式:
init(&ob,’x’,12);换句话说,C++把类对象作为参数传递给函数(传地址)。虽然程序中的成员函数init()没有对应的形参,但程序编译时C++将其转换成以下形式:
voidinit(abc*this,charma,intmb){this->a=ma;this->b=mb;}由于函数调用时,第一个参数是按照地址传递的,因此当对象ob调用函数init()时,this指针便指向ob,于是隐式指针this保证了成员函数init()的操作对象确实是对象ob。.何时显式使用this指针?(1)当需要在一个成员函数内标识被该成员函数操作的对象时,就需要显式使用this指针。#include<iostream.h>classSample{intx,y;public:Sample(inti=0,intj=0){x=i;y=j;}voidcopy(Sample&xy);voidprint(){cout<<x<<“,”<<y<<endl;}};voidSample::copy(Sample&xy){
if(this==&xy)return;
//通过判断,避免不必要的复制*this=xy;}main(){Samplep1,p2(5,6);p1.copy(p2);p1.print();}(2)当成员函数的形参名与该类的数据成员同名时,必须用this指针来显式区分。#include<iostream.h>classsam{inta,b;public:sam(inta,intb){this->a=a;this->b=b;cout<<a<<endl;}voidprint(){cout<<"a="<<a<<""<<"b="<<b<<endl;}};main(){sams2(2,2);s2.print();return0;}this指针的另外一个作用:获取对象自身。因为this指针的值是对象自身的首地址,*this是指针所指向的对象,即当前对象。如果一个类的成员函数返回值是*this,程序就可以用这个返回值去调用另外一个成员函数。【举例】#include<iostream.h>classClassroom{public:Classroom(intn=100,doublel=8.0,doublew=6.0);Classroom&set(intn,doublel,doublew);voidprint();private: intseats; doublelength,width;};Classroom::Classroom(intn,doublel,doublew){ seats=n>0?n:100; length=l>0?l:8.0; width=w>0?w:6.0;}Classroom&Classroom::set(intn,doublel,doublew){ seats=n>0?n:100; length=l>0?l:8.0; width=w>0?w:6.0; return*this;}voidClassroom::print(){cout<<this->width<<"meterswidthand" <<this->length<<"meterslength,"<<"contains"<<this->seats<<"seats."<<endl;}main(){ Classrooma101(80,6,4); cout<<"Classrooma101is"; a101.print(); cout<<"setandprint:"<<endl; cout<<"Classrooma101is";
a101.set(90,7.0,5.0).print(); return0;}this指针是一个const指针,不能在程序中修改它和给它赋值是一个局部数据,它的作用域仅在一个对象内部在系统中隐含存在。一般不必特别地去使用它。4.2对象数组与对象指针
4.2.1对象数组
所谓对象数组是指每一数组元素都是对象的数组。定义一个一维数组的格式如下:
类名数组名[下标表达式];
例4.4对象数组的应用。
#include<iostream.h> classexam{ public: voidset_x(intn){x=n;} intget_x(){returnx;}private: intx; };
intmain(){examob[4];inti;for(i=0;i<4;i++)ob[i].set_x(i);for(i=0;i<4;i++)cout<<ob[i].get_x()<<′′;cout<<endl;return0;
}例4.5通过初始化表给对象数组赋值classexam{public:exam(){x=123;}exam(intn){x=n;}private:intx;};main(){examob1[4]={11,22,33,44};examob2[4]={33,44};examob3[4]={exam(11),exam(22)};ob3[3]=exam(44);}例4.5通过初始化表给对象数组赋值classexam{public:exam(intn,intm){x=n;y=m;}private:intx,y;};main(){examob[3][2]={exam(11,22),exam(33,44)};}4.2.2对象指针
1.用指针访问单个对象成员声明对象指针的一般语法形式为:
类名*对象指针名;如:ABC*p;当用指向对象的指针来访问对象成员时,要用“->”操作符。例4.7对象指针的使用。
#include<iostream.h>classexe{public: voidset_a(inta){x=a;} voidshow_a(){cout<<x<<endl;} private:intx;};
main(){exeob,*p;//声明类exe的对象ob和类exe的对象指针pob.set_a(2);ob.show_a();//利用对象名访问对象的成员p=&ob;//将对象ob的地址赋给对象指针pp->show_a();//利用对象指针访问对象的成员return0;}2.用对象指针访问对象数组
例如将例4.7的main()改写为: main() { exeob[2],*p; ob[0].set_a(10);ob[1].set_a(20);p=ob; p->show_a(); p++; p->show_a(); return0; }4.3向函数传递对象
本节内容中,把对象当作普通变量理解就行了4.3.1使用对象作为函数参数-------------值传递4.3.2使用对象指针作为函数参数-------地址传递4.3.3使用对象的引用作为函数参数----形参值的改变就是改变实参值
例4.11使用对象作为函数参数。#include<iostream.h>classaClass{public:aClass(intn){i=n;}voidset(intn){i=n;}intget(){returni;}private:inti;};voidsqr(aClassob){ob.set(ob.get()*ob.get());cout<<"copyofobjhasivalueof";cout<<ob.get()<<"\n";}main(){aClassobj(10);sqr(obj);cout<<"obj.iisunchangedinmain:";cout<<obj.get()<<endl;return0;}【例】对象指针作函数参数示例。
#include<iostream.h>classM{
public:M(){x=y=0;}M(inti,intj){x=i;y=j;}voidcopy(M*m);voidsetxy(inti,intj){x=i;y=j;}voidprint(){cout<<x<<“,”<<y<<endl;}private: intx,y;};形参为对象指针voidM::copy(M*m)//成员函数定义{x=m->x;y=m->y;}voidfun(Mm1,M*m2);//一般函数说明main(){
Mp(5,7),q;//定义对象q.copy(&p);fun(p,&q);p.print();q.print();} 以p对象的地址为实参voidfun(Mm1,M*m2)//一般函数定义 { m1.setxy(12,15);m2->setxy(22,25);}实参——形参形参pqm1m2
实参57005720082008过程调用中57200820085757572225过程调用后例4.12使用对象指针作为函数参数。#include<iostream.h>classaClass{public:aClass(intn){i=n;}voidset(intn){i=n;}intget(){returni;}private:inti;};voidsqr(aClass*ob){ob->set(ob->get()*ob->get());cout<<"Copyofobjhasivalueof";cout<<ob->get()<<"\n";}main(){aClassobj(10);sqr(&obj);cout<<"obj.iinmainhasbeenchanged:";cout<<obj.get()<<"\n";return0;}例4.13使用对象引用作为函数参数。#include<iostream.h>classaClass{public:aClass(intn){i=n;}voidset(intn){i=n;}intget(){returni;}private:inti;};voidsqr(aClass&ob){ob.set(ob.get()*ob.get());cout<<"Copyofobjhasivalueof";cout<<ob.get()<<"\n";}main(){aClassobj(10);
sqr(obj);cout<<"obj.iinmain()hasbeenchanged:";cout<<obj.get()<<"\n";return0;}[例]#include<iostream.h>classM{public:M(){x=y=0;}M(intI,intj){x=I;y=j;}voidcopy(M&m);voidsetxy(inti,intj){x=I;j=j;}voidprint(){cout<<x<<“,”<<y<<endl;}private: intx,y;};voidM::copy(M&m)//成员函数定义{x=m.x;y=m.y;}voidfun(Mm1,M&m2);//一般函数说明voidmain() {Mp(5,7),q;//定义对象q.copy(p);fun(p,q);p.print();q.print();} voidfun(Mm1,M&m2)//一般函数定义 {m1.setxy(12,15);m2.setxy(22,25);}实参——形参形参pqm1m2
实参570057过程调用中575757572225过程调用后4.4静态成员
4.4.1静态数据成员
在一个类中,若将一个数据成员说明为static,这种成员称为静态数据成员。与一般的数据成员不同,无论建立多少个类的对象,都只有一个静态数据的拷贝。从而实现了同一个类的不同对象之间的数据共享。定义静态数据成员的格式如下:
static数据类型
数据成员名;
例4.15静态数据成员的使用引例。#include<iostream.h>#include<string.h>classStudent{public:Student(char*name1,char*stu_no1,floatscore1);~Student();voidshow();//输出姓名、学号和成绩voidshow_count_sum_ave();//输出人数、总成绩和平均成绩private: char*name;//学生姓名 char*stu_no;//学生学号 floatscore;//学生成绩
staticintcount;//统计学生人数
staticfloatsum;//统计总成绩 staticfloatave;//统计平均成绩};Student::Student(char*name1,char*stu_no1,floatscore1){name=newchar[strlen(name1)+1];strcpy(name,name1);stu_no=newchar[strlen(stu_no1)+1];strcpy(stu_no,stu_no1); score=score1; ++count;//累加学生人数 sum=sum+score;//累加总成绩 ave=sum/count;//计算平均成绩}Student::~Student(){delete[]name;delete[]stu_no;--count;sum=sum-score;}voidStudent::show(){cout<<"\nname:"<<name;cout<<"\nstu_no:"<<stu_no;cout<<"\nscore:"<<score;}voidStudent::show_count_sum_ave(){cout<<"\ncount:"<<count;//输出静态数据成员countcout<<"\nsum:"<<sum;//输出静态数据成员sumcout<<"\nave:"<<ave;//输出静态数据成员ave}intStudent::count=0;//静态数员count初始化floatStudent::sum=0.0;//静态数员sum初始化floatStudent::ave=0.0;//静态数员ave初始化voidmain(){Studentstu1("Liming","990201",90);stu1.show();stu1.show_count_sum_ave();Studentstu2("Zhanghao","990202",85);stu2.show();stu2.show_count_sum_ave();}1、静态变量属于类,为类创建的所有对象所公用。2、类中的非静态变量,在类创建对象时,不同的对象拥有各自的变量存储空间。3、静态变量可以实现同一类中不同对象间的数据共享。有关静态成员变量的语法规定静态成员变量要用static声明。静态成员变量的初始化要在类外单独进行,而且要在对象定义之前,一般在类定义之后、main()之前初始化。初始化的格式:数据类型类名::静态数据成员名=值;如intStudent::count=0;注意:初始化时数据成员名前面不加static。静态成员变量属于类,公有的静态成员变量可以用类名::静态数成员名的方式在类外直接调用。(也可通过对象调用,私有的静态成员变量不能在类外调用。)与普通静态变量一样,在编译时创建并初始化。在该类的任何对象被建立之前就已经存在。静态成员变量实际代替了全局变量的作用。例4.16公有静态数据成员的访问。#include<iostream.h>classmyclass{public: staticinti; intgeti() { returni; }};intmyclass::i=0;main(){myclass::i=200;myclassob1,ob2;cout<<"ob1.i="<<ob1.geti()<<endl;cout<<"ob2.i="<<ob2.geti()<<endl;ob1.i=300;cout<<"ob1.i="<<ob1.geti()<<endl;cout<<"ob2.i="<<ob2.geti()<<endl;return0;}4.17静态数据成员和一般数据成员的不同。#include<iostream.h>classStudent{public:Student(){ ++count; StudentNo=count;}voidprint(){cout<<"student"<<StudentNo<<"";cout<<"count="<<count<<endl;}private: staticintcount;
intStudentNo;};intStudent::count=0;main(){Studentstudent1;student1.print();cout<<"-------"<<endl;Studentstudent2;student1.print();student2.print(); return0;}4.4.2静态成员函数
定义静态成员函数的格式如下:static返回类型静态成员函数名(参数表);与静态数据成员类似,调用公有静态成员函数的一般格式有如下几种:
类名::静态成员函数名(实参表)对象.静态成员函数名(实参表)对象指针->静态成员函数名(实参表)例4.18静态成员函数来访问静态数据成员。#include<iostream.h>#include<string.h>classStudent{private: char*name;//学生姓名char*stu_no;//学生学号 floatscore;//学生成绩
staticintcount;//静态数据成员,统计学生人数 staticfloatsum;//静态数据成员,统计总成绩public:Student(char*name1,char*stu_no1,floatscore1); ~Student();voidshow();//普通成员函数,输出姓名、学号和成绩static voidshow_count_sum();//静态成员函数,输出学生人数和总成绩};Student::Student(char*name1,char*stu_no1,floatscore1){name=newchar[strlen(name1)+1];strcpy(name,name1);stu_no=newchar[strlen(stu_no1)+1];strcpy(stu_no,stu_no1);score=score1;++count;//累加学生人数sum=sum+score;//累加总成绩}Student::~Student(){delete[]name;delete[]stu_no;--count;sum=sum-score;}voidStudent::show(){ cout<<"\nname:"<<name; cout<<"\nstu_no:"<<stu_no; cout<<"\nscore:"<<score;}voidStudent::show_count_sum()//静态成员函数{ cout<<"\ncount:"<<count;//输出静态数据成员cout<<"\nsum:"<<sum;//输出静态数据成员}intStudent::count=0;//静态数据成员初始化floatStudent::sum=0.0;//静态数据成员初始化voidmain(){Studentstu1("Liming","990201",90); stu1.show(); Student::show_count_sum();//使用类名访问静态成员函数Studentstu2("Zhanghao","990202",85); stu2.show(); stu2.show_count_sum();//使用对象stu2访问静态成员函数}有关静态成员函数可以定义成内嵌的,也可类外定义,类外定义时不要static。一般用来访问全局变量或同一类中的静态变量。私有静态成员函数不能被类外部函数和对象访问使用静态成员函数可以在创建对象之前处理静态数据成员,这是普通函数所不能实现的功能。静态成员函数没有this指针。一般不访问类中的非静态成员(变量、函数),访问时,要把对象作为参数传递。例4.19静态成员函数访问非静态数据成员。#include<iostream.h>classsmall_cat{public:small_cat(doublew){ weight=w; total_weight+=w; total_number++;}
staticvoiddisplay(small_cat&w){cout<<"Thesmall_catweights"<<w.weight<<"kg\n";}staticvoidtotal_disp(){cout<<total_number<<"small_cattotalweight";cout<<total_weight<<"kg"<<endl;}private: doubleweight; staticdoubletotal_weight; staticdoubletotal_number;};doublesmall_cat::total_weight=0;doublesmall_cat::total_number=0;main(){ small_catw1(0.9),w2(0.8),w3(0.7); small_cat::display(w1);small_cat::display(w2);
w1.display(w3);
w3.total_disp(); return0;}4.5友元
友元既可以是不属于任何类的一般函数,也可以是另一个类的成员函数,还可以是整个的类。
4.5.1友元函数
友元函数不是当前类的成员函数,而是独立于当前类的外部函数,但它可以访问该类的所有对象的成员,包括私有成员、保护成员和公有成员。1.将非成员函数声明为友元函数例4.22友元函数的使用。#include<iostream.h>#include<string.h>classgirl{ public: girl(char*n,intd) {name=newchar[strlen(n)+1]; strcpy(name,n);age=d;}~girl(){delete[]name;}
friendvoiddisp(girl&);//声明友元函数 private: char*name;intage;};
voiddisp(girl&x)//定义友元函数 {cout<<"Girl\′snameis"<<<<",age:"<<x.age<<"\n";}voidmain() {girle("ChenXinwei",18); disp(e);//调用友元函数 }友元函数没有this指针!!一个函数可以定义为多个类的友元函数。【例4.19】(110页)2.将成员函数声明为友元函数
一个类的成员函数也可以作为另一个类的友元,这种成员函数不仅可以访问自己所在类对象中的所有成员,还可以访问friend声明语句所在类对象中的所有成员。这样能使两个类相互合作、协调工作,完成某一任务。例4.24一个类的成员函数作为另一个类的友元。
#include<iostream.h>#include<string.h>classgirl;classboy{public: boy(char*n,intd){name=newchar[strlen(n)+1]; strcpy(name,n);age=d;}
voiddisp(girl&);
//声明disp()为类boy的成员函数 ~boy(){deletename;}private: char*name; intage;};
classgirl{ public: girl(char*n,intd) {name=newchar[strlen(n)+1]; strcpy(name,n);age=d;}
friendvoidboy::disp(girl&); ~girl(){deletename;}private: char*name; intage;};
voidboy::disp(girl&x)//定义友元函数disp(){
cout<<"Boy\′snameis"<<name<<",age:"<<age<<"\n";//访问boy类对象的成员cout<<"Girl\′snameis"<<<<",age:"<<x.age<<"\n";}
//访问girl类对象的成员
voidmain(){boyb("ChenHao",25);girle("ZhangWei",18);b.disp(e);}
程序运行结果如下:Boy′snameisChenHao,age:25Girl′snameis:ZhangWei,age:18
类的成员函数作为另一类的友元时,该类应该先定义4.5.2友元类
一个类也可以作为另一个类的友元。例如:classY{//…};classX{//…friendY;//声明类Y为类X的友元类//…};
一个类被声明为另一个类的友元时,它的所有成员函数都成为另一个类的友元函数。【例】友元类的示例。#include<iostream>classSample{intx;public:Sample(inta){x=a;}
friendclassOperation;//把类Operation当作友元(好朋友)};classOperation{public:intadd(Sample&s1,Sample&s2){returns1.x+s2.x;}intsubtract(Sample&s1,constSample&s2){returns1.x-s2.x;}};intmain(
){Samples1(10),s2(6);Operationobj;cout<<obj.add(s1,s2)<<endl;cout<<obj.subtract(s1,s2)<<endl;return0;}4.6类的组合
如果一个类的对象是另一个类的数据成员,则称这样的数据成员为对象成员(子对象)。例如:classA{//...};classB{Aa;//类A的对象a为类B的对象成员public://…};使用对象成员要注意的问题是对象成员的初始化问题,即类B的构造函数如何定义?例如有以下的类:
classX{类名1对象成员名1;类名2对象成员名2;…类名n对象成员名n;};一般来说,类X的构造函数的定义形式为;X::X(形参表0):对象成员名1(形参表1),…,对象成员名i(形参表i),…,对象成员名n(形参表n){//…构造函数体}
练习:写出程序的运行结果#include<iostream.h>classObject{ intval;public: Object(); //构造函数 Object(inti);//构造函数 ~Object(); //析构函数};Object::Object()//默认构造函数{ val=0; cout<<"\nDefaultconstructorforObject.\n";}Object::Object(inti) //构造函数定义{ val=i; cout<<"\nConstructorforObject:"<<val<<endl;}Object::~Object() //析构函数定义{ cout<<"\nDestructorforObject:"<<val<<endl;}classContainer//定义新类,它含Object的对象{private: intdate; Objectone; //对象成员 Objecttwo; //对象成员public: Container(); //构造函数 Container(inti,intj,intk); //构造函数 ~Container(); //析构函数};Container::Container() //默认构造函数定义{date=0;cout<<"\nDefaultconstructorforContainer.\n";}Container::Container(inti,intj,intk):two(i),one(j){date=k;cout<<"\nConstructorforContainer.\n";}Container::~Container(){cout<<"\nDestructorforContainer.\n";}intmain() //主程序{cout<<"\n...Enteringmain...\n";Containerobj(5,6,10);cout<<"\n...Exitingmain...\n";return0;}4-7共享数据的保护
4.7.1常引用如果在说明引用时用const修饰,则被说明的引用为常引用。常引用的说明形式如下:
const类型说明符&引用名例如:inta=5;constint&b=a;其中,b是一个常引用,它所引用的对象不允许更改。例4.28常引用作函数形参。#include<iostream.h>intadd(constint&i,constint&j);voidmain(){ inta=20; intb=30;cout<<a<<"+"<<b<<"="<<add(a,b)<<endl;}intadd(constint&i,const&j){ returni+j;}4.7.2常对象
如果在说明对象时用const修饰,则被说明的对象为常对象。常对象的说明形式如下:
类名const对象名[(参数表)];或者
const类名对象名[(参数表)];在定义对象时必须进行初始化,而且不能被更新。例4.29非常对象和常对象的比较。#include<iostream.h>classSample{public:intm;Sample(inti,intj){m=i;n=j;}voidsetvalue(inti){n=i;}voiddisply(){cout<<"m="<<m<<endl;cout<<"n="<<n<<endl;}private:intn;};voidmain(){Samplea(10,20);a.setvalue(40);a.m=30;a.disply();}4.7.3常对象成员
1.常数据成员使用const说明的数据成员称为常数据成员。如果在一个类中说明了常数据成员,那么构造函数就只能通过初始化列表对该数据成员进行初始化,而任何其他函数都不能对该成员赋值。
例4.30常数据成员举例。#include<iostream.h>classDate{public: Date(inty,intm,int
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 基于人工智能的区域教育人才培养均衡发展模式与产学研合作机制创新研究教学研究课题报告
- 我国试点时期国债期货基本功能的实证剖析与反思
- 我国融资融券交易业务模式的多维剖析与发展策略研究
- 2025年基础会计考核试题
- 公司合同档案室管理制度
- 猪场档案管理制度范本
- 档案事业单位晋升制度
- 语委办工作档案制度
- 2026年高考英语语法与写作技巧冲刺试卷
- 招商档案管理制度
- 进展性卒中课件
- 口腔客服接诊技巧
- 华为完整版本
- 心血管-肾脏-代谢综合征(CKM)综合管理中国专家共识2025解读课件
- 八年级英语下册集体备课教案:Unit 8 Have you read Treasure Island yet P1
- DB31-T 1433-2023 扬尘在线监测技术规范
- 加油站应急救援知识培训
- 安全生产标准化绩效考核评定报告
- 安徽永牧机械集团有限公司年产10000吨钢结构加工项目环境影响报告表
- 就业单位提前退休申请书
- QSY136-2023年生产作业现场应急物资配备选用指南
评论
0/150
提交评论