第-章━━对象数组静态成员友元优秀文档_第1页
第-章━━对象数组静态成员友元优秀文档_第2页
第-章━━对象数组静态成员友元优秀文档_第3页
第-章━━对象数组静态成员友元优秀文档_第4页
第-章━━对象数组静态成员友元优秀文档_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C++程序设计第5章(3)

━━对象数组、静态成员、友元1主要内容对象数组静态成员数据静态成员函数友元函数友元类指向类中非静态成员函数的指针指向类中静态成员函数的指针指向对象的常指针、指向常对象的指针常对象、对象的常引用类中的常成员━━常成员数据、常成员函数2对象数组对象数组:数组是一组相同类型的元素组成的集合体,而数组元素的类型当然可以是已定义的类类型,这种由同类对象组成的数组称为对象数组。对象数组中的一个元素就是同类的一个对象。对象数组的定义:

类名数组名[元素个数];对象数组元素的引用:数组名[下标]对象数组元素的成员的引用:数组名[下标].成员名对象数组的初始化:

①对象数组中的每一个元素对象被创建时,系统都会调用一次构造函数来初始化该元素对象。若没有为某一数组元素对象显式指定初始值,则调用的是默认构造函数初始化该数组元素对象。

【例】

Pointp[2];

//调用了两次默认构造函数

②定义对象数组时,通过初始化列表。

【例】

Pointp[2]={Point(1,2),Point(3,4)};3【例】(学生类、对象数组)#include<iostream.h>#include<string.h>classStudent{intid;charname[10]; intscore;

public:

Student(inti=0,char*na=0,ints=0){id=i;strcpy(name,na);score=s;cout<<“对象地址=”<<(int)this<<“\t构造(”<<name<<“)了!\n”;}

~Student(){cout<<“对象地址=”<<(int)this<<“\t析构(”<<name<<“)了!\n”;}

voidprint(){cout<<“学号=”<<id<<“\t姓名=”<<name<<“\t成绩=”<<score<<endl;}};voidmain(){

Students[3]={Student(111,“张军”,99),Student(222,“王红”,88),Student(333,“李强”,77)};for(inti=0;i<3;i++)s[i].print();}运行:对象地址=1244996构造(张军)了!对象地址=1245012构造(王红)了!对象地址=1245028构造(李强)了!学号:111姓名:张军成绩:99学号:222姓名:王红成绩:88学号:333姓名:李强成绩:77对象地址=1245028析构(李强)了!对象地址=1245012析构(王红)了!对象地址=1244996析构(张军)了!111张军99333李强77222王红88sS[0]S[1]S[2]4【例】(点类、对象数组)#include<iostream.h>#include<math.h>classPoint{floatx,y;

public:

Point(floata=0,floatb=0){x=a;y=b;cout<<“对象地址=”<<(int)this<<“\t调用构造函数了!\n”;}~Point(){cout<<“对象地址=”<<(int)this<<“\t调用析构函数了!\n”;}

voidinput(){

cout<<“\n输入点坐标(x,y)=”;cin>>x>>y;

}

voidprint(){

cout<<“点(”<<x<<“,”<<y<<“)”;

}

floatcalculate(Point&p){

returnsqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y));

}

};voidmain(){Pointp[3];

inti,j;

for(i=0;i<3;i++)p[i].input();

for(i=0;

i<2;i++)

for(j=i+1;j<3;j++)

{

p[i].print();cout<<“到”;p[j].print();

cout<<“的距离=”;cout<<p[i].calculate(p[j])

<<endl;}}运行:对象地址=1245020调用构造函数了!对象地址=1245028调用构造函数了!对象地址=1245036调用构造函数了!输入点坐标(x,y)=12↙输入点坐标(x,y)=34↙输入点坐标(x,y)=56↙点(1,2)到点(3,4)的距离=2.82843点(1,2)到点(5,6)的距离=5.65685点(3,4)到点(5,6)的距离=2.82843对象地址=1245036调用析构函数了!对象地址=1245028调用析构函数了!对象地址=1245020调用析构函数了!5静态成员数据类的静态成员:指类中由static修饰的成员,有静态成员数据、静态成员函数。类的静态成员为该类所有对象所共享。静态、非静态成员数据的区别:①定义类时,系统并不为类中的成员数据分配存储空间。

②定义对象时,才依次为对象的每一个非静态成员数据分配存储空间,并把该对象所占用的存储空间作为一个整体来看待。同类的不同对象,其非静态成员数据之间是互相独立的。

③定义对象时,系统并不为对象的静态成员数据分配存储空间!静态成员数据是同类所有对象所共享的成员,系统需要单独为类的静态成员数据分配存储空间。静态成员数据的特征:静态成员数据是同类所有对象所共享的成员,当该类的任一对象修改了该静态成员数据,同类其他对象中的该静态成员数据也都之改变。静态成员数据的作用:提供同类的各个对象之间信息交换的捷径。6静态成员数据的声明在类中作引用性声明:

class类名{……

static

类型静态成员数据名;

};在类外、文件作用域的位置作一次且仅能作一次定义性声明:

类型

类名::

静态成员数据名《=初值》;几点说明:①静态成员数据存放在静态区,系统在编译时就为其分配好空间。②若静态成员数据在定义性声明时未做初始化,其初值为0。③在类外作定义性声明时,前面不要加static。

④静态成员数据具有全局变量的一些特性,但受到访问权限的约束,建议将静态成员数据声明为私有,以保证类的封装性。若将其声明为公有,会带来与全局变量同样的副作用。7②将一个独立的普通函数fun()声明为类A的友元函数,其一般套路是:voidsetx(floata){x=a;}p2=Point::sety;(a.floatdistance(Point&p1,Point&p2)//友元函数distance()为独立的普通函数classB{……;voidfun(A&a);};//fun()是类B的成员函数cout<<“点数增至:”<<count<<endl;}classPoint静态、非静态成员函数的区别:returnsqrt(x*x+y*y);}distance()<<endl;}cout<<“点数增至:”<<count<<endl;}{Pointp1,p2;输入点坐标(x,y)=34↙第5章(3)

━━对象数组、静态成员、友元【例】Pointp[2];//调用了两次默认构造函数{count++;x=a;y=b;这样做的好处是:防止在函数中发生误操作,出现修改该形参对象的成员数据时,编译系统将给出错误信息。静态成员数据的引用在类中:直接通过静态成员数据名访问即可。在类外:(只能引用类中的public静态成员数据)①通过类名:类名::

静态成员数据名②通过对象名:对象名.

静态成员数据名③通过对象引用名:对象引用名.

静态成员数据名

④通过对象指针名:对象指针->

静态成员数据名8【例】(利用静态成员数据作为产生对象的计数器)#include<iostream.h>classPoint{floatx,y;

staticintcount;//引用性声明public:Point(floata=0,floatb=0){

count++;

x=a;y=b;cout<<“点数增至:”<<count<<endl;}

Point(Point&p){count++;

x=p.x;y=p.y;cout<<“点数增至:”<<count<<endl;}~Point(){count--;cout<<“点数降至:”<<count<<endl;

}};int

Point::

count=0;//定义性声明voidfun(){Pointb[2];}voidmain(){cout<<“一点所占字节=”<<sizeof(Point)<<endl;

Pointa1(10);cout<<“a1点所占字节=”<<sizeof(a1)<<endl;

for(inti=1;

i<=2;i++

){

fun();Pointa2(20);fun();

}Pointa3(30);}运行:一点所占字节=8点数增至:1a1点所占字节=8点数增至:2点数增至:3点数降至:2点数降至:1点数增至:2点数增至:3点数增至:4点数降至:3点数降至:2点数降至:1点数增至:2点数增至:3点数降至:2点数降至:1点数增至:2点数增至:3点数增至:4点数降至:3点数降至:2点数降至:1点数增至:2点数降至:1点数降至:09【例】(对静态成员数据的引用)#include<iostream.h>classTest{intz;

public:

staticintx,y;

Test(inta=10,intb=20,intc=30){x+=a;y+=b;z=c;}

voidshow(){cout<<“x=”<<x<<“\ty=”<<y<<“\tz=”<<z<<endl;}

};

intTest::x=1;intTest::y=2;voidmain(){

Testa1(1,2,9);a1.show();

a1.x=3;a1.y=4;

a1.show();Testa2;a2.show();

Test::x=5;Test::y=6;

a2.show();a1.show();}运行:x=2y=2z=9x=3y=4

z=9x=13y=24

z=30x=5y=6z=30x=5y=6z=910静态成员函数静态、非静态成员函数的区别:

①每一个非静态的成员函数中都包含了一个this指针,通过指向当前对象的指针this,才能直接引用到所操作对象的非静态成员数据。

②静态成员函数和静态成员数据一样,与对象无关。由于静态成员函数中不包含this指针,因此不能直接引用到对象的非静态成员,只能直接引用类的静态成员数据或静态成员函数。③静态成员函数若要访问本类对象的非静态成员,可间接实现,即在定义该静态成员函数时,增加一个形参为本类对象的引用,这样在函数体内就可以通过对象的引用名引用到该对象的非静态成员。

④关键字static只是用在类中声明某成员是静态成员;若在类外作定义性声明,则前面不要加static。⑤C++在定义类的对象时,物理上同类所有对象的成员函数只存储一份代码,所以一般情况下声明静态成员函数没有什么明显好处,通常没有必要声明静态成员函数。11for(inti=0;i<3;i++)s[i].show1();p3.返回值类型类名::静态成员函数名(形参表){函数体}它可以是该类之外的一个独立普通的函数,也可以是另外一个类的成员函数。class类名{count++;x=a;y=b;通过指向非静态成员函数的指针变量来调用函数:返回值类型(*指针变量名)(形参列表);show3();指向常对象的指针变量的声明:const类名*指针变量名[=对象地址];格式1:const类名对象名;返回值类型成员函数名(形参列表)const;学号:111姓名:张军成绩:99静态成员函数的声明和调用在类中可作引用性声明或定义性声明:

class类名{……

static

返回值类型静态成员函数名(形参表);

};也可在类外作定义性声明:

返回值类型类名::静态成员函数名(形参表){函数体}静态成员函数的调用:①在类中:静态成员函数名(实参表);②在类外:

(只能调用类中的public静态成员函数)

类名::静态成员函数名(实参表);

对象名.

静态成员函数名(实参表);

对象引用名.

静态成员函数名(实参表);

对象指针->

静态成员函数名(实参表);12【例】(静态成员函数、在静态成员函数中间接引用本类的非静态成员)#include<iostream.h>

classPoint{floatx,y;

staticintcount;

public:Point(floata=0,floatb=0){x=a;y=b;count++;

}~Point(){

count--;

}

voidshow1(){

cout<<“目前点数=”<<count

<<“\t当前点为(”<<x<<“,”<<y<<“)\n”;

}

static

voidshow2(Point&p)

{cout<<“目前点数=”<<count

<<“\tp点为(”<<

<<“,”<<

<<“)\n”;

}

static

voidshow3()

{cout<<“目前点数=”<<count<<endl;

}};intPoint::count=0;voidmain(){Pointp1(1,2),p2,p3(p1);p1.show1();p2.show1();p3.show1();

Point::show2(

p2

);

Point::show3();p1.show3();p2.show3();}运行:目前点数=2 当前点为(1,2)目前点数=2 当前点为(0,0)目前点数=2 当前点为(1,2)目前点数=2 p点为(0,0)目前点数=2目前点数=2目前点数=2

13友元函数关于友元函数:

①若某类外有一个函数需要引用该类的私有或保护成员,此时可将这个类外的函数通过成为该类的友元函数来实现这种访问。②类的友元函数是该类之外的函数,不是该类的成员函数!它可以是该类之外的一个独立普通的函数,也可以是另外一个类的成员函数。③友元函数不是类的成员函数,在友元函数体中要访问该类对象的成员时,必须在成员名前面加上“对象名.”。④一个类的友元函数可以访问该类中的所有成员,包括私有或保护成员,即不受访问权限的限制,也就打破了类的封装性,应谨慎使用友元函数!使用友元函数目的:提高程序的运行效率,因为使用友元函数可减少调用类的外部接口函数的次数。14友元函数的声明友元函数的类中声明:将类外的一个函数声明为该类的友元函数,只要在该类的类体中作友元函数的原型声明,并在前面加关键字friend。class类名 {……

friend返回值类型函数名(形参表);

friend返回值类型另外一个类的类名::函数名(形参表);};注意:也可在类中作友元函数的定义性声明,但它不是该类的成员函数!友元函数的类外定义:①若友元函数为类外独立的普通函数,按普通函数的定义方式不变。②若友元函数为另外一个类的成员函数,按成员函数的定义方式不变。③在类外定义友元函数时,前面不要加friend。15友元函数的使用友元函数使用的一般套路:

①某类的友元函数不是该类的成员函数!在友元函数中不能直接访问该类的成员,但可以间接访问!即通过该类的对象名、对象引用名或对象指针来间接访问该类的成员。因此在定义友元函数时,应增加一个形参,该形参可以是该类的对象、对象的引用或对象的指针。②将一个独立的普通函数fun()声明为类A的友元函数,其一般套路是:classA{……;

friendvoidfun(

A&a

);

};//fun()是类A的友元函数

voidfun(

A&a

){函数体}//普通函数fun()的类外定义③将类B的一个成员函数fun()声明为类A的友元函数,其一般套路是:

classA;//类A的引用性声明

classB{……;voidfun(

A&a

);

};//fun()是类B的成员函数classA{……;

friendvoid

B::

fun(

A&a

);

};//fun()是类A的友元函数

void

B::

fun(

A&a

){

函数体

}//类B的成员函数fun()的类外定义友元函数的调用:按普通函数或成员函数的调用方式进行调用。16【例】(友元函数为类外的普通函数、求两点之间距离的distance()函数)#include<iostream.h>#include<math.h>

classPoint{floatx,y;public:Point(floata=0,floatb=0){x=a;y=b;}

voidshow(){

cout<<“点(”<<x<<“,”<<y<<“)\t”;

}friendfloatdistance(Point&p1,Point&p2);//友元声明

};floatdistance(Point&p1,Point&p2)//友元函数distance()为独立的普通函数{floatx=;floaty=;returnsqrt(x*x+y*y);

}voidmain(){Pointq1(1,2),q2(3,4),q3(5,6);//定义三个点floats=distance(q1,q2)+distance(q2,q3)+distance(q3,q1);q1.show();q2.show();q3.show();cout<<“\n三点构成三角形的周长=”<<s<<endl;}运行:点(1,2)点(3,4)点(5,6)三点构成三角形的周长=11.313717【例】(友元函数为另外一个类的成员函数)#include<iostream.h>classA;

//类A的引用性声明classB{floatx,y;

public:B(floata=0,floatb=0){x=a;y=b;}

voidshow(){

cout<<“B类:x=”<<x<<“\ty=”<<y<<endl;

}

voidset(A&a);

//成员函数set()的原型声明};classA//类A的定义性声明{floatm,n;

public:A(floata=0,floatb=0){m=a;n=b;}

voidshow(){

cout<<“A类:m=”<<m<<“\tn=”<<n<<endl;

}

friendvoidB::set(A&a);

//声明类B的成员函数set()为友元函数};voidB::set(A&a){

x=a.m;y=a.n;

}

//类B的成员函数set()的定义性声明voidmain(){Bb(1,2);b.show();Aa(3,4);a.show();

b.set(a);b.show();}运行:B类:x=1y=2A类:m=3n=4B类:x=3y=418友元类友元类:将整个类声明为另外一个类的友元。友元类的声明:将整个类声明为某类的友元类,只要在该类的类体中作友元类的引用性声明,并在前面加关键字friend。class类名 {……

friendclass另一个类的类名; };友元类的特征:①若声明类B是类A的友元类,则类B中的所有成员函数都是类A的友元函数,即类B中的所有成员函数都可以访问类A中的所有成员,称类B为类A的友元。②友元关系不具有传递性。若类A是类B的友元,而类B是类C的友元,则不能推断出类A就是类C的友元。③友元关系不具有交换性。若类A是类B的友元,则不能推断出类B就是类A的友元。④友元关系不具有继承性。若类A是类B的友元,而类B是类C的基类,则不能推断出类A就是类C的友元。19【例】(直线类Line是点类Point的友元类)#include<iostream.h>#include<math.h>classPoint{floatx,y;public:Point(floata=0,floatb=0){x=a;y=b;}

voidshow(){

cout<<“点(”<<x<<“,”<<y<<“)\t”;

}friendclassLine;};classLine{Pointp1,p2;

public:Line(Pointq1,Pointq2):p1(q1),p2(q2)

{}

floatdistance(){

returnsqrt(()*()+()*(p1.y-p2.y));}

};voidmain(){Pointp1(1,2),p2(3,4);LineL(p1,p2);p1.show();p2.show();cout<<“\n两点构成直线的长度=”<<L.distance()<<endl;}运行:点(1,2)点(3,4)20指向类中成员函数的指针指向成员函数的指针:即指向类中一个成员函数的入口地址。几点说明:

①指向类中成员函数的指针变量不是类中的成员,应在类外定义。

②不能将任一成员函数的入口地址赋给指向成员函数的指针变量,只能将与其具有相同返回值类型且相同参数(参数类型、个数、顺序均一致)的这一类成员函数的地址赋给该指针变量。

③通过指向成员函数的指针只能调用public成员函数;若要调用private成员函数,必须通过类中其他的public成员函数间接实现。21指向类中非静态成员函数的指针指向非静态成员函数的指针变量的定义:返回值类型(

类名::

*指针变量名

)(形参列表);对指向非静态成员函数的指针变量的赋值:指针变量=类名::

成员函数名

注意:赋值时使用的是类名::

成员函数名,不是对象名::

成员函数名!通过指向非静态成员函数的指针变量来调用函数:

格式1:(对象名

.*

指针变量名)(实参列表)格式2:(对象指针

->*

指针变量名)(实参列表)

注意:通过这种指向非静态成员函数的指针变量来调用非静态成员函数时,必须指明调用的是哪一个对象的成员函数,不能单独使用!22Pointa3(30);}②不能将任一成员函数的入口地址赋给指向成员函数的指针变量,只能将与其具有相同返回值类型且相同参数(参数类型、个数、顺序均一致)的这一类成员函数的地址赋给该指针变量。对象数组元素的引用:数组名[下标]类型类名::静态成员数据名《=初值》;x=13y=24z=30cout<<“\n三点构成三角形的周长=”<<s<<endl;}静态成员函数的声明和调用也可在类外作定义性声明:#include<math.指向静态成员函数的指针变量的定义:①静态成员数据存放在静态区,系统在编译时就为其分配好空间。Pointa(1,2);floatgetx(){returnx;}返回值类型类名::静态成员函数名(形参表){函数体}通过指向非静态成员函数的指针变量来调用函数:cout<<“x=”<<(a1.【例】(指向类中非静态成员函数的指针)#include<iostream.h>classPoint{

floatx,y;public:

Point(floata=0,floatb=0){x=a;y=b;}

floatgetx(){returnx;}floatgety(){returny;}

voidsetx(floata){

x=a;}

voidsety(floata){

y=a;

}};voidmain(){float(Point::

*p1)();void(Point::

*p2)(float);

Pointa(1,2);

p1=

Point::

getx;cout<<“x=”<<(a.*p1

)()<<‘\t’;

p1=

Point::

gety;cout<<“y=”<<(

a.*p1

)()<<‘\n’;

p2=Point::

setx;(

a.*p2

)(3);

p2=Point::

sety;(

a.*p2

)(4);cout<<“x=”<<a.getx()<<“\ty=”<<a.gety()<<endl;

}运行:x=1y=2x=3y=423指向类中静态成员函数的指针指向静态成员函数的指针变量的定义:返回值类型(

*指针变量名

)(形参列表);注意:①定义时不要使用类名::

*指针变量名,即不加类名和域运算符!②指向静态成员函数的指针变量的定义与指向普通函数的指针变量的定义方法类同。对指向静态成员函数的指针变量的赋值:

指针变量=类名::

成员函数名通过指向静态成员函数的指针变量来调用函数:格式1:

(*指针变量)

(实参列表)格式2:

指针变量

(实参列表)24【例】(指向类中静态、非静态成员函数的指针)#include<iostream.h>classA{floatx;

staticfloaty;

public:

A(floata=0,floatb=0){x=a;y=b;}

floatgetx(){returnx;}

staticfloatgety(){returny;}};floatA::y;voidmain(){float(A::*p1)();float(*p2)();Aa1(1,2),a2(3,4);

p1=A::getx;

p2=A::gety;cout<<“x=”<<(a1.*p1

)()<<“\ty=”<<p2

()<<endl;cout<<“x=”<<(a2.*p1

)()<<“\ty=”<<p2

()<<endl;}运行:

x=1y=4x=3y=425指向对象的常指针指向对象的常指针变

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论