类内静态函数和全局静态函数的相同点和不同点

上一篇 / 下一篇  2012-08-14 11:01:50 / 个人分类:杂谈

 1)全局静态函数只在本编译单元有效。51Testing软件测试网O9R#ALc?{%J+vV4V-^

  2)类静态函数,对比普通成员函数,没有this指针,不能访问非static成员。51Testing软件测试网 P4MtJ t)ns

51Testing软件测试网RHd*L)KZ#?%t.v q

  3)要说二者相同点,都是c++名字控制的手段:全局静态函数被局限在一个编译单元,通俗的将就是在一个cpp文件中定义的全局静态函数在另一个cpp文件中不能被调用。例程如下;51Testing软件测试网1G Ug:aO7OT

51Testing软件测试网&?r)I;TS;cS)@ c

51Testing软件测试网 r/['\~%}lXW2kNi

//   main.cpp51Testing软件测试网]EQ}&C n*dE
#include   <iostream>
:a&\lY3m}n\0extern   int   hello2();51Testing软件测试网@.pY$j f
static   int   hello()51Testing软件测试网%~kO%KH/i
{51Testing软件测试网9[.?FSs0f8p$l
        std::cout   < <   "hello,   world! "   < <   std::endl;
Re_?-] o x;i-b0        return   0;
:_ Bi5^ o0}
}+WrC'U ]0int   main()
.b K4B/]Q^0{51Testing软件测试网0~AKt3|?
        hello();
3xR@ZW0        hello2();51Testing软件测试网 a1d1R1h`u~
}51Testing软件测试网.z(s9l1GX:^2R
//   append.cpp51Testing软件测试网[ v5gz'o Sp
extern   int   hello();51Testing软件测试网9o R&F7H6t![6f9yf
int   hello2()
_'E{!f:o1O y0{51Testing软件测试网t9tYW3JYX6b
        hello();
"uHW{ uF ?y,N0}51Testing软件测试网 o3d&c y0vf};w
//---------------------------------------------
51Testing软件测试网 L4r1okX ~*djp SO

  编译将产生错误:

,^%ekmHHAM0

w1je$Hc"hF0  append.obj   :   error   LNK2001:   unresolved   external   symbol   "int   __cdecl   hello(void) "   (?hello@@YAHXZ)
}9f/U$D gE\0  Debug/Test.exe   :   fatal   error   LNK1120:   1   unresolved   externals
51Testing软件测试网'PG-S i9kvu8I

51Testing软件测试网 [@8b-a;]#^ H-s

  而把hello前面的static去掉之后就可以编译成功了。51Testing软件测试网'C/W"h3X&J(try _d p

E+z.V"NK|4o0  可见不能在append.cpp中调用main.cpp中的全局静态成员函数。

#W"gcy_0

^ Z)jVODOR0  而类静态函数,必须使用其“类名::静态函数名”51Testing软件测试网)s*N.}2Y{e1Yo3HE

51Testing软件测试网R q/s }8z }C~*?

6DW:k@P7AQ#zN[0
#include<iostream>
*M7T"g'F!dLv c0using namespace std;
"krTq J;Z c0class A51Testing软件测试网x3|7Kj$@2O:{I2?
{
A-q y*MkEZ%u*Ra0 public:
u9G{WeuK0 static void fun(int x)
Q;t9OpFO0]3\RB0 {51Testing软件测试网AfwJx0pf2A E)C
  51Testing软件测试网v0B k~N|1k%b
  cout<<x<<endl;51Testing软件测试网xDmf_9o
 }
^ {A ^(K(i:fO0};
ScztgI0int main()
Bp`N f,]Vo0{
J q N4Io4Y;^0 A son;
-YqMge6k3[0 son.fun(5);51Testing软件测试网(d/E0N*u1A0|#y EJ-a-p
// A::fun(5);
hc3b] H wt?|0 return 0;
L6K6q-Lqs0}
51Testing软件测试网1so+f8e$f)JJQx p7K

  编译虽然会出结果,但是有一条警告,son未引用的局部变量,说明静态成员函数不可以用对象调用的。但是至于为什么会输出正确结果不太理解,望高手指教。也有待进一步研究。用//注释起来的也可以输出正确结果。

~{5oD|n4N"uAy0n051Testing软件测试网 C1kNi u%Wq|

  我们把函数和变量声明为静态的有什么优点那,从静态变量的角度看,更容易理解一些。51Testing软件测试网P)d7hCHd G;Y

51Testing软件测试网8`s0S V[.s

  使用静态数据成员可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值 对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,就可以保证所有对象都能够访问到被更新后的值,这样可以提高效率和节省内存 空间。这是静态变量的优点同时也是他的一个缺点,在类中声明了静态变量,无论用户使用使用这个类,而这个静态变量都会申请他需要的内存容量。对于多线程的 情况下,访问静态变量我们需要加一些异步机制,防止多个线程同时修改静态变量。

]T1k8[8B3f1vDJE0

OGm5z ET8k6[+P0  类内静态函数比全局静态函数的用处要多的多,在这里先讲简单的51Testing软件测试网 q2r8]7{3Z)~

51Testing软件测试网6]&F[!j{}f"i

  全局静态函数的应用比较常见的就是51Testing软件测试网-I"i9~;Ox[

ou5y*_9Xf t051Testing软件测试网VO!z1{ a

static   int   fun()
1l4sIr8f Y0{
OFPn$@8]%R'f0...;51Testing软件测试网;E,g'G8^,}Wk1J
return   1;
6u ~4}$[2vS0}

UoC9dx+j ^0  当我们希望在多个类中调用fun函数时,我们必须把fun声明为static类型,不然在link时编译器会发现多个关于fun的定义。这种函 数的应用,多少带有C的色彩,尤其当我们在C环境写好的函数,移植到C++中时,需要在函数前面需要加上static,而如果我们需要移植多个函数时,更 通用的一种方法是使用未命名名字空间51Testing软件测试网7dt(D$Q;| y;e-vG|

51Testing软件测试网@&AQYM"D_!}

51Testing软件测试网3[ g-Srj6@8`3\tK%S

namespace{51Testing软件测试网*g:A'Z t@P!A.]
int   fun()
*W$me5v'B4Gef0{
vO0B5R%qwK0...;
&OPC~4_yw*A0return   1;51Testing软件测试网.]`f/r wS O
}51Testing软件测试网SRx;@2v4ba2D i
51Testing软件测试网g$c(V8p9\!^_&J,w
}

G_x.B?V0  也许有人问如果在未命名名字空间中的函数再加上static修饰符号会怎么样?这个就完全取决以使用的编译器,可能会直接报错,也可能可以编译并正常使用。不过这样写,代码从语言层次上就很难移植编译环境,所以尽量不要这样写。

@ cR7M)UsH0

c}C)^7V$?0  关于这样的应用,在我从前的项目中实施过。当时我需要定义很多函数,执行三角形,已经像素转换方面的计算,所以把这些函数声明为static的。51Testing软件测试网G+b|&`6|F

51Testing软件测试网#_BC r4Y[%s

  对于与全局静态函数,我们继续类内静态函数和静态变量的讨论,我想他们的应用是两者区别的最好体现。

6_"]M-Z kSY0

1Tkw {V1w0  对于类内静态变量,我们需要在类外初始化,这是在使用静态变量需要注意的地方,有些初学者很容易在这里出错。类内静态变量使用最多的就是计算类的实例化个数。51Testing软件测试网 ?M&Q*n ]L$@

51Testing软件测试网EF o0?T

51Testing软件测试网 \Gz:Z*T&}

class   A51Testing软件测试网w5n;~qYfH4M p)I
{51Testing软件测试网 L~T;od,|vG8z
static   int   i;   //   外部初始化为051Testing软件测试网%Mr nLl^F
public:51Testing软件测试网Ix1iIqk ]
A()   //   构造函数51Testing软件测试网-[:{!xH:_KZ
{51Testing软件测试网a#S,T[8{t0m7z|
++i;51Testing软件测试网 Wy"\`'l ~-Cv
}
\ D5Rf V8B(o%~1f-z1K0~A()   //   析构函数  
2Wg:^.}G {x.o3fA0{51Testing软件测试网#h(~BK3~ |&R tla
--i;
g d4[{0Zb1t,XS$T#F0}
SReIJ!})FS9r-ruS.A0static   int   CreateObjectNumber()   //   或者创建对象的数目
&Kh@uG6y"jL0{
UoRs7x%{m7y0return   i;
YAn%j-Ki0}
Dui.K1H a i"d5p0};
51Testing软件测试网*k}K`4XR,?

  也许读者认为这种方法,只是用来学习而已,实际很少使用。我不赞同这个观点。51Testing软件测试网 oP ^C)tO1dF

51Testing软件测试网F&Kb!A0T

  1:静态变量受public,protected   ,private限制,也就是如果静态变量是protected或者private类型的,在类外不能访问,比如51Testing软件测试网2Qb+g&Y{.F}7k8o

Z)KY5c$uG} YF6H$Y0  A::i是错误的51Testing软件测试网r;y~E#mJ0Gg

:lM:YV;o7?)I7B0  这条规则同样适用于静态函数

8O2t,\ lst$vE0

+[2x8|_ki0  2:静态变量在类内声明,而必须在类外初始化,模版类中应用也是这样。这里我们在static后面加上const类型,可以直接初始化。比如51Testing软件测试网 Z&xy'mLVN#z

51Testing软件测试网W b7K/dgq&mz

51Testing软件测试网7N;Rc8?$z&v

Class   A51Testing软件测试网"K-J5\2OM v!O4U*A ^[
{
,~L9{hc9o-DX9g0//   Static   int   I   =   5;   //   error
/|:g]Ji-yM0Static   const   int   I   =   5;   //   ok
pJ6oM}h!z7M$Z0Int   m_list[I];51Testing软件测试网 Y7A6W8G!y f PgU(T"\
}

cn&@XOthiYxC0  而这里I的应用也无非是Int   m_list[I];

WH2RN8A0

4L.t:d3e#W0  3:静态成员函数只能访问类的静态变量,而类的成员函数也可以访问类的静态变量,这样就可以通过静态成员变量建立类的静态成员函数和类对象的关联关系。51Testing软件测试网%p0H1M%H&j+{ u

+tN Un{8N(Z/{4@z0  4:还存在一种静态变量,他不是全局静态变量,而是函数内的静态变量,如下例中的i,这算是对全局静态变量的一种补充。

{/gp~@&[+FjAG0

/|:L`&lU0

_e9nl:e ]'i7V6d0
int   fun()51Testing软件测试网c}v*a"@2lm&_Z
{51Testing软件测试网I$n;{7wK?
static   int   i   =   3;
PIgU'DND;G K0++i;
tzlIF9U@0return   i;51Testing软件测试网O9G2~kS4J
}
51Testing软件测试网1V a X1o{

  这种方式的好处时,只用调用fun函数时,静态变量i才申请内存,这也符合lazy   evaluation的设计要求。只有当需要时,才去申请。

M*y'c5_.k+Q&C051Testing软件测试网Jly`BES.a

  同样作为破坏封装的一种技术应用是友元函数或者友元类的应用,很多人形象比喻这种方式是在封装的物体上开了一个小小的洞,不提倡使用这种技术。 其实任何技术都有他应用的场所,不然就不会出现这种技术。不过不去了解这种特性,也许永远我们不会知道这些技术的重要性。碰见这些技术也只会使用有色眼镜 去看。友元函数的特征基本如下

4l:u+So?v5jS%mh0n j051Testing软件测试网l*\}gt

  1)必须在类的说明中说明友元函数,说明时以关键字friend开头,后跟友元函数的函数原型,友元函数的说明可以出现在类的任何地方,包括在private和public部分,不受private限制

(Q P7[7xj']DBb0

*mz#~)s.a BW;T3gV0  2)友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用 ":: "指示属于哪个类,只有成员函数才使用 ":: "作用域符号;

\s\ c+i Sg0

"\{in#K-t0  3)友元函数不能直接访问类的成员,只能访问对象成员,所以在调用友元函数时,确保友元类的必须实例化。

7h5GE"JJ&vP&P RZb ^0

I2~ xG8p,Hr iT[0  4)友元函数可以访问对象的私有成员,但普通函数不行,这个需要注意,尤其是在友元类中,有时候发现两个类互相为友元类,确不能调用成员函数,就是这个原因。

8[+|!_5F*_d0

*?*zy?$@R"\f {d9KJ0  5)调用友元函数时,在实际参数中需要指出要访问的对象,也可以把对象声明为全局对象而在友元函数中调用,当然在友元函数中可以调用其他全局函数,或者实例对象等操作。

$Kz3m0i!}*`2Q3N0

,n4h*R M/gGW.BY0  使用友员函数最大的优点就是,不用对类中的每个变量写Get/Set接口函数。尤其是当类中有大量的私有成员变量,而又不想为每个变量设置接 口,同时又需要外部的某个函数调用。这样最好就是把这个函数声明为友元函数,我们在一些开源项目中很常见这种技术,比如阿agentx++。51Testing软件测试网f{4T cVQ^g

51Testing软件测试网4D k2^]"QE0xlO

0rS[(N`$w2q9{0

*xcGD(D\ v:H!X0class   AU
7u)Gu5B B(AH'N!D0{
5hD?%Fn0public:51Testing软件测试网5v9X }s^hWzH
AU(){
ssux_rS(xB0};
b9W]Oe:Fm"B4`0string   GetAU()
Z5hp0y-|0{
2w#Ii"L&q8\f0return   "Base--GetAU ";
6A5C7lby6e-mF0}
4u wGDb"U-Z0virtual   string   GetAUU()51Testing软件测试网&^Hn5t:l Y(_!dki
{51Testing软件测试网 `:gk/J,v'L R
return   "Base--GetAUU ";
$Ey WcC\E5p,j0};
[}$W,u#QE)_0virtual   ~AU(){};
-Af KN] V0};
51Testing软件测试网3Q O7S'CY+|~)R

aG+Pmeqr;G5T0template   <class   T,class   TBase>51Testing软件测试网:iCr(U AdW
class   TEMU:public   TBase51Testing软件测试网} T0lg^0@%_S4k
{
}~YO,A \0public:51Testing软件测试网D ~lRzc
string   GetAA()
iRa$Xd;`U]8Vuw0{
#~ c8B~+f7_8O i0T*   pt   =   static_cast <T*> (this);
y_z @7?_bo`0return   pt-> GetA();   //   这里调用的是static   string   GetA()函数51Testing软件测试网q9`N nYCY-p_7w
}

xG t ar_051Testing软件测试网[ ]6_Hn&b g

string   GetBB()51Testing软件测试网%w;puG K*sS
{51Testing软件测试网6w(? bt\k
T*   pt   =   static_cast <T*> (this);51Testing软件测试网'o'{ON eIl
return   pt-> GetB();   //   这里调用的是string   GetB()
ZD.e1Ns]0}

LG O%\-Af r0

TV*i4qiB oeZ8w/jA0public:
;e i-x,R:WK(d0string   GetA()51Testing软件测试网!Qy uI;[zbC/e8L
{51Testing软件测试网QG5hR]D!CJ;[f!gP
return   "TEMU   -   GetA ";51Testing软件测试网n d5QHC9W&_q/o
}

6Y)u~ Se0

k Q+rVU1{w0string   GetB()51Testing软件测试网!v7M8o#^8z4IU:EGb g
{51Testing软件测试网1Q/Dj^zJ
return   "TEMU   -   GetB ";51Testing软件测试网D1Zt:D:m&b
}51Testing软件测试网z9B.xKg
};

E+Y7M7L YU {051Testing软件测试网:?"Ovq#E1_A7A'Ww

class   DeriveTEMU   :   public   TEMU <DeriveTEMU,AU>51Testing软件测试网%ops;S0P2c!P+@tmY
{51Testing软件测试网^0G"H AP)X*}? n
public:
*R xc*B&y0static   string   GetA()   //   注意这里是静态函数
B7ui*k \%ii0{
,fP@ c~ d$P0return   "DeriveTEMU   -   GetA ";51Testing软件测试网hfH0_'l
}51Testing软件测试网8]-g%lK7M7A)x(mr){${
string   GetB()
3\W.w(v)VR&K0{
h6u(JyZ6?T:C5Z0return   "DeriveTEMU   -   GetB ";51Testing软件测试网0u1}8}k/z/V!i&o/O+[p
}
']V"y VJ;kD*p0};

IZ-H!RE S0
51Testing软件测试网[x#B R w9~

  测试用例51Testing软件测试网&~ P4n@$a*Y

51Testing软件测试网1LYt#y7L

  DeriveTEMU   u;51Testing软件测试网(Z$\:iUMWJK
  TEMU <DeriveTEMU,AU>   *p   =   &u;51Testing软件测试网 H*rM.C3M p7d{{
  cout   < <   p-> GetAA()   < <   endl;
D$DOl{EA0  cout   < <   p-> GetBB()   < <   endl;

h fe{1U R*o%Wr`4S0

pWw8O.x |?0  输出结果

U+M6s5E@b/O0C0

)q2mZ[7G1~/f6T0  DeriveTEMU   -   GetA51Testing软件测试网7i@ec0e \9CK-{ X
  DeriveTEMU   –   GetB

8s'iO J2DRI5p051Testing软件测试网2[X G!r9nb\

  在这里我们看到,调用类内静态函数的方式并不是简单的类名::函数的形式,而是通过模版父类调用子类静态函数,同样也给出了,调用普通函数的方 式。这种机制可以理解为模版继承关系中的虚继承关系。当认识到模版中的静态函数使用,也许会更大的改变我们对静态函数的印象,这种机制在ATL,WTL中 有广泛的应用,几乎每种涉及到消息影射关系的类中,都使用这种方式。

%{/lW;m1Uz/a_k}:H0

TAG:

 

评分:0

我来说两句

Open Toolbar