关于C++中虚函数的作用
2015-11-21 15:39
337 查看
昨天去面试,面试官问道:虚函数有什么作用,我解释了半天也没解释清楚,其实说到底还是理解不够深刻,或者说简直没什么理解,连子类重写父类的普通函数和子类重写父类的虚函数的区别都不知道,真是弱爆了!!1
虚函数的作用:通过以下两个程序来进行解释!
可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时,
基类指针调用其虚成员函数,则会调用其真正指向对象的成员函数,
而不是基类中定义的成员函数(只要派生类改写了该成员函数)。
若不是虚函数,则不管基类指针指向的哪个派生类对象,调用时都
会调用基类中定义的那个函数。
程序1:
#include <iostream>
using namecpace std;
class B0 //基类B0声明
{
public:
void display(){cout<<"B0::display()"<<endl;} //公有成员函数
};
class B1: public B0
{
public:
void display(){cout<<"B1::display()"<<endl;}
};
class D1: public B1
{
public:
void display(){cout<<"D1::display()"<<endl;}
};
void fun(B0 *ptr)
{
ptr->display(); //"对象指针->成员名"
}
void main() //主函数
{
B0 b0; //声明B0类对象
B1 b1; //声明B1类对象
D1 d1; //声明D1类对象
B0 *p; //声明B0类指针
p=&b0; //B0类指针指向B0类对象
fun(p);
p=&b1; //B0类指针指向B1类对象
fun(p);
p=&d1; //B0类指针指向D1类对象
fun(p);
}
运行结果:
B0::display()
B0::display()
B0::display()
程序2:
#include <iostream>
using namespace std;
class B0 //基类B0声明
{public: //外部接口
virtual void display() //虚成员函数
{cout<<"B0::display()"<<endl;}
};
class B1: public B0 //公有派生
{ public:
void display() { cout<<"B1::display()"<<endl; }
};
class D1: public B1 //公有派生
{ public:
void display() { cout<<"D1::display()"<<endl; }
};
void fun(B0 *ptr) //普通函数
{ ptr->display(); }
void main() //主函数
{ B0 b0, *p; //声明基类对象和指针
B1 b1; //声明派生类对象
D1 d1; //声明派生类对象
p=&b0;
fun(p); //调用基类B0函数成员
p=&b1;
fun(p); //调用派生类B1函数成员
p=&d1;
fun(p); //调用派生类D1函数成员
}
运行结果:
B0::display()
B1::display()
D1::display()
虚函数是动态绑定的基础。
是非静态的成员函数。
在类的声明中,在函数原型之前写virtual。
virtual 只用来说明类声明中的原型,不能用在函数实现时。
具有继承性,基类中声明了虚函数,派生类中无论是否说明,同原型函数都自动为虚函数。
本质:不是重载声明而是覆盖。
调用方式:通过基类指针或引用,执行时会根据指针指向的对象的类,决定调用哪个函数。
到这个地方还没完,其实完全可以不用父类类型的指针,直接创建子类对象来调用子类的普通函数也是可以的啊,为什么非要使用虚函数呢?
虽然这样说,但是实际开发过程中不是这样的,当我们使用一些类库、框架的时候,这些类库、框架是事先就写好的。我们在使用的时候不能直接修改类库的源码,我们只能派生类库中的类来覆盖一些成员函数以实现我们的功能,但这些成员函数有的是由框架调用的。这种情况下,用虚函数是很好的办法。
虚函数的作用:通过以下两个程序来进行解释!
可以让成员函数操作一般化,用基类的指针指向不同的派生类的对象时,
基类指针调用其虚成员函数,则会调用其真正指向对象的成员函数,
而不是基类中定义的成员函数(只要派生类改写了该成员函数)。
若不是虚函数,则不管基类指针指向的哪个派生类对象,调用时都
会调用基类中定义的那个函数。
程序1:
#include <iostream>
using namecpace std;
class B0 //基类B0声明
{
public:
void display(){cout<<"B0::display()"<<endl;} //公有成员函数
};
class B1: public B0
{
public:
void display(){cout<<"B1::display()"<<endl;}
};
class D1: public B1
{
public:
void display(){cout<<"D1::display()"<<endl;}
};
void fun(B0 *ptr)
{
ptr->display(); //"对象指针->成员名"
}
void main() //主函数
{
B0 b0; //声明B0类对象
B1 b1; //声明B1类对象
D1 d1; //声明D1类对象
B0 *p; //声明B0类指针
p=&b0; //B0类指针指向B0类对象
fun(p);
p=&b1; //B0类指针指向B1类对象
fun(p);
p=&d1; //B0类指针指向D1类对象
fun(p);
}
运行结果:
B0::display()
B0::display()
B0::display()
程序2:
#include <iostream>
using namespace std;
class B0 //基类B0声明
{public: //外部接口
virtual void display() //虚成员函数
{cout<<"B0::display()"<<endl;}
};
class B1: public B0 //公有派生
{ public:
void display() { cout<<"B1::display()"<<endl; }
};
class D1: public B1 //公有派生
{ public:
void display() { cout<<"D1::display()"<<endl; }
};
void fun(B0 *ptr) //普通函数
{ ptr->display(); }
void main() //主函数
{ B0 b0, *p; //声明基类对象和指针
B1 b1; //声明派生类对象
D1 d1; //声明派生类对象
p=&b0;
fun(p); //调用基类B0函数成员
p=&b1;
fun(p); //调用派生类B1函数成员
p=&d1;
fun(p); //调用派生类D1函数成员
}
运行结果:
B0::display()
B1::display()
D1::display()
虚函数是动态绑定的基础。
是非静态的成员函数。
在类的声明中,在函数原型之前写virtual。
virtual 只用来说明类声明中的原型,不能用在函数实现时。
具有继承性,基类中声明了虚函数,派生类中无论是否说明,同原型函数都自动为虚函数。
本质:不是重载声明而是覆盖。
调用方式:通过基类指针或引用,执行时会根据指针指向的对象的类,决定调用哪个函数。
到这个地方还没完,其实完全可以不用父类类型的指针,直接创建子类对象来调用子类的普通函数也是可以的啊,为什么非要使用虚函数呢?
虽然这样说,但是实际开发过程中不是这样的,当我们使用一些类库、框架的时候,这些类库、框架是事先就写好的。我们在使用的时候不能直接修改类库的源码,我们只能派生类库中的类来覆盖一些成员函数以实现我们的功能,但这些成员函数有的是由框架调用的。这种情况下,用虚函数是很好的办法。
相关文章推荐
- [c++] final override keyword
- 001--VS2013 c++ 游戏框架
- C++ sizeof 使用规则及陷阱分析
- C++学习笔记25——泛型算法之写入容器
- C++ 面向对象程序设计
- C语言二叉树的遍历,递归和非递归
- effective c++避免返回handles指向对象内部成分(2)
- C++控制台循环链表实现贪吃蛇
- 【C++】判断顺序栈出栈顺序的合法性
- C++ 学习(继承和动态内存分配)
- 深入解析C++ STL中的常用容器
- 重学C语言(一) 字符串数组输出
- 关于C++各类排序算法与std::sort性能的比较
- [C++] Returning values by reference in C++
- C++设计模式之组合模式
- C++设计模式之外观模式
- C++设计模式之建造者模式
- C++设计模式之抽象工厂模式
- C++设计模式之桥接模式
- C++设计模式之备忘录模式