简述虚函数实现多态的原理
- 格式:docx
- 大小:36.41 KB
- 文档页数:1
虚函数原理虚函数是 C++ 中一个非常重要的特性,它为面向对象编程提供了很强的支持。
虚函数的实现原理是通过虚函数表实现的,本文将介绍虚函数的概念、使用方法以及实现原理。
一、虚函数概念虚函数是指在基类中使用 virtual 关键字声明的成员函数,它的作用是允许在子类中对该函数进行覆盖。
具体来说,虚函数允许在子类中定义一个与基类中同名的函数,当使用子类对象调用该函数时,程序会动态的选择调用子类中的函数。
虚函数的语法如下:```class Base {public:virtual void foo();};```虚函数可以被重写(覆盖),也可以被继承,但是不能被 static 和 friend 修饰。
二、虚函数的使用使用虚函数需要满足一下条件:1.虚函数必须在公有的类成员函数列表中声明,并在类声明的内部定义。
2.虚函数必须在基类和派生类中以相同的参数列表进行定义。
下面是一个使用虚函数的简单例子:class Square: public Shape {public:Square(double s) : side(s) {}double getArea() { return side * side; }Shape 是一个基类,Square 是它的一个派生类,Square 中重写了 getArea() 函数,计算正方形的面积。
虚函数的实现原理是通过虚函数表实现的。
虚函数表是一个指针数组,存储了每个类中的虚函数指针。
当对象被创建时,会在其内存空间中创建一个指向虚函数表的指针,这个指针通常称为虚函数表指针(vptr),虚函数的调用就是通过这个指针完成的。
每个含有虚函数的类都有一个独立的虚函数表,虚函数表智能在类的第一个对象中存储,它包含了该类中所有虚函数的地址。
在派生类中,虚函数表通常继承自它的直接基类,并在此基础上添加或修改虚函数的地址。
这样如果在派生类对象中调用虚函数时,程序会先获得对象的虚函数表指针,然后通过该指针找到对应的虚函数地址来执行函数。
c++多态的原理
C++多态的原理是基于面向对象的编程理念,它允许使用统一接口来操作不同类型的对象,即通过基类指针或引用调用各个子类的相同函数,实现了动态绑定。
C++多态的实现依赖于两个重要的概念:虚函数和虚表。
1. 虚函数:在基类中声明的虚函数可以被子类重写,通过在基类中使用virtual关键字修饰函数,可以将该函数声明为虚函数。
在子类中重写虚函数时,需要使用override关键字,以确保正确重写父类中的虚函数。
2. 虚表:每个含有虚函数的类都会有一个对应的虚表,虚表是一个函数指针的数组,存储了所有虚函数的地址。
每个对象实例中都会保存一个指针指向该类的虚表。
当通过基类指针或引用调用虚函数时,编译器会根据当前对象的实际类型,从虚表中查找对应的虚函数地址,并调用相应的函数。
这个过程被称为动态绑定或后期绑定,因为函数的绑定发生在运行时而不是编译时。
通过多态,可以实现代码的灵活性和可扩展性,使得代码可以以更通用的方式编写,同时又能够根据实际类型进行适当的操作。
python 虚函数定义Python 虚函数定义虚函数是面向对象编程中的一个重要概念。
它允许子类重新定义父类中的方法,并按照子类的需求来进行实现,从而实现多态性。
在Python中,虚函数的定义可以通过抽象基类和装饰器来完成。
本文将详细介绍Python中虚函数的定义过程,并解释其背后的原理。
1. 什么是虚函数?在面向对象编程中,虚函数是指一个在父类中定义的方法,该方法可以在子类中重新定义。
虚函数的存在使得不同的子类能够有不同的实现,从而更好地满足各自的需求。
虚函数的实现依赖于多态性,即同一方法能够根据不同的对象调用不同的实现。
2. 定义抽象基类在Python中,可以通过定义抽象基类来实现虚函数的定义。
抽象基类是一个包含抽象方法的类,它不能被实例化,只能被用作其他类的基类。
抽象方法是指在抽象基类中定义的方法,它只有方法签名,没有具体的实现。
如果一个子类不实现抽象基类中的抽象方法,那么该子类也会被视为抽象类。
为了定义一个抽象基类,需要导入`abc`模块并继承`abc.ABC`类。
使用`abstractmethod`装饰器来标记方法为抽象方法。
下面是一个示例:pythonfrom abc import ABC, abstractmethodclass Animal(ABC):abstractmethoddef make_sound(self):pass在上面的例子中,`Animal`类是一个抽象基类,它定义了一个抽象方法`make_sound`。
任何继承`Animal`类的子类都必须实现`make_sound`方法。
3. 定义子类在继承抽象基类的子类中,可以重新定义父类中的虚函数。
子类可以根据自己的需求来实现虚函数,并且可以调用父类中的相同名称的方法。
下面是一个示例:pythonclass Dog(Animal):def make_sound(self):print("Woof!")在上面的例子中,`Dog`类继承了`Animal`类,并重新定义了`make_sound`方法。
虚函数的多态性机制分析摘要:在面向对象程序设计中,继承性映射了现实世界中事物之间的层次现象,而多态性则是映射事物自身行为的多外延现象;虚函数可以实现不同的对象在收到相同的消息时,产生不同的动作。
重载是同一对象在收到相同的消息时,产生不同的动作。
该文对虚函数的多态性机制进行深入分析,提出用虚函数实现多态性的四项法则。
关键词:动态联编;虚函数;多态性中图分类号:TP312文献标识码:A文章编号:1009-3044(2011)13-3089-03The Analyze to Polymorphphism of Virtual FunctionLI Qiang, WU Yuan(Economic Department, South China Normal University ZC College, Guangzhou 512000, China)Abstract: In Object-Oriented Programming,the Inheritance reflects things of herarchical phenomenon in real world,but thePolymorphphism reflects the phenomenon of externalmulti-appearance of things itself.The virtual function can occur distinct motion by receiving same message in distinctobjects.Overloading can occur distinct motion by receivingsame message in same objects.This paper analyses deeply tothe Polymorphphism and proposes four rules about the realization of Polymorphphism.Key words: dynamic co-compiling; virtual function; polymorphphism1 面向对象程序设计的多态性在C++中,把类看作类型,把以public方式继承的派生类看作是基类的子类型。
虚函数表-C++多态的实现原理解析⽬录1、说明2、虚函数表3、代码⽰例1、说明我们都知道多态指的是⽗类的指针在运⾏中指向⼦类,那么它的实现原理是什么呢?答案是虚函数表在关于virtual⼀⽂中,我们详细了解了C++多态的使⽤⽅式,我们知道没有virtual关键⼦就没法使⽤多态2、虚函数表我们看⼀下下⾯的代码class A{public:int i;virtual void func() { cout << "A func" << endl; }virtual void func2() { cout << "A func2" << endl; }void func3() { cout << "A func3" << endl; }};class B : public A{int j;void func() { cout << "B func" << endl; }void func3() { cout << "B func3" << endl; }};int main(){cout << sizeof(A) << ", " << sizeof(B); //输出 8,12return 0;}在32位编译模式下,程序的运⾏结果是:8,12但是如果把代码中的virtual删掉,则程序的运⾏结果为:4,8可以发现,有了虚函数之后,类所占的存储空间⽐没有虚函数多了4个字节,这个4个字节就是实现多态的关键 -- 位于对象存储空间的最前端的指针,存放的是虚函数表的地址,这个是由编译器实现的每个带有虚函数的类(包括其⼦类)都有虚函数表虚函数表中存放着虚函数的地址,注意是虚函数的地址,⾮虚函数不在此列虚函数表是编译器实现的,程序运⾏时被载⼊内存,⼀个类的虚函数表中列出了该类的全部虚函数地址。
c++多态实现原理C++多态是面向对象程序设计中的重要概念。
它允许不同类型的对象对同一方法进行不同的操作,这在程序设计中具有很大的灵活性和可维护性。
本文将介绍C++多态的实现原理。
多态的定义多态是指一个对象具有多种形态,它可以根据上下文的不同而表现出不同的行为。
在面向对象程序设计中,多态是指不同类型的对象对同一方法进行不同的操作。
多态性有两种表现形式:静态多态和动态多态。
静态多态是通过函数重载和模板实现的,而动态多态是通过虚函数和继承实现的。
静态多态静态多态是指在编译期确定函数的调用方式。
C++通过函数重载和模板实现了静态多态。
函数重载函数重载是指在同一个作用域内定义多个名称相同但是参数类型和数量不同的函数。
当调用函数时,编译器会根据实参的类型和数量选择最匹配的函数。
如下例所示:```void fun(int x) {// do something}模板模板是C++的一个重要特性,可以使代码在编译时生成。
它可以用来实现函数和类的泛型化,可以接受任意数据类型的参数。
例如,我们可以用下面的代码来定义一个模板函数:```template<typename T>T max(T a, T b) {return a > b ? a : b;}虚函数虚函数是指在基类中声明为虚函数的函数,在派生类中可以被重新定义。
在调用虚函数时,会根据实际对象的类型来调用相应的函数。
例如:```class Animal {public:virtual void make_sound() {std::cout << "Animal makes sound" << std::endl;}};继承继承是指一个派生类可以继承一个或多个基类的数据和函数。
派生类可以重写基类的函数,从而改变基类函数的行为。
例如:class Rectangle : public Shape {public:Rectangle(double w, double h) : width_(w), height_(h) {}double area() const override {return width_ * height_;}private:double width_, height_;};在这个例子中,`Shape`类中定义了一个纯虚函数`area`,派生类`Rectangle`和`Circle`分别继承了`Shape`类。
(CC++学习)5.C++中的虚继承-虚函数-多态解析说明:在C++学习的过程中,虚继承-虚函数经常是初学者容易产⽣误解的两个概念,它们与C++中多态形成的关系,也是很多初学者经常产⽣困惑的地⽅,这篇⽂章将依次分别对三者进⾏解析,并讲述其之间的联系与不同。
⼀.虚继承1.在多继承中,对于多个⽗类的数据及函数成员,虽然有时候把他们全部继承下来是有必要的,⽐如当这些成员都不同的时候。
但在⼤多数的情况下,⽐如当多个⽗类之中的成员有重叠的地⽅时,因为保留多份数据成员的拷贝,不仅占有了较多的存储空间,还增加了访问的难度(由于继承了来⾃多个⽗类的同名数据成员,访问时需要加上⽗类的作⽤域,⽐如“⽗类名::成员”),因此,在实际的继承中是没必要的。
⽽虚继承则可以完美的解决这⼀问题。
2.在虚继承中,被虚继承的类叫做虚基类,虚基类是需要设计和抽象的,它应当提取多继承⽗类中重叠的部分作为成员,虚继承是对继承的⼀种扩展。
⽰例1:1 #include<iostream>2using namespace std;34class furniture5 {6public:7 furniture(float l,float wi,float we)8 :len(l),wid(wi),weight(we)9 {}10void dis()11 {12 cout<<"len = "<<len<<endl;13 cout<<"wid = "<<wid<<endl;14 cout<<"weight="<<weight<<endl;15 }16protected:17float len;18float wid;19float weight;20 };2122//+++++++++++++++++++++++++2324class bed:virtual public furniture25 {26public:27 bed(float l,float wi,float we)28 :furniture(l,wi,we)29 {}3031void sleep(){cout<<"go to sleep"<<endl;}32 };3334//+++++++++++++++++++++++++3536class sofa:virtual public furniture37 {38public:39 sofa(float l,float wi,float we)40 :furniture(l,wi,we)41 {}4243void sit(){cout<<"go to have a rest"<<endl;}44 };4546//+++++++++++++++++++++++++4748class sofabed:public bed,public sofa49 {50public:51 sofabed(float l,float wi,float we)52 :furniture(l,wi,we),bed(1,2,3),sofa(1,2,3)53 {}54 };5556int main()57 {58 bed b(1,2,3);59 b.sleep();64 sofabed sb(4,5,6);65 sb.sleep();66 sb.sit();67 sb.dis();68return 0;69 }70查看代码程序运⾏结果:在本例中,如果仅仅采⽤的是多继承⽽⾮虚继承,如下代码所⽰:1 #include<iostream>2using namespace std;34class bed5 {6public:7 bed(float l,float wi,float we)8 :len(l),wid(wi),weight(we)9 {}1011void sleep()12 {13 cout<<"go to sleep"<<endl;14 }1516void dis()17 {18 cout<<"len = "<<len<<endl;19 cout<<"wid = "<<wid<<endl;20 cout<<"weight = "<<weight<<endl;21 }22protected:23float len;24float wid;25float weight;26 };27//+++++++++++++++++++++++++++++28class sofa29 {30public:31 sofa(float l,float wi,float we)32 :len(l),wid(wi),weight(we)33 {}34void sit()35 {36 cout<<"go to have a rest"<<endl;37 }38void dis()39 {40 cout<<"len = "<<len<<endl;41 cout<<"wid = "<<wid<<endl;42 cout<<"weight = "<<weight<<endl;43 }44protected:45float len;46float wid;47float weight;4849 };50//+++++++++++++++++++++++++++51class sofabed:public bed,public sofa52 {53public:54 sofabed(float l,float wi,float we)55 :bed(l,wi,we),sofa(l,wi,we)56 {}57 };58//+++++++++++++++++++++++++++59int main()60 {61 bed b(1,2,3);62 b.sleep();67 sofabed sb(5,6,7);68 sb.sit();69 sb.sleep();70 sb.sofa::dis();71 sb.bed::dis();72return 0;73 }查看代码则sb.dis()就有问题了;因为它产⽣了⼆义性,编译器不知道该调⽤哪⼀个⽗类的成员函数,⽽正确做法是加上⽗类的作⽤域,这⽆疑是增加了访问了难度。
详解C++虚函数的⼯作原理静态绑定与动态绑定讨论静态绑定与动态绑定,⾸先需要理解的是绑定,何为绑定?函数调⽤与函数本⾝的关联,以及成员访问与变量内存地址间的关系,称为绑定。
理解了绑定后再理解静态与动态。
静态绑定:指在程序编译过程中,把函数调⽤与响应调⽤所需的代码结合的过程,称为静态绑定。
发⽣在编译期。
动态绑定:指在执⾏期间判断所引⽤对象的实际类型,根据实际的类型调⽤其相应的⽅法。
程序运⾏过程中,把函数调⽤与响应调⽤所需的代码相结合的过程称为动态绑定。
发⽣于运⾏期。
C++中动态绑定在C++中动态绑定是通过虚函数实现的,是多态实现的具体形式。
⽽虚函数是通过虚函数表实现的。
这个表中记录了虚函数的地址,解决继承、覆盖的问题,保证动态绑定时能够根据对象的实际类型调⽤正确的函数。
这个虚函数表在什么地⽅呢?C++标准规格说明书中说到,编译器必须要保证虚函数表的指针存在于对象实例中最前⾯的位置(这是为了保证正确取到虚函数的偏移量)。
也就是说,我们可以通过对象实例的地址得到这张虚函数表,然后可以遍历其中的函数指针,并调⽤相应的函数。
虚函数的⼯作原理要想弄明⽩动态绑定,就必须弄懂虚函数的⼯作原理。
C++中虚函数的实现⼀般是通过虚函数表实现的(C++规范中没有规定具体⽤哪种⽅法,但⼤部分的编译器⼚商都选择此⽅法)。
类的虚函数表是⼀块连续的内存,每个内存单元中记录⼀个JMP指令的地址。
编译器会为每个有虚函数的类创建⼀个虚函数表,该虚函数表将被该类的所有对象共享。
类的每个虚成员占据虚函数表中的⼀⾏。
如果类中有N个虚函数,那么其虚函数表将有N*4字节的⼤⼩。
虚函数(virtual)是通过虚函数表来实现的,在这个表中,主要是⼀个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其真实反映实际的函数。
这样,在有虚函数的类的实例中分配了指向这个表的指针的内存(位于对象实例的最前⾯),所以,当⽤⽗类的指针来操作⼀个⼦类的时候,这张虚函数表就显得尤为重要,指明了实际所应调⽤的函数。
【转】什么是多态,怎样实现多态C++中多态是怎样实现的?多态是⼀种不同的对象以单独的⽅式作⽤于相同消息的能⼒,这个概念是从⾃然语⾔中引进的。
例如,动词“关闭”应⽤到不同的事务上其意思是不同的。
关门,关闭银⾏账号或关闭⼀个程序的窗⼝都是不同的⾏为;其实际的意义取决于该动作所作⽤的对象。
⼤多数⾯向对象语⾔的多态特性都仅以虚拟函数的形式来实现,但C++除了⼀般的虚拟函数形式之外,还多了两种静态的(即编译时的)多态机制:1、操作符重载:例如,对整型和串对象应⽤ += 操作符时,每个对象都是以单独的⽅式各⾃进⾏解释。
显然,潜在的 += 实现在每种类型中是不同的。
但是从直观上看,我们可以预期结果是什么。
2、模板:例如,当接受到相同的消息时,整型vector对象和串vector对象对消息反映是不同的,我们以关闭⾏为为例:vector < int > vi; vector < string > names;string name("VC知识库");vi.push_back( 5 ); // 在 vector 尾部添加整型names.push_back (name); // 添加串和添加整型体现差别的潜在的操作静态的多态机制不会导致与虚拟函数相关的运⾏时开。
此外,操作符重载和模板两者是通⽤算法最基本的东西,在STL中体现得尤为突出。
那么接下来我们说说以虚函数形式多态:通常都有以重载、覆盖、隐藏来三中⽅式,三种⽅式的区别⼤家应该要很深⼊的了解,这⾥就不多说了。
许多开发⼈员往往将这种情况和C++的多态性搞混淆,下⾯我从两⽅⾯为⼤家解说:1、编译的⾓度C++编译器在编译的时候,要确定每个对象调⽤的函数的地址,这称为早期绑定(early binding)。
2、内存模型的⾓度为了确定对象调⽤的函数的地址,就要使⽤迟绑定(late binding)技术。
当编译器使⽤迟绑定时,就会在运⾏时再去确定对象的类型以及正确的调⽤函数。
简述虚函数实现多态的原理
虚函数是C++中支持多态的一种机制,多态是指同一函数在不同对象上产生不同的行为。
虚函数实现多态的原理是通过使用虚表(Vtable)和虚指针(Vptr)实现。
虚表是一个指针数组,它保存了类中所有虚函数的地址。
当一个对象被创建时,会在其内存布局中添加一个指向该类虚表的虚指针。
当调用一个虚函数时,编译器会通过该对象的虚指针查找对应虚表,进而找到虚函数的地址,然后执行该函数。
使用虚函数实现多态的过程如下:
1. 定义一个基类,并将其中需要实现多态的成员函数声明为虚函数。
2. 派生出子类,并根据需要重写基类的虚函数。
3. 通过基类指针或引用调用虚函数时,编译器会根据实际对象类型确定调用哪个版本的虚函数。
由于虚函数是在运行时才确定的,所以可以实现动态绑定,使程序具有更高的灵活性和可扩展性。