2026/1/2 3:21:01
网站建设
项目流程
网站做排名,阿芹网站建设,网站ico如何修改,成都淮州新城建设投资有限公司网站虚函数简单介绍理解C提供的新机制#xff0c;虚函数允许函数调用与函数体的匹配在运行时才确定#xff0c;是一种动态绑定机制。正常来说#xff0c;通过基类引用或指针所能看到的是一个基类对象#xff0c;派生类中的成员对于基类引用或指针来说是不可见的#xff0c;无法…虚函数简单介绍理解C提供的新机制虚函数允许函数调用与函数体的匹配在运行时才确定是一种动态绑定机制。正常来说通过基类引用或指针所能看到的是一个基类对象派生类中的成员对于基类引用或指针来说是不可见的无法通过基类的指针或引用指向派生类。举例class Base_demo { public: void demo() { cout 这是基类Base endl; } }; class Derived_demo :public Base_demo { public: void demo() { cout 这是派生类Derived endl; } }; int main() { Base_demo b1, *b2; Derived_demo d1 ; b2 b1; b2-demo();//这是基类Base b2 d1; b2-demo();//这是基类Base return 0; }我们想通过基类引用或指针来访问派生类的成员就得使用本章的主题虚函数——virtual将基类的Print说明为虚函数形式。这样就可以通过基类引用或指针来访问派生类class Base_demo { public: virtual void demo() {//在此使用虚函数 cout 这是基类Base endl; } }; class Derived_demo :public Base_demo { public: void demo() { cout 这是派生类Derived endl; } }; int main() { Base_demo b1, *b2; Derived_demo d1 ; b2 b1; b2-demo();//这是基类Base b2 d1; b2-demo();//这是派生类Derived return 0; }为了更好体现虚函数在运行时才确定下面我将使用if进行判断运行;class Base_demo { public: virtual void Demo() { cout 这是基类Base endl; } }; class Derived_demo :public Base_demo { public: void Demo() { cout 这是派生类Derived endl; } }; class if_demo{ public: void Demo(Base_demo b1, Derived_demo d1, Base_demo* b2) { int condition; cin condition; if (1 condition) b2 b1; else b2 d1; } }; int main() { Base_demo b1, * b2; Derived_demo d1; if_demo i1; i1.Demo(b1, d1, b2); b2-Demo(); return 0; }如上Demo的调用依赖于用户输入的condition值而非在编译阶段就确定好谁调用Demo。虚函数概念理解在基类中用virtual关键字声明的成员函数即是虚函数。并且虚函数可以在一个或者多个公有派生类中被定义但是要求虚函数的原型必须完全相同。否则原型不同如只函数名相同会被编译器定义为函数重载从而丢失虚函数特性。仅返回类型不同其他相同。C编译器认为这种情况是不允许的。意义基类使用虚函数提供一个接口但派生类可以定义自己的实现版本。调用的解释依赖于它的对象类型这就实现了“一个接口多种语义”的概念。注意虚函数的限制条件1.不能将虚函数说明为全局函数。2.不能将虚函数说明为静态成员函数。3.不能将虚函数说明为友元函数。4.虚函数必须是类的非静态成员函数。class Base { public: // 错误构造函数不能是virtual virtual Base() { } };原因虚函数的调用依赖对象的虚指针VPTR和虚函数表VTABLE但1.VPTR 是在构造函数中初始化的对象的 VPTR 是由类的构造函数自动设置的构造函数执行时才会把 VPTR 指向当前类的 VTABLE2.构造函数执行时对象还没完全创建构造函数是用来 “创建对象” 的执行构造函数的那一刻对象的内存刚分配VPTR 还未初始化 —— 此时虚函数的调用逻辑通过 VPTR 找 VTABLE根本无法工作。5.构造函数不能定义为虚函数而析构函数可以定义为虚函数。class Base_demo { public: virtual void Demo() { cout 这是基类Base endl; } virtual ~Base_demo() { cout 析构Base endl; } }; class Derived_demo :public Base_demo { public: void Demo() { cout 这是派生类Derived endl; } ~Derived_demo() { cout 析构Derived endl; } }; int main() { Base_demo * b2, * d2; b2 new Base_demo(); d2 new Derived_demo(); delete b2; delete d2; return 0; }虚函数表和虚指针在编译时为每个有虚函数的类建立一张虚函数表VTABLE表中存放的是每一个虚函数的指针同时用一个虚指针VPTR指向这张表的入口。访问某个虚函数时不是直接找到那个函数的地址而是通过VPTR间接查到它的地址。int main(){ Base_demo b1 Base_demo* b2 b1; b2-Demo(); Derived_demo d1; Base_demo* b2 d1; b2-Demo(); }对于基类Base_demo的对象b1b1的内存空间包含自己的data members这里我没定义成员变量所以只有VPTRVPTR虚指针b1的 VPTR 指向 Base_demo的 VTABLE虚函数表这个表中存的是Base_demo::Demo()的函数地址。对于子类Derived_demo的对象d1d1的内存空间包含Base_demo的data members继承的 自己的data membersVPTRd1的 VPTR 指向 Derived_demo的 VTABLE这个表中存的是Derived_demo::Demo()的函数地址。纯虚函数与抽象类定义纯虚函数的语法形式 virtual type functionName(parameters)0;纯虚函数基类中的公共接口只需要有说明而不需要有实现即纯虚函数。纯虚函数刻画了派生类应该遵循的协议这些协议的具体实现由派生类来决定。抽象类拥有纯虚函数的类被称为抽象类。抽象类不能被实例化只能作为基类被使用。抽象类的派生类需要实现纯虚函数否则该派生类也是一个抽象类。接口类当抽象类的所有函数成员都是纯虚函数时这个类被称为接口类。class Shape{ virtual float Perimeter()0; virtual float Area()0; };Shape类中的Perimeter与Area就是纯虚函数而Shape则是抽象类。又可以看到类中成员全是虚函数所以Shape也是一个接口类。没什么用的小知识特殊规则注意一点纯虚函数的重写不受访问限制即使这里没用写public默认的private子类也可以重写。但通过父类指针调用私有虚函数是不合法的。所以一般我们还是要遵守访问限定域。