笔试题目

不用任何局部和全局变量实现int strlen(char *a)

int   strlen(char   *a)   {   
          if(0   ==   *a)   
                  return   0;   
          else     
                  return   1   +   strlen(a   +   1);   
  }


hashtable的实现

一个哈西表的简单实现(C语言版)

2008年12月11日 星期四 08:14


//头文件
#pragma once

#define HASH_MAX 10

enum result{error = -1, false = 0, true};
typedef char elemtype;


struct hashnode
{
    elemtype *pstr;
    struct hashnode *next;
};//用单链表存储数据,以哈西表的结点作为链表的头结点

struct hashtable
{
    size_t table_size;
    struct hashnode *head[HASH_MAX];//建议定义成**head二级指针,
                                                             //在初始化时给head 单独malloc一个空间即可
};

int hash_init(struct hashtable **ht);//初始化
int hash_destroy(struct hashtable **ht);//销毁
int hash_insert(struct hashtable *ht, elemtype *val);//插入
int hash_delete(struct hashtable *ht, elemtype *val);//查找
int hash_show(struct hashtable *ht);//打印出来
struct hashnode *hash_find(struct hashtable *ht, elemtype *key);//查找


//函数实现文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hash.h"

int hash_key(elemtype *key)
{
    int hash_val = 0;

    while(*key++)
        hash_val = (hash_val * 3) + (int)(*key);

    return (hash_val % HASH_MAX);
}

int hash_init(struct hashtable **ht)
{
    int i;
    *ht = (struct hashtable *)malloc(sizeof(struct hashtable));
    if(! *ht)
        return false;
    (*ht)->table_size = HASH_MAX;
    for(i = 0; i < HASH_MAX; i++)
    {
        (*ht)->head[i] = (struct hashnode *)malloc(sizeof(struct hashnode));
        if(!(*ht)->head[i])
        {
            free(*ht);
            return false;
        }
    }

    return true;
}

int hash_destroy(struct hashtable **ht)
{
    int i;
    struct hashnode *pcur, *ptmp;

    for(i = 0; i < HASH_MAX; i++)
    {
        pcur = (*ht)->head[i]->next;
        while(pcur)
        {
            ptmp = pcur->next;
            free(pcur->pstr);
            pcur->pstr = NULL;
            free(pcur);
            pcur = NULL;
            pcur = ptmp;
        }
        free((*ht)->head[i]);
        (*ht)->head[i] = NULL;
    }

    free(*ht);
    *ht = NULL;
    
    return true;
}

int hash_insert(struct hashtable *ht, elemtype *val)
{
    int hash_val = hash_key(val);
    struct hashnode *htmp, *pcur;

    if(hash_find(ht, val) != false)
    {
        printf("%s is already in.\n", val);
        return false;
    }

    htmp = (struct hashnode *)malloc(sizeof(htmp));
    if(!htmp)
        return false;

    htmp->pstr = (elemtype *)malloc(sizeof(elemtype));
    if(!htmp->pstr)
    {
        free(htmp);
        return false;
    }
    strcpy(htmp->pstr, val);
    htmp->next = NULL;
    for(pcur = ht->head[hash_val]; pcur->next != NULL; pcur = pcur->next);
    pcur->next = htmp;

    return true;
}

struct hashnode *hash_find(struct hashtable *ht, elemtype *key)
{
    int hash_val = hash_key(key);
    struct hashnode *htmp;
    
    htmp = ht->head[hash_val]->next;
    while(htmp != NULL)// && !strcmp(htmp->pstr, key))
    {
        if(strcmp(htmp->pstr, key) == 0)
            break;
        htmp = htmp->next;
    }

    if(htmp == NULL)
        return false;
    else
        return htmp;
}

int hash_show(struct hashtable *ht)
{
    int i;
    struct hashnode *pcur;

    for(i = 0; i < HASH_MAX; i++)
    {
        pcur = ht->head[i]->next;
        printf("%d: ", i + 1);
        while(pcur != NULL)
        {
            printf("%s ", pcur->pstr);
            pcur = pcur->next;
        }

        printf("\n");
    }

    printf("\n");
    return true;
}

int hash_delete(struct hashtable *ht, elemtype *val)
{
    struct hashnode *pcur, *pre;

    int hashkey = hash_key(val);

    pcur = ht->head[hashkey];
    pre = pcur->next;

    while(pre)
    {
        if(strcmp(pre->pstr, val) == 0)
        {
            printf("find: %s\n", pre->pstr);
            break;
        }
        pcur = pre;
        pre = pre->next;
    }
    if(pre == NULL)
    {
        printf("%s is not be found\n", val);
        return false;
    }
    pcur->next = pre->next;
    free(pre);
    pre = NULL;

    return true;
}

//主函数

#include <stdio.h>
#include <stdlib.h>
#include "hash.h"
#include "mystring.h"

int main(int argv, char **argc)
{
    struct hashtable *ht;

    elemtype *str1 = "Hljytlo";
    elemtype *str2 = "ellergo";
    elemtype *str3 = "yelglo";
    elemtype *str4 = "mHetello";
    elemtype *str5 = "kHelslo";
    elemtype *str6 = "pHelasdlo";
    hash_init(&ht);
    hash_show(ht);

    hash_insert(ht, str1);

    hash_insert(ht, str2);
    hash_insert(ht, str3);
    hash_insert(ht, str4);
    hash_insert(ht, str5);
    hash_insert(ht, str6);

    hash_show(ht);

    printf("Input a string you want to delte: ");
    str1 = read_line(10);//这个需要自己写的函数,可以用fgets代替,
                                     //建议不要使用gets,因为gets有bug
    hash_delete(ht, str1);
    hash_show(ht);


    hash_destroy(&ht);

    return 0;
}


http://www.cnblogs.com/guoshiandroid

/* Code by Slyar */ 
#include <stdio.h>
#include <stdlib.h>
 
#define max 8
 
 
int queen[max], sum=0; /* max为棋盘最大坐标 */
 
void show() /* 输出所有皇后的坐标 */
{
    int i;
    for(i = 0; i < max; i++)
    {
         printf("(%d,%d) ", i, queen[i]);
    }
    printf("\n");
    sum++;
}
 
int check(int n) /* 检查当前列能否放置皇后 */
{
    int i;
    for(i = 0; i < n; i++) /* 检查横排和对角线上是否可以放置皇后 */
    {
        if(queen[i] == queen[n] || abs(queen[i] - queen[n]) == (n - i))
        {
            return 1;
        }
    }
    return 0;
}
 
void put(int n) /* 回溯尝试皇后位置,n为横坐标 */
{
    int i;
    for(i = 0; i < max; i++)
    {       
        queen[n] = i; /* 将皇后摆到当前循环到的位置 */
        if(!check(n))
        {           
            if(n == max - 1)
            {
                show(); /* 如果全部摆好,则输出所有皇后的坐标 */
            }         
            else
            {
                put(n + 1); /* 否则继续摆放下一个皇后 */
            }
        }
    }
}
 
int main()
{
    put(0); /* 从横坐标为0开始依次尝试 */
    printf("%d", sum);
    system("pause");
    return 0;
}
 

前缀表达式和后缀表达式的问题

35,15,+,80,70,-,*,20,/                    //后缀表达方式
   (((35+15)*(80-70))/20)=25           //中缀表达方式  
   /,*,+,35,15,-,80,70, 20                   //前缀表达方式

人们习惯的运算方式是中缀表达式。而碰到前缀,后缀方式。。迷茫。其实仅仅是一种表达式子的方式而已(不被你习惯的方式),我这里教你一种也许你老师都没跟你讲的简单转换方式。一个中缀式到其他式子的转换方法~~这里我给出一个中缀表达式~           a+b*c-(d+e)
第一步:按照运算符的优先级对所有的运算单位加括号~
                 式子变成拉:((a+(b*c))-(d+e))
第二步:转换前缀与后缀表达式
        前缀:把运算符号移动到对应的括号前面
                 则变成拉:-( +(a *(bc)) +(de))
                 把括号去掉:-+a*bc+de  前缀式子出现
        后缀:把运算符号移动到对应的括号后面
              则变成拉:((a(bc)* )- (de)+ )-
              把括号去掉:abc*+de+-  后缀式子出现

不用sizeof测量数据类型的长度

#include <iostream>

using namespace std;

typedef
double testtype;

int main(){

testtype t[
2];

cout
<< (int)(&t[1])-(int)(&t[0])<<endl;

system(
"pause");

}

 -------------------- -------------------- -------------------- -------------------- 

 堆和栈的区别

 一、预备知识—程序的内存分配  

  

一个由C/C++编译的程序占用的内存分为以下几个部分  

  1、栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。  
  2、堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。  
  3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。  
  4、文字常量区   —常量字符串就是放在这里的。程序结束后由系统释放  
  5、程序代码区—存放函数体的二进制代码。  
   
  二、例子程序    
  这是一个前辈写的,非常详细    
  //main.cpp    
  int   a   =   0;   全局初始化区    
  char   *p1;   全局未初始化区    
  main()    
  {    
  int   b;   栈    
  char   s[]   =   "abc";   栈    
  char   *p2;   栈    
  char   *p3   =   "123456";   123456/0在常量区,p3在栈上。    
  static   int   c   =0;   全局(静态)初始化区    
  p1   =   (char   *)malloc(10);    
  p2   =   (char   *)malloc(20);    
  分配得来得10和20字节的区域就在堆区。    
  strcpy(p1,   "123456");   123456/0放在常量区,编译器可能会将它与p3所指向的"123456"  
  优化成一个地方。    
  }    
  二、堆和栈的理论知识    
  2.1申请方式    
  stack:  由系统自动分配。   例如,声明在函数中一个局部变量int   b;系统自动在栈中为b开辟空间    
  heap: 需要程序员自己申请,并指明大小,在c中malloc函数    
  如p1   =   (char   *)malloc(10);    
  在C++中用new运算符    
  如p2   =   new   char[10];    
  但是注意p1、p2本身是在栈中的。    
  2.2    
  申请后系统的响应    
  栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。    
  堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。  
  另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。    
   
  2.3申请大小的限制    
  栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。    
  堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。    
  2.4申请效率的比较:    
  栈由系统自动分配,速度较快。但程序员是无法控制的。    
  堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.    
  另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一块内存,虽然用起来最不方便。但是速度快,也最灵活。  
  
  2.5堆和栈中的存储内容    
  栈:   在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。    
  当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。    
  堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。   
  2.6存取效率的比较    
  char   s1[]   =   "aaaaaaaaaaaaaaa";    
  char   *s2   =   "bbbbbbbbbbbbbbbbb";    
  aaaaaaaaaaa是在运行时刻赋值的;    
  而bbbbbbbbbbb是在编译时就确定的;    
  但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。    
  比如:    
  #include    
  void   main()    
  {    
  char   a   =   1;    
  char   c[]   =   "1234567890";    
  char   *p   ="1234567890";    
  a   =   c[1];    
  a   =   p[1];    
  return;    
  }    
  对应的汇编代码    
  10:   a   =   c[1];    
  00401067   8A   4D   F1   mov   cl,byte   ptr   [ebp-0Fh]    
  0040106A   88   4D   FC   mov   byte   ptr   [ebp-4],cl    
  11:   a   =   p[1];    
  0040106D   8B   55   EC   mov   edx,dword   ptr   [ebp-14h]    
  00401070   8A   42   01   mov   al,byte   ptr   [edx+1]    
  00401073   88   45   FC   mov   byte   ptr   [ebp-4],al    
  第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到  
  edx中,再根据edx读取字符,显然慢了。    
  2.7小结:    
  堆和栈的区别可以用如下的比喻来看出:    
  使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就  
  走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自  
  由度小。    
  使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由  
  度大。
 -------------------- -------------------- -------------------- -------------------- 

多态性与虚函数

分类: C/C++ 182人阅读 评论(0) 收藏 举报

多态性与虚函数       

      面向对象理论中的3个术语:对象、方法和消息。对象(object):不言而喻,它是构成系统的基本单位,有属性和行为两个要素,在C++中,每个对象都是由数据函数这两部分组成的,数据即是对象的属性行为称之为方法(method),方法是对数据的操作,通常由函数实现。调用对象中的函数就是向该对象传送一个消息(message),所谓“消息”,其实就是一个命令。例如:

       stud.display();

就是向对象stud发出的一个“消息”,通知它执行其中的display“方法”(即display函数)。即:stud是对象,display()是方法,语句“stud.display();”是消息。

 

1.多态性(polymorphism)

       多态性定义:由继承而产生的相关的不同的类,向其对象发送同一个消息,不同的对象接收到后会产生不同的行为(即方法)。

       多态性分为两类:静态多态性和动态多态性。函数重载和运算符重载实现的多态性属于静态多态性,在程序编译时系统就能决定调用的是哪个函数,因此静态多态性有称为编译时的多态性。静态多态性是通过函数的重载实现的(运算符重载实质上也是函数重载)。动态多态性是在程序运行过程中才动态地确定操作所针对的对象,故称之为运行时的多态性。动态多态性是通过虚函数实现的。

关于静态多态性和动态多态性,请看下面的例子:

定义3个类:点、圆和圆柱

  1. #include <iostream.h>  
  2.   
  3. //定义Point基类  
  4. class Point  
  5. {  
  6. public:  
  7.     Point(float=0, float=0);  
  8.     void display();  
  9.     friend ostream & operator <<(ostream &, const Point &);  
  10. protected:  
  11.     float x, y;  
  12. };  
  13.   
  14. Point::Point(float a, float b)  
  15. {  
  16.     x=a; y=b;  
  17. }  
  18.   
  19. ostream & operator <<(ostream &output, const Point &p)  
  20. {  
  21.     output<<"["<<p.x<<","<<p.y<<"]"<<endl;  
  22.     return output;  
  23. }  
  24.   
  25. void Point::display()  
  26. {  
  27.     cout<<"["<<x<<","<<y<<"]"<<endl;  
  28. }  
  29.   
  30. //定义Circle基类  
  31. class Circle: public Point  
  32. {  
  33. public:  
  34.     Circle(float=0, float=0, float=0);  
  35.     float area ( ) const;  
  36.     void display();  
  37.     friend ostream & operator <<(ostream &, const Circle &);  
  38. protected:  
  39.     float radius;  
  40. };  
  41.   
  42. Circle::Circle(float a,float b,float r):Point(a,b),radius(r){ }  
  43.   
  44. float Circle::area( ) const  
  45. return 3.14159*radius*radius; }  
  46.   
  47. ostream & operator <<(ostream &output, const Circle &c)  
  48. {  
  49.     output<<"Center=["<<c.x<<","<<c.y<<"], r="<<c.radius<<", area="<<c.area( )<<endl;  
  50.     return output;  
  51. }  
  52.   
  53. void Circle::display()  
  54. {  
  55.     cout<<"Center=["<<x<<","<<y<<"], r="<<radius<<", area="<<area( )<<endl;  
  56. }  
  57.   
  58. //定义圆柱体类  
  59. class Cylinder: public Circle  
  60. {  
  61. public:  
  62.     Cylinder (float=0,float=0,float=0,float=0);  
  63.     float area() const;//计算圆表面积,和Circle类中的area重名  
  64.     float volume() const;  
  65.     void display();  
  66.     friend ostream & operator <<(ostream &, const Cylinder &);  
  67. protected:  
  68.     float height;  
  69. };  
  70.   
  71. Cylinder::Cylinder(float a,float b,float r,float h):Circle(a,b,r),height(h){}  
  72.   
  73. float Cylinder::area( ) const  
  74. return 2*Circle::area()+2*3.14159*radius*height; }  
  75.   
  76. float Cylinder::volume() const  
  77. return Circle::area()*height; }  
  78.   
  79. ostream & operator <<(ostream & output, const Cylinder &cy)  
  80. {  
  81.     output<<"Center=["<<cy.x<<","<<cy.y<<"], r="<<cy.radius<<", h="  
  82.         <<cy.height<<"\narea="<<cy.area( )<<", volume="<<cy.volume( )<<endl;  
  83.     return output;  
  84. }  
  85.   
  86. void Cylinder::display()  
  87. {  
  88.     cout<<"Center=["<<x<<","<<y<<"], r="<<radius<<", h="  
  89.         <<height<<"\narea="<<area( )<<", volume="<<volume( )<<endl;  
  90. }  

主函数(1),静态关联

  1. int main()  
  2. {  
  3.     Cylinder cy1;  
  4.     cout<<"A Cylinder:\n"<<cy1; //用重载运算符“<<”输出cy1的数据  
  5.       
  6.     Point &p=cy1; //将圆柱cy1赋值给点,p是Point类对象的引用变量  
  7.     cout<<"\np as a Point:\n"<<p;      //p作为一个“点”输出  
  8.       
  9.     Circle &c=cy1; //将圆柱cy1赋值给圆,c是Circle类对象的引用变量  
  10.     cout<<"\nc as a Circle:\n"<<c<<endl;     //c作为一个“圆”输出  
  11.     return 0;  
  12. }  
由该主函数可知:1. 圆柱对象cy1可以直接赋值给其基类的对象;2. Circle类和Cylinder类中都有一个area( )函数,之所以在Cylinder中用area( )能直接调用Cylinder::area( )而没有调用Circle:: area( )是因为“同名覆盖”的缘故,默认Cylinder中的area( )覆盖了基类中的area( )函数(如果不想覆盖,可以用纯虚函数,能够对基类函数重新定义,但是哪个效果更高还不好说)。3. 三个类中都包含了同名的重载运算符“<<”函数,但是他们的第二个参数类型互不相同,所以不能看做是同名覆盖,实际上,是属于静态关联。“<<”运算符之所以能准确地调用不同类中的重载函数,是因为系统在编译时就已经确定了调用对象。

 

主函数(2),动态关联:

  1. int main( )  
  2. {  
  3.     Point p1(9,9);  
  4.     Circle c1(6,6,8);  
  5.     Cylinder cy1(5,5,15,7.5);  
  6.   
  7.     Point *pt=&p1;  
  8.     pt->display();  
  9.     pt=&c1;  
  10.     pt->display();  
  11.     pt=&cy1;  
  12.     pt->display();  
  13.     return 0;  
  14. }  
首先应该明确一点:定义为指向Point基类对象的指针,当改变方向,指向派生类对象后,它仅指向派生类对象中基类的部分对象(例如当pt=&c1后,调用pt->display()相当于调用pt->Point::display()),所以上面调用的display()函数只能输出基类对象的值(即:定义为Point类型的指针pt根本就无法指向派生类增加的数据或函数,例如pt-> Circle::display()就会出错,提示“'Circle' : is not a memberof 'Point'”)。

要想pt能指向Circle::display(),就必须用虚成员函数来实现,即把基类中的display()函数声明为virtual类型。基类中的display()函数声明为了virtual类型,代表了它可以在派生类中被重新定义,为它赋予新功能(所以可以基类中的虚函数的函数体可以为空,或者写成纯虚函数的形式),注意是“重新定义”而不是“共存”,即此时Circle中定义的display()函数不再看做是增加的部分,而是看做基类的部分,所以直接用pt->display()或者pt->Point::display()就可以调用Circle类中定义的display()函数了,写成pt-> Circle::display()反而会出错。

 

2. 虚函数

上面已经说了,C++的动态多态性是通过虚函数来实现的。“虚成员函数”简称“虚函数”,C++不允许在类外声明虚函数。“虚函数允许派生类取代基类所提供的实现。编译器确保当对象为派生类时,取代者(译注:即派生类的实现)总是被调用,即使对象是使用基类指针访问而不是派生类的指针。”

上面的例子,写成虚函数的形式:

  1. class  
  2. {  
  3.     …  
  4.     virtual void display(){}    //声明为空的虚函数  
  5. }  
  6. int mai()  
  7. {  
  8.     Point p1(9,9);  
  9.     Circle c1(6,6,8);  
  10.     Cylinder cy1(5,5,15,7.5);  
  11.     Point *pt=&p1;  
  12.     pt->display();   //错误,因为Point类中的display()被定义为空,没有输出功能  
  13.     pt=&c1;  
  14.     pt->display();   //直接调用就可以输出圆的内容了  
  15.     ……  
  16. }  
也可以写成纯虚函数的形式:
  1. class  
  2. {  
  3.     …  
  4.     virtual void display() =0;  //声明为纯虚函数  
  5. }  
  6. int mai()  
  7. {  
  8.     Point p1(9,9);  //错误,包含纯虚函数的类被成为抽象类,不能被初始化  
  9.     Circle c1(6,6,8);  
  10.     Cylinder cy1(5,5,15,7.5);  
  11.     Point *pt=&p1;  
  12.     pt->display();  
  13.     pt=&c1;  
  14.     pt->display();   //直接调用就可以了  
  15.     ……  
  16. }  
因为纯虚函数“徒有其名,而无其实”,所以包含纯虚函数的类都只作为基类,相当于提供一种基本的类型,它的不能被初始化,这种类被称为“抽象基类”,它总是被调用的。

例如,可以给点、圆和圆柱体定义一个抽象基类Shape(形状):

  1. class Shape  
  2. {  
  3. public:  
  4.     virtual float area() const { return 0.0; }  //虚函数  
  5.     virtual float volume() const { return 0.0; }    //虚函数  
  6.     virtual void shapeName() const =0;  //纯虚函数  
  7. };  

3. 虚析构函数

如果用new运算符建立了临时对象,若基类中有析构函数,并且定义了一个指向该基类的指针变量。在程序用带指针参数的delete运算符撤销对象时,会发生一个情况:系统会只执行基类的析构函数,而不执行派生类的析构函数。例如:

  1. #include <iostream.h>  
  2.   
  3. //定义Point基类  
  4. class Point  
  5. {  
  6. public:  
  7.     Point( ){ }; //定义构造函数  
  8.     ~Point() { cout<<"Point OK!"<<endl; }   //析构函数  
  9. };  
  10.   
  11. class Circle: public Point  
  12. {  
  13. public:  
  14.     Circle( ){ };  
  15.     ~Circle() { cout<<"Circle OK!"<<endl; }  
  16. protected:  
  17.     float radius;  
  18. };  
  19.   
  20. int main( )  
  21. {  
  22.     Point *p=new Circle;  
  23.     delete p;   
  24.     return 0;  
  25. }  
希望用delete释放p所指的空间,但运行结果却为:

Point OK!

表示只执行了基类Piont的析构函数,而没有执行派生类Circle的析构函数。如果希望能执行派生类中的析构函数,可以将基类的析构函数声明为虚函数,如

virtual ~ Point() { cout<<"PointOK!"<<endl; }

如果将基类的析构函数声明为虚函数,由该基类所派生的所有派生类的析构函数也自动成为虚函数,即使它们名字不同。可见原理和格式与上面所说的虚函数是一样的。运行结果为:

Point OK!

Circle OK!

专业人员一般都习惯声明虚析构函数,即使基类并不需要析构函数,也显式地定义一个函数体为空的析构函数,以保证在撤销动态存储空间时能得到正确的处理。

posted @ 2011-09-08 19:04  yanng  阅读(130)  评论(0)    收藏  举报