c++ 数据共享

来源:互联网 发布:discuz 数据字典 编辑:程序博客网 时间:2024/04/29 20:00


对象(变量)的作用域、可见性与生存期 类的静态成员
类的友元
常引用、常对象和常成员

 对象(变量)的作⽤用域、可⻅见性和⽣生存期

• •

对象(变量)的作用域:指对象的有效范围。
一般情况下,对象在其作用域内是可见的和存在的,对象的作用域、可见性和生存期三者是一致的。

对象(变量)的可见性:指不同作用域的同名对象在其作用域范围内的某一处是否可被引用。

对象(变量)的生存期:指对象从诞生(占据内存到结束(不占内存)的这段时间。在生存期内对 象或变量将保持它的值不变直到它们被更新为 止。

-对象(变量)的生存期分为动态生存期和静态生存期两 种。

• •

• •

 对象(变量)的作⽤用域 

局部对象(变量):(函数内)块作用域

从声明处开始到块结束的花括号为止

 形参对象(变量):函数作用域

在整个函数内有效 

成员对象(变量):类作用域

在整个类内有效,即在所有成员函数内有效

 全局对象(变量):文件作用域

在整个文件内有效

• •

• •

 对象(变量)的可⻅见性 一般情况下对象(变量)在其作用域范围内的任一处

是可见的,即可被引用。 在有不同作用域的多个同名对象(变量)的情况下,外层对象(变量)在内层不可见被隐藏起来。

不同作用域的同名对象的 包含关系如图所示。

被隐藏的成员对象(变量可加类名::”来显式地引用被隐藏的全局对象(变量可加“::”来显式地引用。

文件作用域

类作用域

函数作用域

块作用域

作用域关系 图

 对象(变量)的⽣生存期

对象(变量)的生存期:动态生存期、静态生存 期。

动态生存期:对象(变量)在程序运行期间随时诞 生和消失,如局部变量、形参变量、成员变量

静态生存期:对象(变量)在程序运行期间一直存 在,如全局变量。

C语言中静态局部变量:作用域与生存期不一 致。

C++在类的成员函数中定义一个静态局部变量: 该类的所有对象在调用这个成员函数时将共享这 个变量。

C++类的成员为静态成员:静态成员为该类所有 对象所共享,它不属于某个对象的,见下节。

程序实例

 静态成员(static) C语言中,当把函数的一个局部变量说明为

静态的,则该变量在函数调用结束后其值仍然存 在,但其它函数不能引用。若下次再调用该函 数,则该变量的值不再重新初始化为0,函数可以 使用上次调用所保留的值。

C++中,对于某个类所定义的每一个对象, 都有其属于自身的数据成员与成员函数,不同对 象之间的成员是互不相干的,这类似于C中函数 内的局部变量,不同时间函数调用的局部变量是 互不相干的。但它们都同名。

因此,在C++中,当把类的某个成员用关 键字static说明为静态成员时就是把该成员定 义为在该类范围内的全局成员,即无论这个类 建立了多少个对象,所有对象都共用这个成 员。因此,静态成员的主要用途是定义类的各个 对象所共用的数据成员或成员函数,其中尤其 是数据成员。

下面对静态数据成员和静态成员函数分别 进行讨论。

 静态数据成员

在一个类中,若将一个数据成员说明为 static,则该数据成员称为静态数据成员,无论建 立多少个该类的对象,都只有一个共同的数据成 员。static数据成员在编译时按全局变量方式被分 配存储单元并初始化,默认的初始值为零。

欲声明一个成员为静态的,只要在其前方加 上关键字static即可如在Point类定义一个静态数 据成员countP :

static int countP;

静态数据成员的使用与普通数据成员的使用 并无差异,但必须注意两点:

a.由于静态数据成员在该类范围内是一个全局 变量,因此必须在类定义外的全局范围中给它赋 初值,然后才能使用。如下所示:

int Point::countP=0;

给静态数据成员赋初值时必须同时指名数据 类型与所属的类,用类名加作用域运算符来限 定。这里的数据类型必须与在类中声明的数据类 型一致。

由于静态数据成员并不特别属于某一个对象, 上述这样的赋初值语句只能在整个程序中出现一 次。因此,程序员最好不要把静态成员的初始化定 义在头文件中,因为头文件可能在程序中多次被引 入使用,否则将发生错误。

b.当静态数据成员声明于类的public区时,由 于它并不特别属于某一个对象在类范围内是全局 的,因此可以在程序的任何地方直接引用该静态数 据成员,但使用时必须加上类范围的限制,如:

cout<<"对象个数为:"<<Point::countP;

 由于静态数据成员是所有同类对象所共用的

数据,所以

A.getC(); B.getC();

这两个输出语句的结果是相同的,即: 对象个数为:2

对象个数为:2

从程序的最后两句可以看出,类的public数据 成员有两种使用方法:

对象名.数据成员 或 类名::数据成员

第一种方式主要用于非静态数据成员,第 二种主要用于静态数据成员。

 静态成员函数

成员函数也可以被声明为静态的。当一个成 员函数被声明为static时,表明该静态成员函数只 属于一个类,而不属于该类的任何对象。因此, 在访问静态成员函数时,最好用类名加作用域运 算符来调用该静态成员函数。

实际上,当某成员函数只使用静态数据成员 时,应该把该成员函数定义为静态成员函数。这是 因为,一个仅使用到静态数据成员的成员函数通过 某类的对象来调用是没有任何意义的,且容易造成 阅读上的混淆,阅读者无法从程序中直接看出该成 员函数引用了静态数据成员。

因此

A.getC( ); B.getC( );

改为:

Point::getC( ); Point::getC( );

更为妥当。

另一方面静态成员函数不属于某个对象的因 此在静态成员函数访问非静态成员时,必须要指 明所要访问的对象。例如,若在getC中要访问非静 态成员X, getC必须修改为:

static void getC(Point &p)
{ cout<<"
对象个数为:"<<countP<<endl;

cout<<“X:”<<X<<endl; //错误

cout<<“X:"<<p.X<<endl; }

main函数中的调用语句改为:

Point::getC(A); Point::getC(B);


友元(friend) 前面已讲过一个对象的私有数据只能通过成员

函数进行访问。这种数据封装的方法虽有许多优点但在某些情况下也带来许多不便如某个函数需要 使用多个类的多个相关数据或类Y的所有成员函数 要访问类X的私有数据。出于效率而非技术的考虑, C++提供了友元(friend)这样一种辅助手段允许外 面的类或函数去访问一个类的私有数据。

友元分为两种情况:将一个普通函数声明为某 类的友元和将一个类声明为另一个类的友元。

 友元函数

要声明一个普通函数为某类的友元只要在该 类定义中任何一处(不管是privateprotected或是 public)提供对该函数的声明,并在其最前方加 上关键字friend即可。下面是计算两点距离的实 例:

class Point { int X,Y;

friend float fdist(Point &p1, Point &p2);//友元函数 public:

Point (int xx=0, int yy=0){X=xx; Y=yy;} };

与成员函数一样,友元函数可以在类Point的 内部定义,也可以在类Point的外部定义。当在类 外定义时友元函数不需要加::”。如上述fDist 函数在类Point外定义:

double fDist (Point &p1, Point &p2) {

double x=double(p1.X-p2.X); double y=double(p1.Y-p2.Y); return sqrt (x*x+y*y);

}

请注意友元函数与成员函数在定义和使用上 的区别。成员函数与友元函数的主要区别是成员 函数是属于某个类的,而友元函数不属于某个 类。

在友元函数中,必须指定所要访问的对象, 这在三个地方体现出来:

在参数中有2Point类的引用;
(a) 在实现代码中通过引用对象p1“.”来使用数据

成员;
(b) 使用友元函数(即调用该友元函数)时必须有该

类对象作为实参。

 友元类

我们可以将类A声明为类B的友元,这样类的所有成员函数就可以访问类B的私有数据。例 如:

class A; //一个类声明语句 class B
{

friend A; //声明AB的友元类 int i;
void m_func( );

};

class A
{ public:

void f_f1(B &); void f_f2(B &);

...... };

对于友元类的成员函数的使用和定义方式, 由于它兼具有类和友元函数的双重特点,所以 它的使用和定义方式颇具特色,具体如下:

a.由于它是属于某个类(A),所以在类外定义 时必须加作用域运算符来限定它属于某一类(A) 的,在使用时必须加对象名和成员运算符来指定 哪一个对象调用它;

b.由于它是另一个类(B)的友元,所以在其参 数中必须用该类(B)的对象和引用作为形参。

c.在实现代码上,必须用该类(B)的对象名加 成员运算符来使用该类(B)的私有数据。

友元说明只有在确实必要时才应使用,即在 没有它时必须建立一个复杂的类等级的时候才使 用。从性质上来说,友元是一种数据共享,它破 坏了类的封装性,因此要尽量少用。

在使用友元时还要注意:(1)友元不具有可传 递性,如BA的一个友元,AC的一个友元, 并不能得出BC的友元的结论。(2)友元关系是 单向的如果B类是A类的友元,B类的成员函数 可以访问A类的私有数据,但A类的成员函数不能 访问B类的私有数据。(3)友元关系不能被继承, 如果B类是A类的友元,B类的派生类不能自动成 为A类的友元。

 常对象和常成员(const) 虽然数据隐藏保证了数据的安全性,但各种

形式的数据共享却又不同程度地破坏了数据的安 全。因此,对于既需要共享、又需要防止改变的 数据应该声明为常量。因为常量在程序运行期间 是不可改变的,所以可以有效地保护数据。

本节介绍用const定义的常对象、常成员和常 引用。

 常对象

常对象是指常类型对象,即对象常量,定义 的语法形式为:

类名 const 对象名(初值); 

const 类名 对象名(初值);

定义常对象同样要赋初值并且该对象不得再更 新。另外,常对象只能调用它的常成员函数,而 不能调用其他成员函数。参见下面的常成员函 数。

常成员 1. 常成员函

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

(1) const是函数类型的一个组成部分,因此在实 现部分也要带const关键字并且可用于对重载函数 的区分。

使用const关键字说明的函数为常成员函数,常 成员函数据说明格式如下:

(2) 常成员函数不更新对象的数据成员,也不能调 用该类中没有用const修饰的成员函数。

(3) 常对象只能调用它的常成员函数,而不能调用 其他成员函数。

 2. 常数据成

const说明的数据成员称为常数据成员。常数 据成员的值在任何函数中都不能被更改,必须编 写构造函数并采用初始化列表的方式进行初始 化。

常引用

函数的参数可以被说明为常引用(const修 饰),则在该函数内不能修改该形参的值。

• •

小结

一般情况下对象在其作用域内是可见的和存在 的对象的作用域、可见性和生存期三者是一致 的,但在同名和加了static后会出现不一致的情 况。

静态成员是类中所有对象共有的,不属于某一对 象的。

友元函数和友元类可以访问类的私有成员,破坏 了封装性,应慎用。

常对象、常成员和常引用一般用于保护对象或变 量的值不被改变。


原创粉丝点击