每周一贴:类内静态函数和全局静态函数的相同点和不同点?
最近很长时间没有上CSDN,忙于工作。既然担任C++语言的版主,也要为C++fans做些贡献,所以从这周开始,每周在CSDN上发布一个论题,供大家讨论,共同学习,并能从更深层次发掘它的应用,每个议题站在不同的角度考虑时可能会很简单,简单,也不要嗤之以鼻;也可能会很难,难,也不要放弃;每周一贴的目的是整理出来在各个角度看待问题的观点,深刻的了解议题中讨论问题的应用环境,到周末时我将整理大家的讨论,贴出来供初学者学习。
本周议题:类内静态函数和全局静态函数的相同点和不同点?
讨论范围:类内静态函数的声明定义,全局静态函数的声明定义,函数在内存存储位置,堆栈不同,在继承关系中静态函数的调用,在应用模版类中,类内静态函数的特点(构成,存储,应用),模版静态函数的特点,对比类内普遍函数,对比friend函数,对比全局函数的各自有什么不同,可调用的变量范围,全局变量,静态变量,类内变量的不同,类内静态函数和全局静态函数的功能侧重点是什么?平时接触的技术,代码,应用到静态函数(类内,全局)例子,其优缺点。静态函数在设计模式中的应用,静态函数的与何种技术搭配可以发挥更大作用等讨论。
由于个人技术和能力以及阅历不可能面面俱到静态函数的每种应用,只能用一个等字概括未列举的应用。
未尽事宜,敬请补充;
本贴原则上禁止mark,up之类的回帖,同时为了调动大家参与的积极性,放分100,以奖励那些有独特见解,观点新颖的回帖。
问题点数:100、回复次数:46Top
1 楼Muf(沐枫)回复于 2006-10-23 16:19:00 得分 0
全局静态??没听说过。Top
2 楼Kusk(Kusk)回复于 2006-10-23 16:21:15 得分 3
其实两者没有太多关系,只不过恰好都用了static这个同一个关键字而已。把其中一个改成别的,
就没什么问题了。C++的static在不同的场合下被不同地使用,这点本是设计上的不足,而绝不是
鼓励我们去死挖它们之间的联系。不建议太死抠这些东西。Top
3 楼weijiangshanwww(天气预报:今天会下分,偶尔下几颗星星!)回复于 2006-10-23 16:21:27 得分 2
静态成员函数
静态成员函数和静态数据成员一样,它们都属于类的静态成员,它们都不是对象成员。因此,对静态成员的引用不需要用对象名。
在静态成员函数的实现中不能直接引用类中说明的非静态成员,可以引用类中说明的静态成员。如果静态成员函数中要引用非静态成员时,可通过对象来引用。下面通过例子来说明这一点。
Top
4 楼Jokar(贪睡鼠)回复于 2006-10-23 16:21:48 得分 3
本来是想听 ugg版版 讲课的~ :)Top
5 楼weijiangshanwww(天气预报:今天会下分,偶尔下几颗星星!)回复于 2006-10-23 16:22:51 得分 3
一个函数用了 static 修饰,
则标志这个函数是 局部的,
除了该文件内使用, 其他文件不能用!
Top
6 楼ckt1120(坏人一个,切勿联系)回复于 2006-10-23 16:24:30 得分 3
类内静态函数只能被类和该类对象被调用,其处理的数据是类的静态成员变量.
全局函数可以被任何函数调用.
Top
7 楼wanfustudio(雁南飞:知识之败,慕虚名而不务潜修也)回复于 2006-10-23 16:28:28 得分 10
都是共享
一个是全局共享
一个是实例共享
-----------
感谢楼主赏分~Top
8 楼sinall()回复于 2006-10-23 16:33:14 得分 10
呵呵,支持ugg!支持楼上各位观点。
1)全局静态函数只在本编译单元有效。
2)类静态函数,对比普通成员函数,没有this指针,不能访问非static成员。
3)要说二者相同点,都是c++名字控制的手段:全局静态函数被局限在一个编译单元;而类静态函数,必须使用其“类名::静态函数名”Top
9 楼ugg(逸学堂(exuetang.net))回复于 2006-10-23 16:44:45 得分 0
TO:Kusk,可能你比较关注程序设计方面的问题,那么不妨从设计角度谈谈static函数的应用,
比如说static函数在singleton模式中的应用?
TO:sinall,说得不错。
我想举一个反例
class
{
static int fun();
}A;
对于没有类名的class,在他的里面写静态函数如何调用,有没有意义?
其实这里我也不鼓励大家在写程序的过程中去死扣每个概念,毕竟时间不允许。
而平时对技术细节比较了解,并不断地积累,那么当我们设计程序时可以非常
放心的在项目中使用这项技术,而不用再次去摸索,去实践。
对于代码的编写,我认为细节决定成败。Top
10 楼dreamXren(追梦人)回复于 2006-10-23 16:48:46 得分 5
呵呵,就个人理解,全局静态函数和类的private成员函数要更接近些。
按照C++的思想,觉得使用private成员函数要好过全局静态函数。
(当然目的都可以实现,方式不同而已)Top
11 楼genius_hb(本人很差)回复于 2006-10-23 17:52:35 得分 5
差别不是太大吧,类内的静态函数可以用类对象调用而已,然后由于类的封装,给静态成员函数的访问加上了控制手段(通过放置静态成员函数到不同的访问级别段中),加上友元,可以实现对类的静态函数进行访问控制,而全局静态函数的控制可能就是文件级的吧。
Top
12 楼blue_zyb()回复于 2006-10-23 18:11:23 得分 5
我想举一个反例
class
{
static int fun();
}A;
对于没有类名的class,在他的里面写静态函数如何调用,有没有意义?
----------------------------
用A.fun()就可以调用了吧,但想了半天没想出这种用法的用途,lz指教一下。。。Top
13 楼Muf(沐枫)回复于 2006-10-23 20:14:49 得分 0
楼上的楼上的楼上...
既然说是局限于文件内,那怎么能说是全局的。楼主有点扯蛋。Top
14 楼ugg(逸学堂(exuetang.net))回复于 2006-10-23 21:00:04 得分 0
扯淡也好,谈论也好,只要有人认为好就行。
C++方面的讨论向来不缺少人身攻击,也是C++版的特色。
所以,对于这样的回复,我的态度是不理睬。Top
15 楼lw1a2(一刀 现在改六点下班了:()回复于 2006-10-23 21:15:50 得分 10
1.对于全局静态函数:限定于文件内部,是继承了c用法,那时没有命名空间的概念。不知道全局静态函数还有别的什么用法
2.类内静态函数:独立于类对象存在,不能访问this指针;
避免不必要对象的产生:把类的静态对象移到函数里,然后返回它的引用,没有的对象产生的时候,不产生那个静态成员;
单一模式里用来控制对象的产生。
想不出UGG举的那个匿名类干吗用,我没见过
PS.这样挺好,每周讨论。如果一些QQ技术群能这样更好了,避免成天讨论MM。可惜没有多少人能撑起来,有能力的人又没空Top
16 楼snwcwt(风舞影天)回复于 2006-10-23 21:20:25 得分 5
类内静态函数和全局静态函数应该差别不大,在编译成二进制上我估计应该是一样的,不同的是他们的访问权限控制,但如果你要用汇编去违背C++的语法规则调用应是可行的。类内的静态函数Singleton的应用算是比较广泛的了吧,不过其他例子就没看到过了
而全局静态函数很少用,也不知道能用在什么地方或是什么技巧,希望有经验的大大们赐教一下!模板的静态,实际上应该是编译成几份二进制代码,在调用的时候,根据调用的代码编译器分析出后调用相应地址的静态函数~~猜测成份过多,有错请指正Top
17 楼ugg(逸学堂(exuetang.net))回复于 2006-10-23 21:23:34 得分 0
class
{
public:
static int fun();
}A;
此时的fun()函数可以认为是static函数退化为类内成员,所以调用方式是
A.fun();但是其实质还是静态函数,一样不能调用类内成员函数。
其实无类名实例,与普通类事例有很多不同特征,在以后的讨论中希望有机会
深入讨论一下
其实这种类,在C++已经有定义,定义为metaclass(元类)
当希望类只有一个实例时,可以考虑使用元类Top
18 楼wanfustudio(雁南飞:知识之败,慕虚名而不务潜修也)回复于 2006-10-23 21:35:03 得分 0
顺便学习~Top
19 楼blldw(how)回复于 2006-10-23 21:48:35 得分 10
其实对于类内的静态成员函数,就知道其内部不含有this指针,而类内的所有非静态成员及函数前都含有一个隐含的this指针,因此静态成员函数不能调用类的非静态成员;再则调用静态函数的时候只能通过 类名::静态函数名 的方式调用;至于全局静态函数应该像大家所说的只在本单元编译有效吧,不能再被其他编译单元(cpp)调用。
例:
// -------------------------------------------
// main.cpp
#include <iostream>
extern int hello2();
static int hello()
{
std::cout << "hello, world!" << std::endl;
return 0;
}
int main()
{
hello();
hello2();
}
// append.cpp
extern int hello();
int hello2()
{
hello();
}
//---------------------------------------------
编译将产生错误:
append.obj : error LNK2001: unresolved external symbol "int __cdecl hello(void)" (?hello@@YAHXZ)
Debug/Test.exe : fatal error LNK1120: 1 unresolved externals
可见不能在append.cpp中调用main.cpp中的全局静态成员函数。Top
20 楼lotomer(lotomer)回复于 2006-10-24 08:45:38 得分 0
学习Top
21 楼blue_zyb()回复于 2006-10-24 09:53:17 得分 2
其实这种类,在C++已经有定义,定义为metaclass(元类)
当希望类只有一个实例时,可以考虑使用元类
-----------------------------------------
我昨天也想到了“希望只有一个实例时”可以采取这种用法。
可是该静态函数fun不能访问对象A的任何数据(也就是非static的数据),如果访问static的数据又无法在类外部进行定义(因为没有类名)。那它还有什么用?Top
22 楼hxblvc(还是好好学吧...)回复于 2006-10-24 10:41:08 得分 2
static 这个关键字用的太混乱了.
静态成员函数和静态全局函数基本上没什么相关性.
学习...Top
23 楼qxbnit(蓝灵)回复于 2006-10-24 10:49:58 得分 2
....
啊,这个我只能从纸面上理解
或者从java的角度理解
C/C++中好象有点混乱
好象static有时还充当private的角色Top
24 楼lin_style(﹏.贾诩(某人语:矮子也高潮))回复于 2006-10-24 21:14:04 得分 5
static很明显的作用就是解决了全局部名字空间的问题,全局变量是一处定义多处修改的也确实解决了不少问题,但这对面向对象程序思想是相抵触的,它破坏的良好的封装性而对于这些缺点的,正是static能够解决的问题,我们可以在函数,结构,类中定义静态对象,当将变量定义为static时,编译器就会将变量的存储在程序的静态存储区(数据段)域而非普通的函数分配的栈空间上。其次,static会将其修修饰的变量对象的可见性限制在本编译单元内(也就是后所以的具有文件作用域,即全程变量可以再说明为外部变量(extern), 也就是指跨文件作用域,被其它源文件使用, 而静态全程变量却不能再被说明为外部的, 即只能被所在的源文件使用。),使它成为一个内部连接。这与普通全局变量加入”extern”可以在多个文件中使用是相对应的。
----------------------------
以上有点废话,希望可以帮助大家认识清STATCI
-------------------------------
1、类内静态成员函数使用:
不能通过成员对象调用,通过类名::静态函数名,对象的指针或引用
2 类内静态成员函数可以对类内静态成员访问,全局静态函数也可以直接访问(默认在public下)
class t{
public:
static void s_t(){cout<<a<<endl;}
private:
static int a;
};
int t::a=2;
static void g_t(){cout<<t::a<<endl;} //ERROR,无法访问
void main(){
g_t();
}
从设计上来说,更愿意把静态放在规划好的类部
Top
25 楼sjjf(水晶剑锋)回复于 2006-10-24 21:20:48 得分 0
小心的mark一下,有空再看Top
26 楼lann64(昆仑大鹏@迦楼罗)回复于 2006-10-24 21:37:52 得分 0
记得Lippman在c++primer中说,C++不赞成文件静态声明。应该使用未命名的名字空间代替。
类内静态函数可以是私有成员。全局的不行。Top
27 楼yuewen_1983()回复于 2006-10-24 23:09:45 得分 0
mark一下 学习c++ingTop
28 楼skukustar(以黑暗之名の毁灭)回复于 2006-10-25 08:54:56 得分 5
我在这讲一讲友元、友元函数和友元类
友元是提供了不同类或对象的成员函数之间、类的成员函数与一般函数之间惊醒数据共享的机制。
就相当于给类的封装挖一个小小的孔,把数据的隐蔽掀开一个小小的角,通过它,可以看到类内部的一些属性。从这个角度来讲,友元是对数据隐蔽和封装的破坏,但是考虑到数据共享的必要性,为了提高程序的效率,很多情况这些小的破坏也是有必要的。
友元函数是在类声明中由关键字friend修饰的非成员函数。友元函数可以是一个普通函数也可以是其他类的成员函数,它不是本类的成员函数,但是在它的函数体中可以通过对象名访问类的私有和保护成员。
友元类直接看一个例子
class B
{
.... //B类的成员声明
friend class A //声明A为B的友元类
....
};
以上都是些基本的概念,没特殊见解。
Top
29 楼ugg(逸学堂(exuetang.net))回复于 2006-10-25 09:48:15 得分 0
to:lin_style,skukustar
谢谢两位在概念上讲解静态函数和有关友元类函数的定义
在C++中全局static函数,或者我们从C方面移植过来的多个全局函数
我们可以通过对函数加关键词,实现本编译单元有效,从而可以使用
C++的未命名的名字空间的作用确实有这个作用,这种方法尤其对一次移植
多个函数时有效,这样不需要给每个函数添加static,如下
namespace
{
int fun()
{
return 1;
}
...
}
等于
static int fun()
{
return 1;
}
static ...
对于类内静态函数和成员受public,privated,protected约束
而友元函数不受此限制,从面向对象角度来看两者虽然都是破坏封装
但是应用程度还是有一定的区别。
比如类内static函数,虽然不能直接应用类变量和类内函数(构造函数是个特例)
当我们把构造函数声明为protected或者privated类型时,那么我们在static函数内
可以照常使用,而在全局static函数内不能使用。
这个特性我们在设计模式中的singleton中可以见到。
对于友元函数,可以直接使用类变量,或者函数
比如
class A
{
friend int fun();
int a;
}
再类A中定义fun函数为A的友元函数,
那么fun函数可以直接使用A的成员变量。友元类也是一样。
int fun()
{
return a;
}
这个友元特性,在一些特殊场合是非常有用的,在windows编程中,尤其是当
fun是回调函数,而A中又包括一些内核对象之类的系统资源时,这个友元函数的
作用就凸现出来,我知道agentx++master中使用这个功能。当然还有很多
Top
30 楼ugg(逸学堂(exuetang.net))回复于 2006-10-25 09:51:51 得分 0
希望在模版中应用过static,尤其在继承关系中使用过static成员函数的
学友,讲讲static在模版中的应用。Top
31 楼jwqu()回复于 2006-10-27 18:41:43 得分 2
没有在template里面用过static。
我顺便问个以前看到的一个问题。希望斑竹能给出解答
void fun
{
static int i ;
}
变量i的内存地址位于:
A. 已初始化数据段 B.未初始化数据段
我感觉的应该选b 不过很多人选A
Top
32 楼pongba(刘未鹏|http://blog.csdn.net/pongba)回复于 2006-10-27 19:05:07 得分 0
ugg工作用C++么?为何不从一个实际编码场景中抽出一段能够引出这个讨论的段子?以免讨论过分学院化。
一个语言特性只有具有实际用途才是有意义的毕竟。Top
33 楼gm_zhang()回复于 2006-10-28 19:21:28 得分 2
我觉得count
cin
friend
最好不要用
有scanf printf就足够应付了要那么多干嘛呢
还有friend就是破坏c++的封装性
和c++的初衷相违背了
这都是败笔Top
34 楼ugg(逸学堂(exuetang.net))回复于 2006-10-30 17:36:50 得分 0
在CSDN上发帖讨论关于静态函数与全局静态函数的区别时,有网友指出没有全局静态函数之说,既然是全局函数又怎么能是静态的那?关于这个问题,我不想正面回答,static是C++关键字之一,它的作用就是:把有static修饰的函数或者变量变为静态的,这里的静态而不仅仅表示存储在静态区,同时也标示这个函数或者变量为文件内编译有效,也就是本单元编译有效,从这一点上来理解,全局静态函数其实就是本编译单元有效的函数。而这时和static对应关系应该就是extern,由extern声明,表示外部有效,可以直接调用,那么从这个角度看extern修饰的函数或者变量才是全局的。Extern在C编码中非常多的出现。不过我们这里讨论的是static问题,所以不想讨论过多的extern的问题。
同时通过这篇帖子,我也了解网友们想多了解些什么?大家觉得从理论方面讨论这些问题很没有意思?甚至人怀疑我是不是从事C++工作的,提到static函数的应用,无非是类名::函数。对于这些我在发帖中也提到“每周一贴的目的是整理出来在各个角度看待问题的观点,深刻的了解议题中讨论问题的应用环境”,我在这里不是想征求一个问题的解决方案,也不是为吸引人眼球而故意考察某项特性。我想讨论的是大家能从自己的开发环境中出发,讨论在实际开发中的应用。我也不希望通过这篇引导大家只讨论面试题或者算法或者语言特性的。而是更多的从实际出发,谈谈自己的应用,讲讲自己的设计,更加关心的是语言特性给我们带来设计思想的变化。大家很讨厌这种说教式的人,以免引起别人恶心,所以我还不说了。接下来我谈谈我对静态函数的认识,不正确的地方,欢迎指正。
查遍了Cpp2003,也没有找到关于静态函数的几乎完美的解释,所以请允许我用大白话的形式简单说明一下,在函数或者变量前面加上static修饰符号,以便把函数或者变量在类内或者文件范围内共享,那么我们把这种函数和变量叫静态函数和静态变量。
The static specifier can be applied only to names of objects and functions and to anonymous unions There can be no static function declarations within a block, nor any static function parameters.
我们把函数和变量声明为静态的有什么优点那,从静态变量的角度看,更容易理解一些
使用静态数据成员可以节省内存,因为它是所有对象所公有的,因此,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,但它的值是可以更新的。只要对静态数据成员的值更新一次,就可以保证所有对象都能够访问到被更新后的值,这样可以提高效率和节省内存空间。这是静态变量的优点同时也是他的一个缺点,在类中声明了静态变量,无论用户使用使用这个类,而这个静态变量都会申请他需要的内存容量。对于多线程的情况下,访问静态变量我们需要加一些异步机制,防止多个线程同时修改静态变量。
类内静态函数比全局静态函数的用处要多的多,在这里先讲简单的
全局静态函数的应用比较常见的就是
static int fun()
{
...;
return 1;
}
当我们希望在多个类中调用fun函数时,我们必须把fun声明为static类型,不然在link时编译器会发现多个关于fun的定义。这种函数的应用,多少带有C的色彩,尤其当我们在C环境写好的函数,移植到C++中时,需要在函数前面需要加上static,而如果我们需要移植多个函数时,更通用的一种方法是使用未命名名字空间
namespace{
int fun()
{
...;
return 1;
}
…
}
也许有人问如果在未命名名字空间中的函数再加上static修饰符号会怎么样?这个就完全取决以使用的编译器,可能会直接报错,也可能可以编译并正常使用。不过这样写,代码从语言层次上就很难移植编译环境,所以尽量不要这样写。
关于这样的应用,在我从前的项目中实施过。当时我需要定义很多函数,执行三角形,已经像素转换方面的计算,所以把这些函数声明为static的。
对于与全局静态函数,我们继续类内静态函数和静态变量的讨论,我想他们的应用是两者区别的最好体现。
对于类内静态变量,我们需要在类外初始化,这是在使用静态变量需要注意的地方,有些初学者很容易在这里出错。类内静态变量使用最多的就是计算类的实例化个数。
class A
{
static int i; // 外部初始化为0
public:
A() // 构造函数
{
++i;
}
~A() // 析构函数
{
--i;
}
static int CreateObjectNumber() // 或者创建对象的数目
{
return i;
}
};
也许读者认为这种方法,只是用来学习而已,实际很少使用。我不赞同这个观点。
在程序设计中,比如当前我做的皮肤系统中,我需要对所有创建的对象进行,并统计创建和销毁的对象是否相等,从而判断是否存在泄漏问题。所以我定义这样的一个类
// 由于版权,我只保留说明问题的部分
class SkinBaseImpl
{
public:
SkinBaseImpl(void);
virtual ~SkinBaseImpl(void);
public:
…
Top
35 楼ugg(逸学堂(exuetang.net))回复于 2006-10-30 17:37:08 得分 0
#ifdef SKINTRACE
private:
static int _ObjNum;
#endif
};
#ifdef SKINTRACE
int SkinBaseImpl::_ObjNum = 0;
#endif
/*=======================================================================*/
/**
* @bri: SkinBaseImpl构造函数
* @param: void
*/
SkinBaseImpl::SkinBaseImpl(void):_useSkin(USE)
{
#ifdef SKINTRACE
TRACE("Create new object, the number is %d\n",++_ObjNum);
#endif
}
/*=======================================================================*/
/**
* @bri: SkinBaseImpl析构函数
* @param: void
*/
SkinBaseImpl::~SkinBaseImpl(void)
{
#ifdef SKINTRACE
TRACE("free the %d object\n",_ObjNum--);
#endif
}
其他需要管理和统计创建销毁对象的类就可以从这个类继承。
在这里我定义了宏SKINTRACE,当需要使用trace,以便获取创建对象的数量时,定义这个宏就可以。而不需要时,比如发布版时,只需注销到SKINTRACE的定义,这样不会在发布颁布留下任何痕迹。
通过上面的例子,我们知道静态函数和静态变量的几个特性
1:静态变量受public,protected ,private限制,也就是如果静态变量是protected或者private类型的,在类外不能访问,比如
A::i是错误的
这条规则同样适用于静态函数
2:静态变量在类内声明,而必须在类外初始化,模版类中应用也是这样。这里我们在static后面加上const类型,可以直接初始化。比如
Class A
{
// Static int I = 5; // error
Static const int I = 5; // ok
Int m_list[I];
}
而这里I的应用也无非是Int m_list[I];
3:静态成员函数只能访问类的静态变量,而类的成员函数也可以访问类的静态变量,这样就可以通过静态成员变量建立类的静态成员函数和类对象的关联关系。
4:还存在一种静态变量,他不是全局静态变量,而是函数内的静态变量,如下例中的i,这算是对全局静态变量的一种补充。
int fun()
{
static int i = 3;
++i;
return i;
}
这种方式的好处时,只用调用fun函数时,静态变量i才申请内存,这也符合lazy evaluation的设计要求。只有当需要时,才去申请。
同样作为破坏封装的一种技术应用是友元函数或者友元类的应用,很多人形象比喻这种方式是在封装的物体上开了一个小小的洞,不提倡使用这种技术。其实任何技术都有他应用的场所,不然就不会出现这种技术。不过不去了解这种特性,也许永远我们不会知道这些技术的重要性。碰见这些技术也只会使用有色眼镜去看。友元函数的特征基本如下
1) 必须在类的说明中说明友元函数,说明时以关键字friend开头,后跟友元函数的函数原型,友元函数的说明可以出现在类的任何地方,包括在private和public部分,不受private限制
2) 友元函数不是类的成员函数,所以友元函数的实现和普通函数一样,在实现时不用"::"指示属于哪个类,只有成员函数才使用"::"作用域符号;
3) 友元函数不能直接访问类的成员,只能访问对象成员,所以在调用友元函数时,确保友元类的必须实例化。
4) 友元函数可以访问对象的私有成员,但普通函数不行,这个需要注意,尤其是在友元类中,有时候发现两个类互相为友元类,确不能调用成员函数,就是这个原因。
5) 调用友元函数时,在实际参数中需要指出要访问的对象,也可以把对象声明为全局对象而在友元函数中调用,当然在友元函数中可以调用其他全局函数,或者实例对象等操作。
使用友员函数最大的优点就是,不用对类中的每个变量写Get/Set接口函数。尤其是当类中有大量的私有成员变量,而又不想为每个变量设置接口,同时又需要外部的某个函数调用。这样最好就是把这个函数声明为友元函数,我们在一些开源项目中很常见这种技术,比如阿agentx++。
说道现在我一直没有提到模版中静态函数的应用,其实对于模版的应用,我不是很熟练。只能简单的说明一下
Top
36 楼ugg(逸学堂(exuetang.net))回复于 2006-10-30 17:37:22 得分 0
class AU
{
public:
AU(){
};
string GetAU()
{
return "Base--GetAU";
}
virtual string GetAUU()
{
return "Base--GetAUU";
};
virtual ~AU(){};
};
template <class T,class TBase>
class TEMU:public TBase
{
public:
string GetAA()
{
T* pt = static_cast<T*>(this);
return pt->GetA(); // 这里调用的是static string GetA()函数
}
string GetBB()
{
T* pt = static_cast<T*>(this);
return pt->GetB(); // 这里调用的是string GetB()
}
public:
string GetA()
{
return "TEMU - GetA";
}
string GetB()
{
return "TEMU - GetB";
}
};
class DeriveTEMU : public TEMU<DeriveTEMU,AU>
{
public:
static string GetA() // 注意这里是静态函数
{
return "DeriveTEMU - GetA";
}
string GetB()
{
return "DeriveTEMU - GetB";
}
};
测试用力
DeriveTEMU u;
TEMU<DeriveTEMU,AU> *p = &u;
cout << p->GetAA() << endl;
cout << p->GetBB() << endl;
输出结果
DeriveTEMU - GetA
DeriveTEMU – GetB
在这里我们看到,调用类内静态函数的方式并不是简单的类名::函数的形式,而是通过模版父类调用子类静态函数,同样也给出了,调用普通函数的方式。这种机制可以理解为模版继承关系中的虚继承关系。当认识到模版中的静态函数使用,也许会更大的改变我们对静态函数的印象,这种机制在ATL,WTL中有广泛的应用,几乎每种涉及到消息影射关系的类中,都使用这种方式。
以上是我对静态函数,静态变量的简单认识。也没有面面俱到的讲道静态的细节,这样说估计很多人会反感的。如果有错误,不妥,或者您认为重要但没有提到的,欢迎指正。
本回复公布一周,一周后揭帖,并发布下一个议题,同时欢迎大家公布自己的议题。
Top
37 楼xiao_potato(小土豆)回复于 2006-11-19 09:11:19 得分 1
还是学到了不少东西。尽管有mark,up指嫌,还是要顶一把。
版主的下一个议题想了吗?期待中。。。Top
38 楼alan001(星岛孤裔林郎君)回复于 2006-11-19 10:29:08 得分 0
有静态类吗??
静态函数的引入,是微软大楼为程序员分工,引入的工程特技
不应该离开这个指导思想.............Top
39 楼alan001(星岛孤裔林郎君)回复于 2006-11-19 11:15:20 得分 0
比方微软有一个"类合并工具",合并过程产生静态成员
这是关键,毕竟中国也要编写自己的C++编译器................Top
40 楼dfkoko(xiaoyin)回复于 2006-11-19 11:28:50 得分 0
看看Top
41 楼lin_style(﹏.贾诩(某人语:矮子也高潮))回复于 2006-11-19 12:00:50 得分 0
又更新了好多。 留名学习。Top
42 楼OOPhaisky(异化$渴望成功~~)回复于 2006-11-19 12:20:15 得分 2
class
{
public:
static int fun();
}A;
此时的fun()函数可以认为是static函数退化为类内成员,所以调用方式是
A.fun();但是其实质还是静态函数,一样不能调用类内成员函数。
其实无类名实例,与普通类事例有很多不同特征,在以后的讨论中希望有机会
深入讨论一下
其实这种类,在C++已经有定义,定义为metaclass(元类)
当希望类只有一个实例时,可以考虑使用元类
-------------------------------------------------------------------------------------
1. metaclass(元类)
2. 当希望类只有一个实例时,可以考虑使用元类
3. 希望楼主最早推出“无类名实例和普通类实例的区别”一贴,期待中......
ps:大力支持ugg斑竹的每周一贴行为,这样可以不断地丰富自己,提高自己,每个人都有知识的死角,而斑竹的这种举动对排出死角很有帮助^_^Top
43 楼LiChenYue(卐)(李忱悦)(怎堪蔑拒?鳄泪横流㊣暗恋未遂!独孤求偶)(卐)回复于 2006-11-19 13:13:24 得分 0
有一个问题:
STATIC和VIRTUAL能连用吗?Top
44 楼lingdianhuoyan()回复于 2006-11-19 13:41:55 得分 3
class AU
{
public:
AU(){
}
string GetAU()
{
return "Base--GetAU";
}
static void change();
virtual string GetAUU()
{
return "Base--GetAUU";
}
virtual ~AU(){}
private:
static int a;
};
int AU::a=0;
void AU::change()
{
a++;
cout<<a<<endl;
}
template <class T,class TBase>
class TEMU:public TBase
{
public:
string GetAA()
{
T* pt = static_cast<T*>(this);
si++;
cout<<si<<endl;
_tbase.change();
return pt->GetA(); // 这里调用的是static string GetA()函数
}
string GetBB()
{
T* pt = static_cast<T*>(this);
return pt->GetB(); // 这里调用的是string GetB()
}
public:
string GetA()
{
return "TEMU - GetA";
}
string GetB()
{
return "TEMU - GetB";
}
private:
static int si;
static TBase _tbase;
};
template<class T,class TBase>
int TEMU<T,TBase>::si=0;
class DeriveTEMU : public TEMU<DeriveTEMU,AU>
{
public:
static string GetA() // 注意这里是静态函数
{
return "DeriveTEMU - GetA";
}
string GetB()
{
return "DeriveTEMU - GetB";
}
};
int main()
{
DeriveTEMU u1;
DeriveTEMU u2;
TEMU<DeriveTEMU,AU> *p1 = &u1;
TEMU<DeriveTEMU,AU> *p2 = &u2;
cout << p1->GetAA() << endl;
cout << p1->GetBB() << endl;
cout << p2->GetAA() << endl;
cout << p2->GetBB() << endl;
system("pause");
return 0;
}
对LZ的例子作了些修改,在基类AU添加了一个静态成员变量static int a。在TEMU模版类中添加了两个静态变量一个与模版参数有关 static TBase _tbase,一个与模板参数无关 static int si;
运行结果:
1
1
DeriveTEMU - GetA
DeriveTEMU - GetB
2
2
DeriveTEMU - GetA
DeriveTEMU - GetB
看来模版类中的静态成员变量也是同一类型类共享!
Top
45 楼OOPhaisky(异化$渴望成功~~)回复于 2006-11-19 14:30:59 得分 0
to LiChenYue(李忱悦,每一次喊你,在我心!暗恋未遂,独孤求偶!) :
STATIC和VIRTUAL不能连用吗。Top
46 楼ugg(逸学堂(exuetang.net))回复于 2006-12-05 16:58:04 得分 0
STATIC和VIRTUAL不能连用,virtual函数的前提是类的成员函数,是运行时刻才能确定的函数。
而static成员函数是,通过类名限定符号来显示调用函数的。在VC下“虚拟成员函数不能是静态的”
同样值得一提的是virtual和inline是否能连用?答案在vc中是肯定的,两者可以连用。
但是inline操作符是被忽略的。这是编译器的一种选择,并不能代表所有的编译器都能够
支持这样的操作。
其实两者有意思的争论是,virtual表示函数运行确定,而inline表示编译时刻展开,两者
同时存在是没有道理的。
Top




