赞
踩
众所周知C++是门面向对象的语言,其中三大特性是继承、封装和多态。多态又分为动态和静态多态两种,其中静态多态指重载和隐藏,而动态多态指虚函数机制。本篇主要介绍动态多态的虚函数机制。
虚函数是指基类中使用virtual关键字修饰的成员函数,如果基类未实现该虚函数,则成为抽象类,抽象类不能直接实例化,并且如果派生类继承虚函数,必须实现基类的虚函数才能实例化,这个实现过程也叫重写。
如何体现其动态特性能呢?其实是因为面向对象编程的过程中,如果希望基类指针指向不同派生类时,希望其可以调用不同派生类中的函数而不是基类的函数,可以通过将基类中的函数声明为虚函数达成。
具体实现机制如下:编译器为每个具有虚函数的基类生成一个虚函数表,不同类有不同的虚函数表,同一个类的不同对象共享一个虚函数表。继承这种基类的派生类在实例化时,会多出一个虚表指针指向对应类的虚函数表,因此即使派生类被转化成基类指针,其虚表指针依然能帮助指向对应派生类的函数
class ISpearker { protected: size_t id; public: ISpearker(size_t id) :id(id) {} virtual void speak() = 0; virtual void walk() = 0; }; class Dog : public ISpearker { public: Dog() : ISpearker(0) {} void speak() { printf("id: %d, dogs say woof \n", this->id); } void walk() { printf("id: %d, dog is walking\n", ((__dog*)ptr)->id); } }; class Human : public ISpearker { public: Human() : ISpearker(1) {} const char* name; void speak() { printf("id: %d, human %s say hello \n", this->id, this->name); } void walk() { printf("id: %d, human %s is walking \n", this->id, this->name); } }; int main() { //test(); Dog dog; Human human; ISpearker* speaker_dog = static_cast<ISpearker*>(&dog); ISpearker* speaker_human = static_cast<ISpearker*>(&human); speaker_dog->speak(); speaker_human->speak(); speaker_dog->walk(); speaker_human->walk(); }
运行结果:
//创建一个结构用于存储不同虚函数地址 struct SpeakerTable { void(*speak)(void* ptr); void(*walk)(void* ptr); }; //基类对象,如果是纯虚函数, 因为不能实例化,即无法谈论有无虚函数指针 struct __ispeaker { const SpeakerTable* vfptr; size_t id; }; //子类对象Dog,必须实现基类纯虚函数,否则不能实例化,实例化之后的对象存在虚函数指针, //虚函数指针指向Dog类对应的虚函数表,此处位__dogSpeakerTable struct __dog { const SpeakerTable* vfptr; size_t id; }; //子类对象Human,必须实现基类纯虚函数,否则不能实例化,实例化之后的对象存在虚函数指针, //虚函数指针指向Human类对应的虚函数表,此处位__humanSpeakerTable struct __human { const SpeakerTable* vfptr; size_t id; const char* name; }; //编译阶段所有类对应虚函数地址(__dog_speak, __dog_walk, __human_speak,__human_walk)均已经确定 void __dog_speak(void* ptr) { printf("id: %d, dogs say woof \n", ((__dog*)ptr)->id); } void __human_speak(void* ptr) { __human* human = (__human*)ptr; printf("id: %d, human %s say hello \n", human->id, human->name); } void __dog_walk(void* ptr) { printf("id: %d, dog is walking\n", ((__dog*)ptr)->id); } void __human_walk(void* ptr) { __human* human = (__human*)ptr; printf("id: %d, human %s is walking \n", human->id, human->name); } //虚函数表,编译阶段将对应虚函数地址存入对应类的虚函数表,每一个类对应一个虚函数表,所有相同 //类型对象共享一个虚函数表,this指针区分相同类型的不同对象 const static SpeakerTable __dogSpeakerTable = { __dog_speak, __dog_walk }; const static SpeakerTable __humanSpeakerTable = { __human_speak, __human_walk }; //实例化,分配地址,给虚函数指针分配对应虚表地址,初始化成员变量 __dog* createDog(size_t id) { __dog* dog = (__dog*)malloc(sizeof __dog); dog->vfptr = &__dogSpeakerTable; dog->id = id; return dog; } __human* createHuman(size_t id) { __human* human = (__human*)malloc(sizeof __human); human->vfptr = &__humanSpeakerTable; human->id = id; human->name = "tom"; return human; } void test() { __dog* dog = createDog(0); __human* human = createHuman(1); __ispeaker* idog = (__ispeaker*)dog; __ispeaker* ihuman = (__ispeaker*)human; // 编译器根据基类指向的虚函数不同,虚函数指针调用的虚函数不同,ispeaker->speak; idog->vfptr->speak((__dog*)idog); ihuman->vfptr->speak((__human*)ihuman); // ispeaker->walk; idog->vfptr->walk((__dog*)idog); ihuman->vfptr->walk((__human*)ihuman); } int main() { test(); //Dog dog; //Human human; //ISpearker* speaker_dog = static_cast<ISpearker*>(&dog); //ISpearker* speaker_human = static_cast<ISpearker*>(&human); //speaker_dog->speak(); //speaker_human->speak(); //speaker_dog->walk(); //speaker_human->walk(); }
运行结果:
深化对C++虚函数机制
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。