面试题目——虚函数和非虚函数的调用
2012-06-19 16:43
176 查看
本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!
#include "iostream.h"
class CBase
{
public:
virtual void act1() {cout<<"CBase::act1()!
"; act2();}
void act2() {cout<<"CBase::act2()!
"; act3();}
virtual void act3() {cout<<"CBase::act3()!
"; act4();}
virtual void act4() {cout<<"CBase::act4()!
"; act5();}
void act5() {cout<<"CBase::act5()!
"; }
};
class CDerive :public CBase
{
public:
void act3() {cout<<"CDerive::act3()!
"; act4();}
void act4() {cout<<"CDerive::act4()!
"; act5();} //此处的act5()调用CDerive类的act5
void act5() {cout<<"CDerive::act5()!
"; }
};
void main(void)
{
CBase *pObj1=new CBase;
pObj1->act1(); //act5()不是虚函数,此处为静态绑定,调用CBase类的act5()
pObj1->act5();
cout<<endl;
CBase *pObj2=new CDerive;
pObj2->act1();
pObj2->act5(); //act5()不是虚函数,此处为静态绑定,调用CBase类的act5()
delete pObj1;
delete pObj2;
}
运行结果如下:
CBase::act1()!
CBase::act2()!
CBase::act3()!
CBase::act4()!
CBase::act5()!
CBase::act5()!
CBase::act1()!
CBase::act2()!
CDerive::act3()!
CDerive::act4()!
CDerive::act5()!
CBase::act5()!
虚函数与重载设计方法上有何相同和区别:
(1)重载函数依赖静态联编,根据函数参数数目和种类的不同调用不同的函数体;虚函数依赖动态联编,根据类对象指针类型确定正确的类版本调用;
(2)重载函数之间和虚函数之间的返回类型必须是一样的;
(3)构造函数可以为重载函数,不能为虚函数;析构函数应该为虚函数;
(4)重载函数出现在一个类定义体中;虚函数出现在不同版本的派生类中。
虚析构函数设计对运行时的多态性处理的作用:
析构函数应该是虚函数。与一般的成员函数一样,析构函数被调用时,对象的构造已经完成,VPTR和VTABLE也已被正确初始化,因此虚析构函数在实现上是可能的。
从设计任务来看,析构函数的任务是释放内存,因此它必须知道被释放的对象的类型,否则可能破坏有用的数据,产生不可预知的后果。如用基类的指针指向了派生类对象,那么释放内存时,必须是释放派生类对象的存储空间。
考查虚函数和非虚函数的调用
写出如下程序的运行结果:#include "iostream.h"
class CBase
{
public:
virtual void act1() {cout<<"CBase::act1()!
"; act2();}
void act2() {cout<<"CBase::act2()!
"; act3();}
virtual void act3() {cout<<"CBase::act3()!
"; act4();}
virtual void act4() {cout<<"CBase::act4()!
"; act5();}
void act5() {cout<<"CBase::act5()!
"; }
};
class CDerive :public CBase
{
public:
void act3() {cout<<"CDerive::act3()!
"; act4();}
void act4() {cout<<"CDerive::act4()!
"; act5();} //此处的act5()调用CDerive类的act5
void act5() {cout<<"CDerive::act5()!
"; }
};
void main(void)
{
CBase *pObj1=new CBase;
pObj1->act1(); //act5()不是虚函数,此处为静态绑定,调用CBase类的act5()
pObj1->act5();
cout<<endl;
CBase *pObj2=new CDerive;
pObj2->act1();
pObj2->act5(); //act5()不是虚函数,此处为静态绑定,调用CBase类的act5()
delete pObj1;
delete pObj2;
}
运行结果如下:
CBase::act1()!
CBase::act2()!
CBase::act3()!
CBase::act4()!
CBase::act5()!
CBase::act5()!
CBase::act1()!
CBase::act2()!
CDerive::act3()!
CDerive::act4()!
CDerive::act5()!
CBase::act5()!
总结说明:
在面向对象的概念中,多态性是指不同对象收到相同消息时,根据对象类不同产生不同的动作。多态性提供了把接口与实现分开的另一种方法,提高了代码的组织性和可读性,使软件的可扩充性有充分的提高。虚函数与重载设计方法上有何相同和区别:
(1)重载函数依赖静态联编,根据函数参数数目和种类的不同调用不同的函数体;虚函数依赖动态联编,根据类对象指针类型确定正确的类版本调用;
(2)重载函数之间和虚函数之间的返回类型必须是一样的;
(3)构造函数可以为重载函数,不能为虚函数;析构函数应该为虚函数;
(4)重载函数出现在一个类定义体中;虚函数出现在不同版本的派生类中。
虚析构函数设计对运行时的多态性处理的作用:
析构函数应该是虚函数。与一般的成员函数一样,析构函数被调用时,对象的构造已经完成,VPTR和VTABLE也已被正确初始化,因此虚析构函数在实现上是可能的。
从设计任务来看,析构函数的任务是释放内存,因此它必须知道被释放的对象的类型,否则可能破坏有用的数据,产生不可预知的后果。如用基类的指针指向了派生类对象,那么释放内存时,必须是释放派生类对象的存储空间。
相关文章推荐
- 面试题目(3)——虚函数和非虚函数的调用
- 经典面试题目--在C++ 程序中调用被C 编译器编译后的函数,为什么要加extern “C”?
- 为什么一个函数被调用了,但看不到任何地方在调用它?(某公司面试题目)
- 虚函数和非虚函数的调用
- C++继承类和基类之间成员函数和虚函数调用机制
- 函数调用,题目练习
- 初始化函数中的虚函数调用( C++ vs python )
- 虚函数,有的语言里也叫动态函数(DYNAMIC,相对于VIRTUAL),这里的虚,不是没有,而是说,调用对象的类型决定具体的函数。
- c++父类虚函数被子类虚函数覆盖后,如何直接调用父类的虚函数?
- C/C++面试常考题目讨论之二:如何通过函数来分配空间
- C++ primer 这本书上有这么两句话“派生类虚函数调用基类版本时,必须显式使用作用域操作符。如果派生类函数忽略了这样做,则函数调用会在运行时确定并且将是一个自身调用,从而导致无穷递归。”
- C++继承类和基类之间成员函数和虚函数调用机制
- 面试---在C++ 中调用被 C 编译器编译后的函数,加 extern “C”
- 面试题目整理 虚函数和多态
- C语言,题目:函数调用,内存,malloc找错
- 关于C++虚函数与普通函数的编译与调用机制
- 指针 和引用 || 静态成员函数 || 虚函数 || 系统调用和库函数 ||
- 虚函数的作用,为什么构造函数不能是虚函数——金山面试
- 关于如何在不使用虚函数的情况下父类调用子类成员函数的问题
- C++中virtual(虚函数)和普通函数调用的不同