虚函数

C++虚函数(10) - 虚函数能否为inline?

守給你的承諾、 提交于 2019-12-03 22:05:08
虚函数用于实现运行时的多态,或者称为晚绑定或动态绑定。而内联函数用于提高效率。内联函数的原理是,在编译期间,对调用内联函数的地方的代码替换成函数代码。内联函数对于程序中需要频繁使用和调用的小函数非常有用。 默认地,类中定义的所有函数,除了虚函数之外,会隐式地或自动地当成内联函数(注意:内联只是对于编译器的一个请求,编译器可以自己决定是否进行内联). 无论何时,使用基类指针或引用来调用虚函数,它都不能为内联函数(因为调用发生在运行时)。但是,无论何时,使用类的对象(不是指针或引用)来调用时,可以当做是内联,因为编译器在编译时确切知道对象是哪个类的。 #include <iostream> using namespace std; class Base { public: virtual void who() { cout << "I am Base\n"; } }; class Derived: public Base { public: void who() { cout << "I am Derived\n"; } }; int main() { // 此处的虚函数who(),是通过类的具体对象来调用的,编译期间就能确定了,所以它可以是内联的。 Base b; b.who(); // 此处的虚函数是通过指针调用的,需要在运行时期间才能确定,所以不能为内联。 Base *ptr =

多态基本语法和原理

筅森魡賤 提交于 2019-12-03 22:04:51
多态(多种形态)是C++面向对象的三大特性之一 多态分为两类: 1.静态多态: 函数重载和运算符重载属于静态多态,复用函数名 2.动态多态 :派生类和虚函数实现运行时多态 (重点) 静态多态和动态多态的区别: 1.静态多态的函数地址早绑定—编译阶段确定函数地址 2.动态多态函数地址晚绑定—运行阶段确定函数地址 3. 父类的指针或引用指向子类 ,满足子类实现虚函数的功能 动态多态满足条件: 1.有继承关系 2.子类要重写父类的虚函数 重写 :即函数返回值类型 函数名 参数列表 完全相同 //动态多态的使用 父类的指针或者引用,指向子类对象 */ # include "pch.h" # include <iostream> using namespace std ; class animal { public : virtual void speak ( ) { cout << "动物在说话" << endl ; } } ; class cat : public animal { public : //重写:即函数返回值类型 函数名 参数列表 完全相同 void speak ( ) { cout << "小猫在说话" << endl ; } } ; class dog : public animal { public : void speak ( ) { cout << "小狗在说话"

C++ 之虚函数的实现原理

拜拜、爱过 提交于 2019-12-03 22:04:34
c++的多态使用虚函数实现,通过“晚绑定”,使程序在运行的时候,根据对象的类型去执行对应的虚函数。 C++ 之虚函数的实现原理 带有虚函数的类,编译器会为其额外分配一个虚函数表,里面记录的使虚函数的地址,当此类被继承时,子类如果也写了虚函数就在子类的虚函数表中将父类的函数地址覆盖,否则继承父类的虚函数地址。 实例化之后,对象有一个虚函数指针,虚函数指针指向虚函数表,这样程序运行的时候,通过虚函数指针找到的虚函数表就是根据对象的类型来指向的了。 转载于:https://www.cnblogs.com/bewolf/p/9352116.html 来源: CSDN 作者: weixin_30567225 链接: https://blog.csdn.net/weixin_30567225/article/details/97549743

C++虚函数的原理及实现

百般思念 提交于 2019-12-03 22:04:19
虚函数是在类中被声明为virtual的成员函数,当编译器看到通过指针或引用调用此类函数时,对其执行晚绑定,即通过指针(或引用)指向的类的类型信息来决定该函数是哪个类的。通常此类指针或引用都声明为基类的,它可以指向基类或派生类的对象。 多态指同一个方法根据其所属的不同对象可以有不同的行为(根据自己理解,不知这么说是否严谨)。 举个例子说明虚函数、多态、早绑定和晚绑定: 李氏两兄妹(哥哥和妹妹)参加姓氏运动会(不同姓氏组队参加),哥哥男子项目比赛,妹妹参加女子项目比赛,开幕式有一个参赛队伍代表发言仪式,兄妹俩都想 去露露脸,可只能一人去,最终他们决定到时抓阄决定,而组委会也不反对,它才不关心是哥哥还是妹妹来发言,只要派一个姓李的来说两句话就行。运动会如期举 行,妹妹抓阄获得代表李家发言的机会,哥哥参加了男子项目比赛,妹妹参加了女子项目比赛。比赛结果就不是我们关心的了。 现在让我们来做个类比(只讨论与运动会相关的话题): (1)类的设计: 李氏兄妹属于李氏家族,李氏是基类(这里还是抽象的纯基类),李氏又派生出两个子类(李氏男和李氏女),李氏男会所有男子项目的比赛(李氏男的成员函 数),李氏女会所有女子项目的比赛(李氏女的成员函数)。姓李的人都会发言(基类虚函数),李氏男和李氏女继承自李氏当然也会发言,只是男女说话声音不一 样,内容也会又差异,给人感觉不同

C++ 多态(迟绑定)原理

江枫思渺然 提交于 2019-12-03 22:03:58
今天看到一篇帖子关于虚函数的问题,原以为自己已经对c++虚函数,多态了解的不错了,但是,还是发现有一些模糊点,所以,又回头重新总结了一番。 有了不小的收获,下面,就和大家一起来分享一下,也希望对一些朋友起到一定的帮助。 首先先梳理一下概念,以前似乎对概念不是很重视,其实不然,真正对一个东西的定义了解了很透,才能去深入挖掘这个东西的内涵。 好,首先,什么是绑定?( what`s the definition of binding? ) c++编程思想上有说到: Connecting a function call to a function body is called binding.(将函数体和函数调用关联起来,就叫绑定) 然后,那么什么是早绑定?(Early binding) When binding is performed before the program is run (by the compiler and linker), it' s called early binding 在程序运行之前(也就是编译和链接时),执行的绑定是早绑定。 然后,什么是迟绑定?(late binding) late binding, which means the binding occurs at runtime, based on the type of the object.

C++中的动态绑定即多态的意义和原理

你说的曾经没有我的故事 提交于 2019-12-03 22:03:34
[size=medium] 首先梳理一下概念: 1.什么是绑定?(What's the definition of binding?) 将函数体和函数调用关联起来,就叫绑定! 2.什么是早绑定? 早绑定是指在程序运行之前,即编译和链接是执行的绑定就是早绑定! 3.什么事迟绑定? 迟绑定就是指发生在运行时,基于不同类型的对象。对函数调用不同的函数体是发生的绑定。当一种语言要实现迟绑定是,必须有某种机制去确定对象的具体类型,然后调用适当的成员函数! 其次我们来看一个小例子: class Animal{ public: virtual void sleep() { cout<<"Animall sleep!"<<endl; } void breath() { cout<<"Animall breath!"<<endl; } }; class Fish:public Animal { public: void sleep() { cout<<"Fish sleep!"<<endl; } void breath() { cout<<"Fish breath!"<<endl; } }; int main() { cout << "Hello world!" << endl; Fish f; Animal* a=&f; a->breath(); a->sleep(); return 0; }

C++ 深入理解虚函数

孤街浪徒 提交于 2019-12-03 22:03:16
转自: https://www.cnblogs.com/jin521/p/5602190.html 为什么使用虚函数?什么是虚函数?虚函数是为了解决什么问题? 面向对象的三大特征: 封装 多态 继承 普通虚函数 虚析构函数 纯虚函数 抽象类 接口类 隐藏 vs 覆盖 隐藏与覆盖之间的关系 早绑定和晚绑定 虚函数表 什么是多态? 相同对象收到不同消息或不同对象收到相同消息时产生的不同的动作。 静态多态 vs 动态多态 [-:>静态多态也叫做早绑定 class Rect //矩形类 { public: int calcArea(int width); int calcArea(int width,int height); }; 如上面的代码,他们函数名相同,参数个数不同,一看就是互为重载的两个函数 1 int main() 2 { 3 Rect.rect; 4 rect.calcArea(10); 5 rect.calcArea(10,20); 6 return 0; 7 } 程序在编译阶段根据参数个数确定调用哪个函数。这种情况叫做静态多态(早绑定) [-:> 动态多态也叫做晚绑定 比如计算面积 当给圆形计算面积时使用圆形面积的计算公式,给矩形计算面积时使用矩形面积的计算公式。也就是说有一个计算面积的形状基类,圆形和矩形类派生自形状类,圆形与矩形的类各有自己的计算面积的方法

c++ 虚函数实现多态的原理

自作多情 提交于 2019-12-03 22:02:57
前面的文章说过了c++如何实现多态,最主要的就是使用虚函数,另一种方法就是RTTI,这里我们不做说明了。前面说过编译器是这样实现晚绑定的:编译器对每一个含有virtual函数的类创建一个虚函数表vtable,其实vtable就是一个函数指针数组,vtable中存放该类的类型信息和这个类所有的虚函数地址,而且在这个类中,编译器会隐含的设置一个指向这个虚函数表的虚拟指针vptr。每个类vptr的设定和重置是通过类的构造函数、析构函数和拷贝复制运算符自动完成。vtable中的type_info object就是支持RTTI的,一般放在vtable的第一个位置。看下面的一段含有继承关系的代码 class Base { public: Base(); virtual ~Base() {}; virtual void test() { std::cout << "Base::test" << std::endl; } private: int b_i; }; class Derived : public Base { public: virtual void test() { std::cout << "Derived::test" << std::endl; } private: int d_i; }; 他们的对象在内存布局大概形式如图所示 若是没有虚函数时就不需要中间的vtable间接查找

C++多态

南笙酒味 提交于 2019-12-03 21:59:29
C++多态 概念 C++中实现多态的条件 重写、同名隐藏与重载 多态实现原理 多态实现过程: 扩展 概念 多种形态,在完成某个行为时,当不同的对象去完成时会产生不同的形态。多态又分为动态多态和静态多态。 静态多态 (静态绑定,早绑定):编译器在编译时确定调用哪个函数(体现:函数重载、模板)。 动态多态 (动态绑定,晚绑定):编译时无法确定具体调用哪个函数,只有在代码运行时才知道具体应该调用哪个函数(体现:虚函数+重写)。 C++中实现多态的条件 1.在继承体系中,基类中必须要有 虚函数 ,派生类必须对基类进行 重写 。 2.必须 通过基类的指针或引用 去调用虚函数。 上面两个条件缺一不可。 但是也有两个例外: 协变 和 析构函数 。 协变 :返回值类型不同。基类虚函数返回基类的指针或引用,派生类虚函数返回派生类的指针或引用。基类虚函数也可以返回另一个继承体系基类的指针或引用,其派生类虚函数返回与基类返回的指针或引用相同继承体系的派生类指针或引用。 析构函数 :只要基类中的析构函数被virtual关键字修饰,如果其派生类的显式提供了自己的析构函数,则形成重写。 重写、同名隐藏与重载 重写 :派生类重写基类的虚函数,必须保证派生类虚函数与基类函数的原型(返回值类型、函数名字、参数列表)完全相同。 重载 :只要参数列表(参数个数,参数顺序,参数类型)不同,就构成重载,与返回值无关。

C++多态:深入虚函数,理解晚绑定

可紊 提交于 2019-12-03 21:59:11
 C++的多态特性是通过晚绑定实现的。晚绑定(late binding),指的是编译器或解释器程序在运行前,不知道对象的类型。使用晚绑定,无需检查对象的类型,只需要检查对象是否支持特性和方法即可。  在C++中,晚绑定通常发生在使用 virtual 声明成员函数时。此时,C++创建一个虚函数表,当某个函数被调用时需要从这个表中查找该函数的实际位置。通常,晚绑定也叫做动态函数分派(dynamic dispatch)。  考虑如下的代码: #include<iostream> using namespace std ; class D { public : int num; D( int i = 0 ) { num = i; } virtual void print() { cout << "I'm a D. my num=" << num << endl; }; }; class E : public D { public : E( int i = 0 ) { num = i; } void print() { cout << "I'm a E. my num=" << num << endl; } void ppp() { int ttt = 1 ; } }; int main() { void (D::*i)() = &D::print; E* e = new E( 1 ); e