🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸
文章目录
- 一、重载,隐藏/重定义,覆盖/重写
- 二、多态的原理
- 三、inline可以是虚函数吗
- 四、静态成员函数可以是虚函数吗
- 五、构造函数可以是虚函数吗
- 六、拷贝构造可以是虚函数吗
- 七、赋值运算符重载可以是虚函数吗
- 八、析构函数可以是虚函数吗
一、重载,隐藏/重定义,覆盖/重写
重载:同一作用域下的同名函数,需要返回值相同,参数列表不同构成重载
重定义/隐藏:继承关系中,子类与父类有同名函数就构成隐藏,只要名字相同,就构成隐藏,同时,析构函数也是特殊的同名函数。因为多态的需要,编译器会把它同一处理为destructor
重写:
重写具有两个条件:一是该函数在父类是虚函数,二是函数相同(返回值,函数名,参数列表),但是对于返回值而言,有特例,叫做重写的协变,具体请看C++中的多态(上),满足以上两个条件就是重写,不满足函数三同,那么虚函数就按普通函数处理,如果虚函数不是拿来完成多态,纯纯资源浪费,因为会创建虚表指针和虚表。
二、多态的原理
多态的原理就是多态调用是运行时决议,虚函数会创建一个虚表指针指向虚表(这个虚表在常量区中,可以通过打印地址看到)多态调用就会去查找虚表中的对应函数。所以子类完成虚函数重写,那么就可以通过父类的指针/引用来完成多态。
三、inline可以是虚函数吗
内联函数是可以为虚函数的,如果内联不是虚函数,那么构成内联的条件的话,在预编译阶段就会展开,不会进符号表,所以在链接的时候找不到定义,所以把内联函数怕的就是这个。但是,inline是建议性的关键字,加了virtual之后,编译器就忽略掉了inline。
四、静态成员函数可以是虚函数吗
①虚函数的调用过程:会先进入函数,因为虚函数是接口继承,所以父和子的接口都一样,随便进入一个,反正多态调用最后都会查虚表,该函数对应的虚表只有这一个,进入函数之后,通过this指针的方式,访问到虚表,从而进行调用,而静态成员函数的一大特点就是没有this指针,所以它也无法去通过多态调用。所以就算把静态成员函数存进虚表,也没有意义
②因为静态成员函数是可以通过指定类域的方式访问的 如A::func(); 说明它是编译时决议,你不管怎么多态,它在编译的时候就确定地址了,所以怎么也不会走到调用虚表这一地步。
五、构造函数可以是虚函数吗
①首先,虚构造函数是没有意义的,因为构造函数的名字和类名相同,所以并不会发生重写,所以构造函数如果是虚函数,只会浪费空间
②虚函数表和虚函数指针是在构造函数的初始化列表进行初始化的,因为构造函数只会在对象创建的时候调用一次,如果你去调用虚构造函数,那么进入构造函数就会调用this,找到虚表指针去查虚表(虚表是编译阶段就确定了的,因为编译器通过识别virtual来创建虚表,存在常量区),但是此时构造函数都还没有构造,虚表指针都找不到
所以构造函数不能是虚函数
六、拷贝构造可以是虚函数吗
①第一点同上,没有意义,浪费资源
②第二点也同上,因为还没有拷贝构造好,你就要调用我的虚表指针,我找不到
七、赋值运算符重载可以是虚函数吗
因为如果已经到赋值运算符重载了,说明对象以及构造好了,所以赋值运算符重载可以是虚函数
八、析构函数可以是虚函数吗
析构函数需要定义成虚函数,这是因为避免内存泄漏。如果不定义成虚函数,那么A*a = new B/A&a = b;(b是new出来的),他们就只能析构父类的部分,而子类新开辟的空间就没有被释放掉,导致内存泄漏,编译器为了能让析构函数完成重写,函数名会同一处理成destructor,然后调用的时候,只需调用子类的析构就可以了(父类的析构会在子类的析构之后自动调用,细节见C++中的多态(上))