最初发在QQ空间里,转过来:http://user.qzone.qq.com/31731705/blog/1310540087
上个月面试了一些快要毕业在找工作的学生,有个奇怪的感觉,学校就是学校,搞的东西大多是理论或者算法方面的,听的我是云里雾里,还有就是很NB很酷的那种,动不动就是内核,驱动,有分析Linux内核源码的,有做Windows内核驱动的。还记得当时我问一个学生,为什么你看的是Linux 0.11的代码,不是最新的,学生支支吾吾,说是版本虽然老,但功能齐全,我还是很疑惑,那为什么不是0.08或者是0.3,0.4版本的呢?最终,在我的“追问”下得知了答案,原来有本书就是分析Linux 0.11代码的,他照着这本书看的。
其实对于工程来说,一个重点是动手能力,不管你是研究理论算法,还是写驱动分析内核,都要能够给出解决方案并且付诸实践。很多毕业生,谈起来头头是道,面对一些基本的问题,却是老鼠咬乌龟,束手无策。我有用过一道题,是使用C编写一个模拟实现C++多态应用的一个范例,这题主要考察几点。
- C的基本的编程能力,大多数院校中C语言是必修课,即使如此,很多人也写不出基本的程序来。
- C++的知识,虽然不直接使用C++编程,但必须理解C++的多态概念,知道多态的应用是怎么一回事,在此基础上,知其然并且知其所以然,要能够理解C++的多态是如何实现的。
意料之中又在意料之外,只有极少数人能够写出象样的答案。意料之中,是因为大多数学生习惯于获取知识,这样就以为我懂了,我会了,而不是去思考背后的一些东西,缺少探索,总结;意料之外,则是学生们没有学习的热情和欲望,上学就是拿学位的,是因为生活压力嘛?这让那些希望工程的渴望上学的孩子们情何以堪。
最后,贴一下这题目的代码,有注释:
- // 几个基本的函数,对应抽象类中的虚函数
- //
- void foo1()
- {
- printf( "anything foo1 \r\n" );
- }
- void foo2( int i )
- {
- }
- void foo3( int i, int j )
- {
- }
- // 虚表,包含了虚函数的指针
- typedef struct Vtbl
- {
- void (*pf1)();
- void (*pf2)( int );
- void (*pf3)( int, int );
- }Vtbl;
- // 类的虚表
- Vtbl g_vtbl = { &foo1, &foo2, &foo3, };
- // 基类,开始处是虚表指针,
- // 后面是结构成员。
- typedef struct Anything
- {
- //Vtbl *pvtbl;
- void *pvtbl;
- int field1;
- int field2;
- }Anything;
- // 构造函数
- // 也是一个普通的成员函数,需要一个this指针
- void InitAnything( Anything *p )
- {
- p->pvtbl = &g_vtbl;
- p->field1 = 0x1234;
- p->field2 = 0x5678;
- }
- // 子类中的虚函数,重载了父类中的同类型函数
- void Sfoo1()
- {
- // 可以考虑调用父类中的函数
- // foo1();
- printf( "something foo1 \r\n" );
- }
- void Sfoo4( char *s )
- {
- printf( "hello %s\r\n", s );
- }
- // 子类中的虚表,因为内存布局是一样的,
- // 直接使用父类的
- typedef struct SVtbl
- {
- Vtbl vtbl;
- void (*pf4)( char * );
- }SVtbl;
- // 子类的虚表
- SVtbl g_svtbl = { { &Sfoo1, &foo2, &foo3, }, &Sfoo4, };
- // 某个子类,包含父类的内容
- // 还有自己的成员
- typedef struct Something
- {
- Anything a;
- int field3;
- }Something;
- // 构造函数
- // 也是一个普通的成员函数,需要一个this指针
- void InitSomething( Something *p )
- {
- InitAnything( (Anything*)p );
- p->a.pvtbl = &g_svtbl;
- p->field3 = 0xabcd;
- }
- void TestPolymorphism( Anything *p )
- {
- // 虽然使用的是父类型的指针
- // 但虚函数最终会根据对象的真实类型调用。
- (*((Vtbl*)p->pvtbl)->pf1)();
- }
- void TestVtbl()
- {
- // 子类的一个对象
- Something s;
- Anything *p = 0;
- // 初始化
- InitSomething( &s );
- p = (Anything*)&s;
- // 调用Sfoo4
- ((SVtbl*)p->pvtbl)->pf4( "Sfoo4" );
- // 测试多态
- TestPolymorphism( (Anything*)&s );
- }