虚函数能够实现动态联编,是多态的实现形式之一,相同的函数根据对象的不同可以实现不同的功能。本文重点阐述虚函数的实现、注意事项、实现机制。
虚函数的实现
头文件:
#include <iostream>
#include <string>
class BaseClass
{
private:
std::string base_string_;
public:
BaseClass(std::string str="BaseClass") :base_string_(str) {}
virtual void VirtualShow1() const { std::cout << "BaseClass::VirtualShow1 is called and type is " << base_string_ << std::endl; }
virtual void OverloadShow2() const{ std::cout << "BaseClass::OverloadShow2 is called and type is " << base_string_ << std::endl; }
void FunctionShow3() const { std::cout << "BaseClass::FunctionShow3 is called and type is " << base_string_ << std::endl; }
virtual ~BaseClass(){}
};
class DeriveClass :public BaseClass
{
private:
std::string derive_string_;
public:
DeriveClass(std::string str1="BaseClass", std::string str2="DeriveClass") :BaseClass(str1), derive_string_(str2){}
void VirtualShow1() const { std::cout << "DeriveClass::VirtualShow1 is called and type is " << derive_string_ << std::endl; }
void OverloadShow2(std::string str) const { std::cout << "DeriveClass::OverloadShow1 is called and " << str << std::endl; }
void FunctionShow3() const { std::cout << "DeriveClass::FunctionShow3 is called and type is " << derive_string_ << std::endl; }
virtual ~DeriveClass(){}
};
main.cpp
#include "stdafx.h"
#include "virtualfunction.h"
int _tmain(int argc, _TCHAR* argv[])
{
BaseClass base_object;
DeriveClass derive_object;
BaseClass * point_derive = &derive_object;
std::cout << "base_object" << std::endl;
base_object.VirtualShow1();
base_object.OverloadShow2();
base_object.FunctionShow3();
std::cout << "derive_object" << std::endl;
derive_object.VirtualShow1();
derive_object.OverloadShow2("this is overload function!");
derive_object.FunctionShow3();
std::cout << "point_derive" << std::endl;
point_derive->VirtualShow1();
point_derive->OverloadShow2();
point_derive->FunctionShow3();
return 0;
}
运算结果:
结果分析:基类对象base_object调用基类的函数,子类对象derive_object调用子类的函数。
当使用基类指针指向子类对象时,即指针point_derive,利用该指针调用重载函数或普通函数时,属于静态联编,根据指针类型来编译,即调用基类函数;利用该指针调用虚函数时,属于动态联编,根据指针指向内容来编译,即调用子类函数。
1 基类中使用关键字virtual声明函数为虚函数;
2 继承类中,针对同样的函数,可定义不同的功能(注意:请与函数重载区分开)。在此可用virtual 再次声明,以表明该函数为虚函数,也可省去virtual关键字。当基类声明为虚函数时,继承类的同名函数默认为虚函数;
3 使用基类的指针或引用指向继承类或基类对象,在编译时,会根据对象内容调用函数。
虚函数的注意事项
1 虚函数必须处于基类的public部分,这样才能被对象访问;
2 虚函数不能为静态函数,不能为友元函数;
3 借助指针或引用,利用虚函数可达到动态联编功通过;
4 虚函数的声明原型中,基类与子类的函数名、形参类型、返回类型应相同(需与函数重载分开);
5 构造函数不能为虚函数,析构函数强烈建议为虚函数。
虚函数的实现机制
首先需要了解两个名词:vTable、vPointer
vTable 属于类所有,当该类含虚函数时,编译器会为该类创建vTable表,用于记录该类中所有虚函数的入口地址。
vPointer属于对象所有。使用含有vTable的类创建对象时,编译器自动创建成员函数vPointer,指向vTable表。同一个类的所有对象共用一个vTable表。
当调用虚函数时,进行以下4步:
Step1 获取对象的vPointer内容;
Step2 利用vPointer找到vTable;
Step3 利用vTable找到对应的函数入咒骂
Step4 执行对应的虚函数
本文参考以下内容: