博文

虚函数定义时遵循的规则(2010-06-09 21:20:00)

摘要:虚函数的定义要遵循以下重要规则:   1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后 联编的。   2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用于有继承关系的类对象,所以普通函数不能说明为虚函数。   3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。   4.内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义,但是在编译的时候系统仍然将它看做是非内联的。   5.构造函数不能是虚函数,因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。   6.析构函数可以是虚函数,而且通常声名为虚函数。   ------------------------------------   构造函数和虚构函数的调用:        如果是子类构造先基类,再子类      如果是子类析构先子类,再基类      但如果基类析构不是虚,只调用基类.否则如果基类析构是虚,则先调用子类,再调用基类。      如果是用new初始化的,必须用delete来释放,否则不调用析构函数。......

阅读全文(1699) | 评论:0

高难度面试题求解(C++)(初级)(2010-06-08 21:12:00)

摘要:C++面试题(初级) 姓名______ 日期_______ 1:写出输出 void fun(int i) { static int value=i++; cout<<value; } int main() { fun(0); fun(1); fun(2); } 2:引用和指针之间有什么区别? 3:比较全局变量和静态变量,试说明两者有何异同. 4:分析代码,给出i,j,k的结果. int i,j,k; i=j=k=0; if(++i||j++||++k) {} 5:说出如下const声明的含义: 1.const char* p 2.char const* p 3.char* const p 4.char A::fun() const; 6:编译下面的代码,会有什么结果? 1: void fun(char); void fun(char*); int main() { fun(0); } 2: void fun(int); void fun(int*); int main() { fun(0); } 7:请写出程序运行的结果 class A{ public: A() { cout<<"A::A()"<<endl;} ~A() { cout<<"A::~A()"<<endl;} }; class B{ public: B() {cout<<"B::B()"<<endl;} ~B() {cout<<B::~B()"<<endl;} }; class C:public B{ A a; public: C() {cout<<"C::C()"<<endl;} ~C() {cout<<"C::~C()"<<endl;} }; A a; int main() { C c; } 8:请写出程序运行的结果 class......

阅读全文(2296) | 评论:0

详解virtual table(2010-06-07 22:11:00)

摘要:C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。 关于虚函数的使用方法,我在这里不做过多的阐述。大家可以看看相关的C++的书籍。在这篇文章中,我只想从虚函数的实现机制上面为大家 一个清晰的剖析。 当然,相同的文章在网上也出现过一些了,但我总感觉这些文章不是很容易阅读,大段大段的代码,没有图片,没有详细的说明,没有比较,没有举一反三。不利于学习和阅读,所以这是我想写下这篇文章的原因。也希望大家多给我提意见。 言归正传,让我们一起进入虚函数的世界。 虚函数表 对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。 在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了 这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。 这里我们着重看一下这张虚函数表。在C++的标准规格说明书中说到,编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。 听我扯了那么多,我可以感觉出来你现在可能比以前更加晕头转向了。 没关系,下面就是实际的例子,相信聪明的你一看就明白了。 假设我们有这样的一个类: class Base { public: virtual void f() { cout << "Base::f" << endl; } virtual void g() { cout << "Base::g" << endl; } virtual void h() { cout &l......

阅读全文(1499) | 评论:0

C/C++ 程序设计员应聘常见面试试题深入剖析(2010-06-07 21:33:00)

摘要:1.引言   本文的写作目的并不在于提供C/C++程序员求职面试指导,而旨在从技术上分析面试题的内涵。文中的大多数面试题来自各大论坛,部分试题解答也参考了网友的意见。   许多面试题看似简单,却需要深厚的基本功才能给出完美的解答。企业要求面试者写一个最简单的strcpy函数都可看出面试者在技术上究竟达到了怎样的程度,我们能真正写好一个strcpy函数吗?我们都觉得自己能,可是我们写出的strcpy很可能只能拿到10分中的2分。读者可从本文看到strcpy函数从2分到10分解答的例子,看看自己属于什么样的层次。此外,还有一些面试题考查面试者敏捷的思维能力。   分析这些面试题,本身包含很强的趣味性;而作为一名研发人员,通过对这些面试题的深入剖析则可进一步增强自身的内功。   2.找错题   试题1: void test1() {  char string[10];  char* str1 = "0123456789";  strcpy( string, str1 ); }   试题2: void test2() {  char string[10], str1[10];  int i;  for(i=0; i<10; i++)  {   str1[i] = 'a';  }  strcpy( string, str1 ); }   试题3: void test3(char* str1) {  char string[10];  if( strlen( str1 ) <= 10 )  {   strcpy( string, str1 );  } }   解答:   试题1字符串str1需要11个字节才能存放下(包括末尾的’\0’),而string只有10个字节的空间,strcpy会导致数组越界;   对试题2,如果面试者指出字符数组str1不能在数组内结束可以给3分;如果面试者指出strcpy(string, str1)调用使得从str1内存起复制到string内存起所复制的字节数具有不确定性可以给7分,在此基础上指出库函数strcpy工作方式的给10分;   对试题3,if(strlen(str1) <= 10)应改为if(strlen......

阅读全文(1245) | 评论:0

指针做形参(2010-06-07 20:18:00)

摘要:void test(int* p) { *p = 2; p = NULL; }int main(int argc, char * argv[]) { int te = 3; cout<<"te = "<<te<<endl; int *pTe = &te; cout<<"*pTe = "<<*pTe <<endl; cout<<"pTe = "<<pTe <<endl; test(pTe); cout<<"After test()\n*pTe = "<<*pTe <<endl; cout<<"pTe = "<<pTe <<endl; system("pause"); return 0; } 输出: te = 3 *pTe = 3 pTe = 0013FF38 After test() *pTe = 2 pTe = 0013FF38 Press any key to continue . . . 说明: 函数的形参可以是指针,此时将复制实参指针。与其他非引用类型的形参一样,该类形参的任何改变也仅作用于局部副本。如果函数将新指针赋给形参,主调函数使用的实参指针的值没有改变。 当函数调用的时候,传递给被调用函数一个指针变量p的复制,即原来地址的复制;如果在被调用函数中修改了被指向的对象,即指针所指向的地址处的内容时,由于调用函数中的被复制的指针依然指向这块地址,所以,造成了返回后原指针所指向的对象的值的改变。如果在被调用函数中对指针本身进行任何操作,其实都不会对调用函数中的指针造成任何的修改。......

阅读全文(2947) | 评论:0

全局变量、局部变量、静态全局变量、静态局部变量的区别(2010-05-26 13:03:00)

摘要:全局变量、局部变量、静态全局变量、静态局部变量的区别(转)C++变量根据定义的位置的不同的生命周期,具有不同的作用域,作用域可分为6种:全局作用域,局部作用域,语句作用域,类作用域,命名空间作用域和文件作用域。从作用域看:全局变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。静态局部变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。局部变量也只有局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。静态全局变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量。从分配内存空间看:全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间 全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。    1)、静态变量会被放在程序的静态数据存储区(全局可见)中,这样可以在下一次调用的时候还可以保持原来的赋值。这一点是它与堆栈变量和堆变量的区别。  2)、变量用static告知编译器,自己仅仅在变量的作用范围内可见。这一点是它与全局变量的区别。从以上分析可以看出, 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static ......

阅读全文(1674) | 评论:0

c++内存空间分配【转】(2010-05-26 13:02:00)

摘要: 一. 在c中分为这几个存储区1.栈 - 由编译器自动分配释放2.堆 - 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收3.全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束释放4.另外还有一个专门放常量的地方。- 程序结束释放                                                                                                                                        &nbs......

阅读全文(2942) | 评论:0