1 / 32

四、静态成员 五、指向成员的指针

第 16 章 数据的共享和流通. 四、静态成员 五、指向成员的指针. 四、静态成员 extern 在不同的模块中沟通全局变量的外部连接 , static 则充当内部屏蔽作用。 C++ 语言中静态成员属于类内部的合法成员但凌驾于对 象之上。模块之间静态成员具有 extern 的外部连接属性。 a. 静态数据成员 static 变量具有特别惹人垂青的性能: 1). 生命与程序等长的持久性。 2). 维持其原先位置的隐蔽性,禁止外部直接访问。 静态全局变量是内部连接的,但静态成员变量具有外部 连接属性。.

daisy
Download Presentation

四、静态成员 五、指向成员的指针

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第16章 数据的共享和流通 • 四、静态成员 • 五、指向成员的指针

  2. 四、静态成员 • extern在不同的模块中沟通全局变量的外部连接, • static则充当内部屏蔽作用。 • C++语言中静态成员属于类内部的合法成员但凌驾于对 • 象之上。模块之间静态成员具有extern的外部连接属性。 • a.静态数据成员 • static变量具有特别惹人垂青的性能: • 1). 生命与程序等长的持久性。 • 2). 维持其原先位置的隐蔽性,禁止外部直接访问。 • 静态全局变量是内部连接的,但静态成员变量具有外部 • 连接属性。

  3. [例]静态成员变量的声明、定义和使用 • #include <stdio.h> • static long* pa; • class CType • { public: static int data; • CType (int n=1) { m_n=n; data++; } • static void f() • { pa=sa; } • protected: static long sa[ ]; • private: int m_n; • }; • 静态成员声明static long sa[ ]; 相当于原先的外部全局 • 变量连接说明extern long sa[ ];

  4. 静态成员变量的定义和初始化设置: • 1. 定义和初始化不管是公共的还是私有的一律采用相 • 同的格式。 • 2. 定义时不再加static关键字但类域分辨符则是静态成 • 员变量定义的整体部分。 • 3. 定义是唯一的且在文件范围内进行,定义时可以不赋 • 初始值,如同定义全局变量。 • 4. 最好在.cpp部分同时指定初始值,特别定义私有的静 • 态成员变量时。放在头文件的全局范围定义静态成员变量容 • 易导致定义的重复,因此避免这样做是上策。

  5. 5. 不完备的声明语句如[static long sa[];]在定义点需补 • 充足够的信息。 • 6. 在构造函数中对静态成员变量赋值不牵涉静态成员变 • 量的内存分配, 高度警惕对静态成员变量data=const合法的 • 简单赋值,这导致对象构造一次静态成员变量又回归原值。 • 下面是静态成员变量在文件范围定义的格式: • 数据类型 类名::静态成员变量名;

  6. [例] • int CType::data; • long CType::sa [ ]={20,30,40}; • void main () • { CType::data=0; • printf ("%d,static data=%d\t", sizeof • (CType),CType::data); • CType::f (); • printf ("pa[0]=%d,pa[1]=%d, • pa[2]=%d\n",pa[0],pa[1],pa[2]); • } • //输出:4,static data=0 pa[0]=20,pa[1]=30,pa[2]=40

  7. 上面例题中并无具体对象,静态成员变量明显地独立于上面例题中并无具体对象,静态成员变量明显地独立于 • 对象而存在。可以当作全局变量一样在类外通过全限定名操 • 作公共的静态成员如CType::data,也可以通过该类的实例以 • 对象名obj.data方式进行处理。 • 对象名obj.data方式的访问与对象本身的具体属性毫不 • 相干。根据内存数据状态唯一性原则系统最终将其归约为 • CType::data的形式。 • 私有的保护的静态成员变量由成员函数和友元访问。 • 静态成员变量可以用于监控一组成员函数,纪录它们被 • 调用的次数,根据调用次数进行适当的恢复或前进操作。 • 静态成员变量实质上是平移到类中再加上访问控制规则 • 制约的全局变量。

  8. b.静态成员函数 • 静态成员函数没有隐含的this指针,因而不操作类中的 • 非静态成员,因而不能是虚函数。只读成员函数本质上是限 • 定this指针为只读指针。 静态成员函数不含当前类的this指 • 针因而不能是只读成员函数。 • 静态成员函数操作的是静态成员变量、类中的梅举常数 • 和全局变量以及自身入口中的局部变量。 • 非静态的成员函数可以直接操作静态成员函数或全局函 • 数,静态成员函数需要通过对象或对象指针间接操作非静态 • 的成员。

  9. 下面是使用静态成员函数的三个步骤: • 1. 在类中通过关键字static声明类中的静态成员函数 • class CType • { protected: • static double function(int,float,...,long); • tatic 返回类型 函数名(形参列表); • }; • 2. 在类的外部给出静态成员函数的定义,定义时不再加 • static关键字但类域分辨符则是静态成员函数定义的整体部 • 分。 • 静态成员的连接属性根据语言约定是extern性质,但 • inline定义的静态成员函数是内部连接的。

  10. 返回类型 类名:: 函数名(形参列表) • {不含this的语句序列;} • double CType::function (int n,float f,...,long l) • {不含this的语句序列;} • 3.公共的静态成员函数可直接全限定方式调用,就象 • 调用全局函数: • double v=CType::function (n,f,..., l); • 对象名的访问方式也是可行的如: • CType a; double v= a.function (n,f,..., l); • 对象或对象指针调用静态成员函数,与对象的数据状态 • 无关。换言之a.function (n,f,..., l)是全限定访问形式的 • CType::function (n,f,..., l)的一个间接别名。

  11. [例]静态成员对象实质上是全局对象, 静态成员函数实质上 • 是全局函数 • # include<stdio.h> • class A • { private: static A a; int m_n; • A(int n) • { m_n=n; printf ("call A::A ();\t"); } • public: static A& GetStatic (); • int GetNum () {return this->m_n; } • }; • inlineA& A::GetStatic () • {return a;} • A A::a(10);

  12. void main() • { printf ("Here is in main scope\t"); • printf ("m_n=%d\t", A::GetStatic().GetNum()); • A& (*pf) ()=A::GetStatic; • printf ("m_n=%d\n",pf ().GetNum ()); • } • //输出: • call A::A(); Here is in main scope m_n=10 m_n=10

  13. 类中的声明中自身的对象是不许作为成员的。 • 上面A类中具有一个私有静态成员正好是A类的对象, • 但由于static修饰的结果这个对象实际上是一个加上类域分 • 辨符的全局对象,这个静态成员对象A::a是独立于类的具体 • 实例的,是唯一的。 • 静态成员函数实质上是加上类域分辨符和访问控制规则 • 制约的全局函数。 • 因此可以由类型属性为A& (*)()的常规函数指针pf间接 • 调用,而不是A& (A::*)()型的成员函数指针。

  14. 五、指向成员的指针 • 指针是用于管理内存数据的变量,指向成员的指针分两 • 种:一种是指向成员函数的指针,另一种是指向成员数据的 • 指针。用type,t1,t2等表示类名。 • type,t1,t2等可以是int,long,float等也可是结构名等, • 用CType表示类类型名 • 1.指向数据成员的指针 • 指向成员的指针是C++新引进的,C语言意义上的指针 • 称为常规指针或简称指针;指向成员的指针简称为成员指针.

  15. 静态数据成员是独立于对象的类的全局变量,因而指向静态数据成员是独立于对象的类的全局变量,因而指向 • 静态数据成员的指针是一个常规的数据指针。 • 定义指向数据成员的指针的格式为: • type CType::* pm; • 类名 类类型名::* 指向数据成员的指针 • 指向数据成员的指针pm的类型为type CType::*,而 • 常规指针的类型为type*,两者的差别在于类域分辨符 • CType:: • 如果CType类的声明里存在两个type型的成员变量, • 这个指向数据成员的指针pm可以指向其中之一。 • class CType { type m_t1; type m_t2; };

  16. 指向成员的指针可不在类的声明中,访问控制属性仅在指向成员的指针可不在类的声明中,访问控制属性仅在 • 该指针与其成员关联时起作用。 • 公共的成员可在当前类的外部如全局函数中赋给指向成 • 员的指针。 • 私有的或保护的成员可在成员函数或友元函数中与指向 • 成员的指针关联,而不在外部环境赋值。 • 一经关联编译器就难以限制指向成员的指针对成员访问 • 控制属性的挑战。 • 对于CType类特定的对象obj, type*型的指针p指向 • type型成员的格式是: • p=&obj. m_t1; • 在成员函数内部p的关联格式是: • p=&this->m_t1;

  17. type*型的指针指向特定对象的数据成员,指向成员的 • 指针指向待定对象的相对偏移。 • 如下语句进行了指向数据成员的指针和类的成员变量的 • 关联: • 成员指针名=&类名::数据成员名 • pm=&CType::m_t2 • //此关联式中不含对象 C++引进两个运算符访问指向成员的指针,一个运算 • 符“.* ”是对象访问成员指针运算符,另一个运算符“->* ”是 • 对象指针访问成员指针运算符。 • 星号"*"右边是成员指针。 • 圆点"."左边是对象名,箭头"->"左边是对象指针。

  18. 下面是索引指向数据成员的指针的格式: • 对象.*成员指针 • obj.* pm • //对象obj访问成员指针pm 对象指针->*成员指针 • pObj->*pm • //对象指针pObj访问成员指针pm • this->*成员指针 • this->*pm • //this指针访问成员指针pm

  19. 对于类型为type CType::*的指针pm,表达式 • obj.*pm(或pObj->*pm, this->*pm) • 是type型的左值; • 如果type表示int,则obj.*pm是int型的左值,如果type • 表示double*型,则obj.*pm是double*型的左值。 • 对于对象a,b和对象指针p,q; • 当[pm=&CType::m_t2;]时,则[a.*pm;b.*pm;]等价于 • [a.m_t2; b.m_t2;] • 当[pm=&CType::m_t1;]时,则[p->*pm;q->*pm;]等价于 • [p->m_t1;q->m_t1;]

  20. 2.指向成员函数的指针 • 指向成员函数的指针简为成员函数指针。 • 成员函数指针是将常规函数指针平移到类内的产物。不 • 失一般性以两个参数为例,常规函数指针的定义格式为: • type (*pf)(t1, t2 ); • 类型 (*函数指针名)(类型1,类型2); • pf是具有类型属性为type (*)(t1,t2 )的函数指针。 • 在常规函数指针前冠上类域分辨符CType::就得到成员 • 函数指针的定义格式: • 类型 (类类型名::*成员函数指针名)(类型1,类型2); • type (CType::*pfm)(t1,t2 );

  21. 如上语句定义一个类型属性为 type (CType::*)(t1,t2 ) • 的普通又奇异的指针pfm。 • 成员函数指针可独立于对象而存在,但同时又必须指向 • 成员函数,成员函数具有访问控制属性,而超乎其外的成员 • 函数指针并不全然理会私有禁锢的制约。 • 在初始化成员函数指针时编译器设置一道防线维持内部 • 访问控制的约束机制: • 如果成员函数指针指向私有或保护的成员函数,初始化 • 可在友元或成员函数中进行。 • 如果成员函数指针指向公共的成员函数,初始化可在全 • 局范围或全局函数中进行。

  22. 指向静态成员函数的指针是常规的函数指针。 • 指向静态成员和变量如obj.m_t的常规指针和指向成员 • 的指针初始关联时存在相同的约束,在可访问的环境获得初 • 始值后, 常规指针和指向成员的指针就可以在外部实施对 • 成员的间接访问。 • 成员函数指针一经赋值,该指针则可以在外部实施对成 • 员函数的间接调用。 • 因此指针是解除内部封装的有力手段。

  23. 成员函数指针的初始化语法格式为: • 成员函数指针名=类名::同类型的成员函数名; • pfm= &CType::f; • 成员函数f具有与成员函数指针相同的类型属性即函数 • 原型的全限定形式为: • 返回类型 类名::函数名(类型1,类型2); • type CType::f (t1, t2 ); • 同全局函数一样取地址运算符&是可选的,亦可在定义成 • 员函数指针时就赋初值: • 类型 (类名::*成员函数指针)(类型1,类型2)= • 类名::同类型的成员函数名; • type (CType::*pfm)(t1, t2 )= &CType::f;

  24. 成员函数通过对象名或对象指针来调用,成员函数指针成员函数通过对象名或对象指针来调用,成员函数指针 • 的使用格式为: • (对象名.*成员函数指针)(实参1,实参2) • (obj.*pfm)(v1,v2) • (对象指针->*成员函数指针)(实参1,实参2) • (pobj->*pfm)(v1,v2) • (this->*成员函数指针)(实参1,实参2) • (this->*pfm)(v1,v2) • 当[pfm= &CType::f;]时,间接调用(obj.*pfm)(v1,v2) • 相当于直接调用obj.f(v1,v2)。实参v1,v2应与类型t1,t2匹 • 配。 • 返回类型确定函数调用的使用方式。 • 规定成员函数指针不指向构造函数和析构函数,即 • pfm=&CType::CType是非法的。

  25. 由于成员函数指针的类型书写起来过于冗长,因此指定由于成员函数指针的类型书写起来过于冗长,因此指定 • 一个成员函数指针的别名就是自然的事情,从定义成员函数 • 指针的格式前在冠一个typedef关键字就得到类型的别名: • type (CType::*pfm)(t1,t2); • typedef type (CType::*PFM)(t1,t2); • PFM是类型type (CType::*)(t1,t2)的一个别名。 • 由此可以定义成员函数指针或数组: PFM pfm, pfmn[5];

  26. [例]指向数据成员的指针,静态成员函数的地址属性同等于[例]指向数据成员的指针,静态成员函数的地址属性同等于 • 全局函数的地址属性 • #include <stdio.h> • class CType • { public:static void Setpm (int CType::* & ,int k) • void Set (int CType::*& pm,int k) • { Setpm (pm,k); this->*pm+=k; } • CType (int x=10,int y=20) • { m_t1=x; m_t2=y; } • void Show() • { printf ("m_t1=%d,m_t2=%d\t",m_t1,m_t2); } • public: int m_t1; • private: int m_t2; • };

  27. void CType::Setpm ( int CType::*& pm, int k) • { if (k==1) pm=&CType::m_t1; • else pm=&CType::m_t2; • } • void (*Setpm)( int CType::*& ,int)= CType::Setpm; • void main () • { int CType::* pm; • CType::Setpm(pm,1); CType a; • a.Show(); a.*pm+=10; • Setpm(pm,2); • a.*pm+=20; a.Set (pm,1); a.Show (); • } // 输出:m_t1=10,m_t2=20 m_t1=21,m_t2=40

  28. [例]指向成员函数的指针 • #include <stdio.h> • class CType; • typedef int (CType::*PFM)(int); • class CType • { public: static void Setpfm (PFM & pfm,int); • CType (int x=0) { pfm(x); } • void Show() { printf ("m_x=%d\t",m_x); } • int pfm (int x) { m_x=x; return 2; } • private: int Add (int x){m_x+=x; return 1; } • int m_x; • };

  29. void CType::Setpfm (PFM & pfm,int num) • { switch (num) • { case 1: pfm=&CType::Add; break • default: pfm=&CType::pfm; break; • } • } • int (CType::*gpfm) (int)=&CType::pfm;

  30. void main () • { CType* pthis=new CType (); • (pthis->*gpfm)(10); pthis->Show (); • PFM pfm; • CType::Setpfm (pfm,1); • (pthis->*pfm)(20); • pthis->Show (); • CType::Setpfm (pfm,2); • (pthis->*pfm) (3); • pthis->Show (); • pthis->pfm (4); • pthis->Show (); • }

  31. //输出:m_x=10 m_x=30 m_x=3, m_x=4 • 说明: • 上面的程序定义一个名为pfm的指向成员函数的局部指 • 针,在类中存在一个名为pfm的成员函数。对于成员函数指 • 针pfm的访问格式为: • (pthis->*pfm)(3) • pfm右边紧贴右圆括号左圆括号对“)(”是必不可少的。 • (pthis->*pfm)(3)是对于指向成员函数指针的间接调 • 用, pthis->pfm (4)是直接调用成员函数pfm。

  32. 请打开"第17章(1).ppt"

More Related