5 第5章 数据的共享与保护.docx

上传人:b****8 文档编号:30192514 上传时间:2023-08-07 格式:DOCX 页数:30 大小:563.30KB
下载 相关 举报
5 第5章 数据的共享与保护.docx_第1页
第1页 / 共30页
5 第5章 数据的共享与保护.docx_第2页
第2页 / 共30页
5 第5章 数据的共享与保护.docx_第3页
第3页 / 共30页
5 第5章 数据的共享与保护.docx_第4页
第4页 / 共30页
5 第5章 数据的共享与保护.docx_第5页
第5页 / 共30页
点击查看更多>>
下载资源
资源描述

5 第5章 数据的共享与保护.docx

《5 第5章 数据的共享与保护.docx》由会员分享,可在线阅读,更多相关《5 第5章 数据的共享与保护.docx(30页珍藏版)》请在冰豆网上搜索。

5 第5章 数据的共享与保护.docx

5第5章数据的共享与保护

第5章数据的共享与保护

5.0导学

问题与解决

●问题1:

变量和对象可以定义在不同的位置:

函数体内、类体内、函数原型参数表内、所有函数和类之外,使用的时候分别有什么不同、访问和共享有什么限制呢?

●不同位置定义的变量和对象,其作用域、可见性、生存期都不同。

如果要在不同的程序模块间共享数据,就需要了解变量和对象的作用域、可见性、生存期。

●作用域是指……;可见性是……;生存期是……。

●问题2:

如何在同一个类的所有对象之间共享数据?

比如需要记录一个类的对象总数。

●定义属于整个类而不是对象的数据成员——静态数据成员

●定义用于处理静态数据成员的函数——静态成员函数

●问题3:

类的私有成员在类外不能直接访问,这是为了保护数据的安全性和隐藏细节。

但是需要频繁访问私有数据时,调用接口函数的开销比较大。

●对一些类外的函数、其他的类,给预授权,使之可以访问类的私有成员

●提高了效率,但是带来一些安全隐患,需要权衡、慎用

●问题4:

共享数据的安全性如何保证

●通过const关键字,限制对共享数据的修改,使共享的数据在被共享时,是只读的。

●在编译之前,需要进行预处理,例如包含头文件,选择在不同情况下编译程序的不同部分

●编译预处理

●问题5:

当程序的规模略大些的时候,就不能将所有代码放在一个文件里了

●多文件结构

学习建议

●完成练习题和编程作业

●编写程序(或者修改例题)观察和验证变量的作用域、可见性、生存期

●除了完成作业,希望

●能自己举出一些需要定义静态成员的例子,并编写程序实现

●找出以前的例题、习题,看看可否改写,将一些类的成员函数改为常函数;将一些函数的参数定义为常引用。

●尝试在程序中使用编译预处理命令,并观察效果。

5.1 标识符的作用域与可见性

5.2 对象的生存期

5.3 类的静态成员

5.4 类的友元

5.5 共享数据的保护

5.6 多文件结构和编译预处理命令

小结

5.1 标识符的作用域与可见性

●作用域是一个标识符在程序正文中有效的区域。

●作用域分类

1.函数原型作用域

2.局部作用域(块作用域)

3.类作用域

4.文件作用域

5.命名空间作用域(详见第10章)

函数原形作用域

●函数原型中的参数,其作用域始于"(",结束于")"。

●函数原形作用域举例

doublearea(doubleradius);

局部作用域

●函数的形参、在块中声明的标识符;

●其作用域自声明处起,限于块中。

●局部作用域举例

voidfun(inta){

intb=a;

cin>>b;

if(b>0){

intc;

......

}

}

类作用域

●类的成员具有类作用域,其范围包括类体和非内联成员函数的函数体。

●如果在类作用域以外访问类的成员,要通过类名(访问静态成员),或者该类的对象名、对象引用、对象指针(访问非静态成员)。

●文件作用域

●不在前述各个作用域中出现的声明,就具有文件作用域,这样声明的标识符其作用域开始于声明点,结束于文件尾。

可见性

●可见性是从对标识符的引用的角度来谈的概念

●可见性表示从内层作用域向外层作用域“看”时能看见什么。

●如果标识在某处可见,就可以在该处引用此标识符。

●如果某个标识符在外层中声明,且在内层中没有同一标识符的声明,则该标识符在内层可

见。

●对于两个嵌套的作用域,如果在内层作用域内声明了与外层作用域中同名的标识符,则外层作用域的标识符在内层不可见。

例5-1

//例5_1作用域实例.cpp(P149)

#include

usingnamespacestd;

inti;//全局变量,文件作用域

namespaceNs{

intj;//在Ns命名空间中的全局变量

}

intmain(){

i=5;//为全局变量i赋值

Ns:

:

j=6;//为全局变量j赋值

{//子块1

usingnamespaceNs;//使得当前块中可以直接引用Ns命名空间的标识符

inti;//局部变量,局部作用域

i=7;

cout<<"i="<

cout<<"j="<

}

cout<<"i="<

return0;

}

运行结果:

5.2 对象的生存期

静态生存期

●这种生存期与程序的运行期相同。

●在文件作用域中声明的对象具有这种生存期。

●在函数内部声明静态生存期对象,要冠以关键字static。

动态生存期

●块作用域中声明的,没有用static修饰的对象是动态生存期的对象(习惯称局部生存期对象)。

●开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。

//例5_2变量的生存期与可见性.cpp(P151)

#include

usingnamespacestd;

inti=1;//i为全局变量,具有静态生存期。

voidother(){

staticinta=2;

staticintb;

//a,b为静态局部变量,具有全局寿命,局部可见。

//只第一次进入函数时被初始化。

intc=10;//C为局部变量,具有动态生存期,

//每次进入函数时都初始化。

a+=2;

i+=32;

c+=5;

cout<<"---OTHER---\n";

cout<<"i:

"<

"<

"<

"<

b=a;

}

intmain(){

staticinta;//静态局部变量,有全局寿命,局部可见。

intb=-10;//b,c为局部变量,具有动态生存期。

intc=0;

cout<<"---MAIN---\n";

cout<<"i:

"<

"<

"<

"<

c+=8;other();

cout<<"---MAIN---\n";

cout<<"i:

"<

"<

"<

"<

i+=10;other();

return0;

}

运行结果:

例5_3具有静态和动态生存期对象的时钟程序

//例5_3具有静态和动态生存期对象的时钟程序.cpp

#include

usingnamespacestd;

classClock{//时钟类定义

public:

//外部接口

Clock();

voidsetTime(intnewH,intnewM,intnewS);//三个形参均具有函数原型作用域

voidshowTime();

private:

//私有数据成员

inthour,minute,second;

};

//时钟类成员函数实现

Clock:

:

Clock():

hour(0),minute(0),second(0){}//构造函数

voidClock:

:

setTime(intnewH,intnewM,intnewS){//三个形参均具有局部作用域

hour=newH;

minute=newM;

second=newS;

}

voidClock:

:

showTime(){

cout<

"<

"<

}

ClockglobClock;//声明对象globClock,具有静态生存期,命名空间作用域

//由缺省构造函数初始化为0:

0:

0

intmain(){//主函数

cout<<"Firsttimeoutput:

"<

//引用具有命名空间作用域的对象globClock:

globClock.showTime();

//对象的成员函数具有类作用域

//显示0:

0:

0

globClock.setTime(8,30,30);//将时间设置为8:

30:

30

ClockmyClock(globClock);

//声明具有局部作用域的对象myClock

//调用拷贝构造函数,以globClock为初始值

cout<<"Secondtimeoutput:

"<

myClock.showTime();

//引用具有局部作用域的对象myClock

//输出8:

30:

30

return0;

}

运行结果:

5.3 类的静态成员

5.3.1 静态数据成员

●静态数据成员

■用关键宇static声明

■为该类的所有对象共享,静态数据成员具有静态生存期。

■必须在类外定义和初始化,用(:

)来指明所属的类。

●例5-4具有静态数据成员的Poinr类

//例5_4具有静态数据成员的Poinr类.cpp(P155)

#include

usingnamespacestd;

classPoint{//Point类定义

public:

//外部接口

Point(intx=0,inty=0):

x(x),y(y){//构造函数

count++;//在构造函数中对count累加,所有对象共同维护同一个count

}

Point(Point&p){//拷贝构造函数

x=p.x;

y=p.y;

count++;

}

~Point(){count--;}

intgetX(){returnx;}

intgetY(){returny;}

voidshowCount(){//输出静态数据成员

cout<<"Objectcount="<

}

private:

//私有数据成员

intx,y;

staticintcount;//静态数据成员声明,用于记录点的个数

};

intPoint:

:

count=0;//静态数据成员定义和初始化,使用类名限定

intmain(){//主函数

Pointa(4,5);//定义对象a,其构造函数回使count增1

cout<<"PointA:

"<

a.showCount();//输出对象个数

Pointb(a);//定义对象b,其构造函数回使count增1

cout<<"PointB:

"<

b.showCount();//输出对象个数

return0;

}

运行结果:

5.3.2 静态函数成员

●类外代码可以使用类名和作用域操作符来调用静态成员函数。

●静态成员函数主要用于处理该类的静态数据成员,可以直接调用静态成员函数。

●如果访问非静态成员,要通过对象来访问。

例5-5具有静态数据、函数成员的Point类

//例5_5具有静态数据、函数成员的Point类源.cpp(P157)

#include

usingnamespacestd;

classPoint{//Point类定义

public:

//外部接口

Point(intx=0,inty=0):

x(x),y(y){//构造函数

//在构造函数中对count累加,所有对象共同维护同一个count

count++;

}

Point(Point&p){//拷贝构造函数

x=p.x;

y=p.y;

count++;

}

~Point(){count--;}

intgetX(){returnx;}

intgetY(){returny;}

staticvoidshowCount(){//静态函数成员

cout<<"Objectcount="<

}

private:

//私有数据成员

intx,y;

staticintcount;//静态数据成员声明,用于记录点的个数

};

intPoint:

:

count=0;//静态数据成员定义和初始化,使用类名限定

intmain(){//主函数

Pointa(4,5);//定义对象a,其构造函数回使count增1

cout<<"PointA:

"<

Point:

:

showCount();//输出对象个数

Pointb(a);//定义对象b,其构造函数回使count增1

cout<<"PointB:

"<

Point:

:

showCount();//输出对象个数

return0;

}

运行结果:

5.4 类的友元

友元是C++提供的一种破坏数据封装和数据隐藏的机制。

通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息。

可以使用友元函数和友元类。

为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元。

5.4.1友元函数

友元函数是在类声明中由关键字friend修饰说明的非成员函数,在它的函数体中能够通过对象名访问 private 和 protected成员

作用:

增加灵活性,使程序员可以在封装和快速性方面做合理选择。

访问对象中的成员必须通过对象名。

例5-6 使用友元函数计算两点间的距离

//例5_6使用友元函数计算两点间的距离.cpp(P160)

#include

#include

usingnamespacestd;

classPoint{//Point类定义

public:

//外部接口

Point(intx=0,inty=0):

x(x),y(y){}

intgetX(){returnx;}

intgetY(){returny;}

friendfloatdist(Point&p1,Point&p2);//友元函数声明

private:

//私有数据成员

intx,y;

};

floatdist(Point&p1,Point&p2){//友元函数实现

doublex=p1.x-p2.x;//通过对象访问私有数据成员

doubley=p1.y-p2.y;

returnstatic_cast(sqrt(x*x+y*y));

}

intmain(){//主函数

Pointmyp1(1,1),myp2(4,5);//定义Point类的对象

cout<<"Thedistanceis:

";

cout<

return0;

}

运行结果:

5.4.2友元类

若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员。

声明语法:

将友元类名在另一个类中使用friend修饰说明。

classA{

friendclassB;

public:

voiddisplay(){

cout<

}

private:

intx;

};

classB{

public:

voidset(inti);

voiddisplay();

private:

Aa;

};

voidB:

:

set(inti){

a.x=i;

}

voidB:

:

display(){

a.display();

}

类的友元关系是单向的

如果声明B类是A类的友元,B类的成员函数就可以访问A类的私有和保护数据,但A类的成员函数却不能访问B类的私有、保护数据。

5.5共享数据的保护

● 对于既需要共享、又需要防止改变的数据应该声明为常类型(用const进行修饰)。

● 对于不改变对象状态的成员函数应该声明为常函数。

常类型

● 5.5.1常对象:

必须进行初始化,不能被更新。

■ const类名对象名

● 5.5.2常成员

■ 用const进行修饰的类成员:

常数据成员和常函数成员

● 5.5.3常引用:

被引用的对象不能被更新。

■ const 类型说明符 &引用名

● 常数组:

数组元素不能被更新(详见第6章)。

■ 类型说明符 const 数组名[大小]...

● 常指针:

指向常量的指针(详见第6章)。

常对象

● 用const修饰的对象

● 例:

classA

{

 public:

   A(inti,intj){x=i;y=j;}

                    ...

 private:

   intx,y;

};

Aconsta(3,4);//a是常对象,不能被更新

● 思考:

哪些操作有试图改变常对象状态的危险?

常成员

● 用const修饰的对象成员

● 常成员函数

■ 使用const关键字说明的函数。

■ 常成员函数不更新对象的数据成员。

■ 常成员函数说明格式:

类型说明符 函数名(参数表)const;

这里,const是函数类型的一个组成部分,因此在实现部分也要带const关键字。

■ const关键字可以被用于参与对重载函数的区分

● 通过常对象只能调用它的常成员函数。

●常数据成员

■ 使用const说明的数据成员。

例5-7 常成员函数举例

//例5_7常成员函数举例.cpp(P164)

#include

usingnamespacestd;

classR{

public:

R(intr1,intr2):

r1(r1),r2(r2){}

voidprint();

voidprint()const;

private:

intr1,r2;

};

voidR:

:

print(){

cout<

"<

}

voidR:

:

print()const{

cout<

}

intmain(){

Ra(5,4);

a.print();//调用voidprint()

constRb(20,52);

b.print();//调用voidprint()const

return0;

}

 运行结果:

例5-8  常数据成员举例

//例5_8常数据成员举例.cpp(P165)

#include

usingnamespacestd;

classA{

public:

A(inti);

voidprint();

private:

constinta;

staticconstintb;//静态常数据成员

};

constintA:

:

b=10;//静态常数据成员在类外说明和初始化

//常数据成员只能通过初始化列表来获得初值

A:

:

A(inti):

a(i){}

voidA:

:

print(){

cout<

"<

}

运行结果:

常引用

● 如果在声明引用时用const修饰,被声明的引用就是常引用。

● 常引用所引用的对象不能被更新。

● 如果用常引用做形参,便不会意外地发生对实参的更改。

常引用的声明形式如下:

■ const 类型说明符 &引用名;

例5-9 常引用作形参

//例5_9常引用作形参.cpp(P167)

#include

#include

usingnamespacestd;

classPoint{//Point类定义

public:

//外部接口

Point(intx=0,inty=0):

x(x),y(y){}

intgetX(){returnx;}

intgetY(){returny;}

friendfloatdist(constPoint&p1,constPoint&p2);

private:

//私有数据成员

intx,y;

};

floatdist(constPoint&p1,constPoint&p2){//常引用作形参

doublex=p1.x-p2.x;

doubley=p1.y-p2.y;

returnstatic_cast(sqrt(x*x+y*y));

}

intmain(){//主函数

constPointmyp1(1,1),myp2(4,5);//定义Point类的对象

cout<<"Thedistanceis:

";

cout<

return0;

}

运行结果:

5.6多文件结构和编译预处理命令

注意:

视频中例5-10程序代码有误,请看下面的更正:

Point(intx=0,inty=0):

x(x).y(y){}更正为

Point(intx=0,inty=0):

x(x),y(y){count++;}

5.6.1c++程序的一般组织结构

●一个工程可以划分为多个源文件

■类声明文件(.h)

■类实现文件(.cpp)

■类的使用文件(main()所在的.cpp文件)

●利用工程来组合各个文件

例5-10多文件的工程

//文件1,类的定义,Point.h

classPoint{//类的定义

public:

//外部接口

Point(

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 交通运输

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1