虚函数

C/C++基础知识点面试题

北城以北 提交于 2019-11-28 19:21:44
目录 一、虚函数的数据结构,如何工作? 二、const与define的区别? 三、指针与引用的区别? 四、指针与数据的区别? 五、不用临时变量实现两个变量的交换 七、一个C++源文件从文本到可执行文件经历的过程 八、C++11新特性 九、C++和C的不同 十、malloc的原理 十一、内存泄漏、野指针 十二、static 十三、union和struct 十四、new与malloc的区别 十五、C++类型转换 十六、面向对象的了解 十七、前置和后置的区别 十八、静态库和动态库 十九、struct内存大小的确定 二十、strlen,strcpy函数的实现 二十一、memcpy,memset内部函数实现 二十二、C/C++内存管理方式,内存分配 二十三、深拷贝和浅拷贝 二十四、debug和release的区别 二十五、main是否需要返回值? 二十六、C++动态链接库与C动态链接库 二十七、结构体 二十八、拷贝构造函数为什么传引用? 二十九、程序崩溃原因 三十、C++字符串输入 三十一、lambda表达式 一、虚函数的数据结构,如何工作? 虚函数:用virtual定义的函数为虚函数。 虚函数来源:基于C++的一个特性:子类能转换成父类,例如: CBasic *parent; CBasic *p1; CChildren *child; parent = new CBsic; child =

虚函数表详解

允我心安 提交于 2019-11-28 18:46:02
一、概述 为了实现C++的多态,C++使用了一种动态绑定的技术。这个技术的核心是虚函数表(下文简称虚表)。本文介绍虚函数表是如何实现动态绑定的。 二、类的虚表 每个包含了虚函数的类都包含一个虚表。 我们知道,当一个类(A)继承另一个类(B)时,类A会继承类B的函数的调用权。所以如果一个基类包含了虚函数,那么其继承类也可调用这些虚函数,换句话说,一个类继承了包含虚函数的基类,那么这个类也拥有自己的虚表。 我们来看以下的代码。类A包含虚函数vfunc1,vfunc2,由于类A包含虚函数,故类A拥有一个虚表。 class A { public: virtual void vfunc1(); virtual void vfunc2(); void func1(); void func2(); private: int m_data1, m_data2; }; 类A的虚表如图1所示。 图1:类A的虚表示意图 虚表是一个指针数组,其元素是虚函数的指针,每个元素对应一个虚函数的函数指针。需要指出的是,普通的函数即非虚函数,其调用并不需要经过虚表,所以虚表的元素并不包括普通函数的函数指针。 虚表内的条目,即虚函数指针的赋值发生在编译器的编译阶段,也就是说在代码的编译阶段,虚表就可以构造出来了。 三、虚表指针 虚表是属于类的,而不是属于某个具体的对象,一个类只需要一个虚表即可

inline函数

一个人想着一个人 提交于 2019-11-28 18:44:18
Inline函数特征: 相当于把内联函数里面的内容写在调用内联函数处; 相当于不用执行进入函数的步骤,直接执行函数体; 相当于宏,却比宏多了类型检查,真正具有函数特性; 编译器一般不内联包含循环、递归、switch 等复杂操作的内联函数; 在类声明中定义的函数,除了虚函数的其他函数都会自动隐式地当成内联函数。 优缺点    优点 内联函数同宏函数一样将在被调用处进行代码展开,省去了参数压栈、栈帧开辟与回收,结果返回等,从而提高程序运行速度。 内联函数相比宏函数来说,在代码展开时,会做安全检查或自动类型转换(同普通函数),而宏定义则不会。 在类中声明同时定义的成员函数,自动转化为内联函数,因此内联函数可以访问类的成员变量,宏定义则不能。 内联函数在运行时可调试,而宏定义不可以。    缺点 代码膨胀。内联是以代码膨胀(复制)为代价,消除函数调用带来的开销。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。 inline 函数无法随着函数库升级而升级。inline函数的改变需要重新编译,不像 non-inline 可以直接链接。 是否内联,程序员不可控。内联函数只是对编译器的建议,是否对函数内联,决定权在于编译器 虚函数(virtual)可以是内联函数(inline)吗?

C++多态与虚函数表

こ雲淡風輕ζ 提交于 2019-11-28 18:14:58
转自 https://www.cnblogs.com/findumars/p/9845429.html 首先第一点: 为什么运行时多态无法在编译期进行: 比如 class A { virtual void func(){...}; }; class A1:public A { void func(){...}; };   对于这样一种最简单的形式,A1派生类对基类A中的func方法进行了重写。 在我们的程序中,假如有一个A*型指针pa: 对于pa->func(),我们并不知道它到底要调用哪个func,比如在某一行:pa=new A();pa->func();我们知道这时是调用的基类的func(); 但在下一行,很可能就是pa=new A1();pa->func();这下就是调用派生类A1的func方法了。 但对于编译器来说,这两个pa->func();对它来说它完全看不出任何区别,这样就无法在编译期将这个操作的函数地址定下来,因为func的地址既可能是A里的func的地址,也可能是A1中的func的地址,对于pa->func();这样有两种可能性,语义不详的语句,编译器当然不可能将它翻译成只有一个意思的机器指令,因此编译期是无法进行这种多态行为的。 但对于静态多态:重载与函数模板 对于重载func函数,由于是通过name magling的方式实现的,因此虽然都是func函数

C++多态

跟風遠走 提交于 2019-11-28 16:33:14
多态 概念:不同的对象去完成时会产生处不同的状态 定义与实现: class Person { public: virtual void BuyTicket() { cout << "买票-全价" << endl; } }; class Student : public Person { public: virtual void BuyTicket() { cout << "买票-半价" << endl; } /*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时,虽然也可以构成重写(因为继承后 基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用*/ /*void BuyTicket() { cout << "买票-半价" << endl; }*/ }; void Func(Person& p) { p.BuyTicket(); } int main() { Person ps; Student st; Func(ps); Func(st); return 0; } 要构成多态还有两个条件: 1. 必须通过基类的指针或者引用调用虚函数 2. 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写(父类中必须是虚函数,派生类可以不是) 注意: 父类中的virtual去掉,则构成 隐藏/重定义 派生类中的virtual去掉

c++ 之 内存模型:虚函数篇

拈花ヽ惹草 提交于 2019-11-28 14:01:29
一、虚函数 1.虚函数表位置分析 类:有虚函数,这个类会产生一个虚函数表 类的对象:有一个指针(vptr)会指向类的虚函数表——虚函数表指针。(位置可能在类内存空间的开头,也可能在末尾,具体由编译器实现决定) 2.继承关系作用下虚函数的手工调用 拿到虚函数表的地址,通过定义函数指针并赋值的方式可以直接调用虚函数。子类的虚函数会覆盖父类的虚函数。 3.虚函数表分析 (1)一个类只有包含虚函数才会存在虚函数表,同属于一个类的对象共享虚函数表,但拥有各自的虚函数表指针(vptr)。当然所有的该类对象的vptr都指向同一个虚函数表。 (2)父类中有虚函数就等于子类中有虚函数。(父类中有虚函数表则子类中肯定有虚函数表) 因为子类会继承父类。 如果子类中将父类虚函数的virtual去掉,函数就不再是虚函数? 在父类中是虚函数,即使子类中该函数不写virtual,它依然是虚函数。 不管是父类还是子类,每一个类都只有属于自己的唯一虚函数表。子类中是否会存在多个虚函数表? (3)如果子类中完全没有新的虚函数,则子类虚函数表的内容与父类虚函数表的内容相同。但两个虚函数表在内存中的位置是不同的。是两个虚函数表。虚函数表中的每一项包含一个虚函数的首地址,但如果子类的虚函数表某项和父类虚函数表某项代表同一个函数(这表示子类没有覆盖父类的虚函数)则该表项所指向的函数相同。 (4)超出虚函数表部分内容不可知。

虚函数与构造函数和析构函数之间的问题

99封情书 提交于 2019-11-28 11:03:06
多态中为什么要将析构函数定义为虚函数 构造函数不能被定义为虚函数,在多态中,析构函数最好定义成虚函数 为什么构造函数不能被定义成虚函数?   构造一个对象时,必须要知道对象的类型,而虚函数本身是在运行期间确定其类型的。   虚函数执行依靠虚函数表,而虚函数表是在构造函数中进行初始化的。在构造对象期间,虚函数表未被初始化,将无法进行。 析构函数定义为虚函数的原因。   析构函数的作用是将类的对象从内存中抹掉。在多态情况中,考虑以下两种情况:   1. 用子类指针绑定子类对象,析构的时候,能正常析构。   2. 用父类指针绑定子类对象,假如父类没有将析构函数定义成虚函数的话,父类指针无法根据虚函数表找到子类的析构函数,所以只能调用父类析构函数对子类析构,从而造成内存泄漏。 来源: https://blog.csdn.net/weixin_41731295/article/details/100056803

C++软件开发面试题总结

落爺英雄遲暮 提交于 2019-11-28 07:34:53
  面试题有难有易,不能因为容易,我们就轻视,更不能因为难,我们就放弃。我们面对高薪就业的态度永远不变,那就是坚持、坚持、再坚持。出现问题,找原因;遇到困难,想办法。我们一直坚信只有在坚持中才能看到希望,而不是看到希望才去坚持。   人生没有如果,只有结果和后果。既然选择了,就不后悔。年轻就是资本,年轻就要吃苦,就要历练。就要学会在坚持中成长。如此感慨,至深的心得体会,绝对的经验之谈。 1、 Static有什么用途? (1)函数体内static变量的作用范围是该函数体,该变量的内存只被分配一次,因此它的值在下次调用时不变; (2)模块内的static全局变量同样只能在该模块内的函数访问和调用,不能被模块外的其他函数访问; (3)在类中的static成员变量属于整个类所有,对类的所有对象只有一份拷贝,这个函数不接受this指针,因为只能范围类的static成员函数。 2、 const (1)不管在函数声明修饰形参、还是修饰类的成员变量,表示该成员变量不能被改变,而且通常需要进行初始化,因为之后不能再改变; (2)对于指针来说,可以修饰指针所指向的变量(在*左边,即指针指向内容为常量),也可以指定指针本身为const(在*右边,指针本身是常量),或者两者同时指定为const(都是常量)。 3、 this指针 (1)this指针本质是一个函数参数,只是编译期隐藏起形式的,语法层面上的参数

虚函数调用错误

杀马特。学长 韩版系。学妹 提交于 2019-11-28 06:40:47
首先贴另外一个地址 https://blog.csdn.net/kikikind/article/details/2645316 一、理论上case 当一个纯虚函数被调用到时,vc++的debug模式下会弹出这么一个对话框: 这里没拷贝到。 然后就是crash了。 在网上找了一下,发现已经有人对此作了详细的介绍: "Pure Virtual Function Called": An Explanation . 这是一篇相当全面的文章,从纯虚函数抽象基类讲起,介绍了对象模型中vptr及vtable的概念以及他们的构造析构过程。有了这些基础,作者然后列出了5中可能出现"pure virtual function call"的情况,其实可以总结为两种: 在基类的构造函数或析构函数中直接或间接的调用纯虚函数 举个在基类构造函数中间接调用纯虚函数的例子: class Base { public: Base(){callVirtual();} void callVirtual(){virtualFunc();} virtual void virtualFunc() = 0; }; class Derived: public Base { public: virtual void virtualFunc(){} }; Derived d; //构造过程中调用到纯虚函数 通过野指针调用到虚函数