一面
忘记录音,大部分题目都忘了,吐了
静态成员函数能否访问普通成员
静态成员函数不传递this指针,没有指针的话不能定位到非静态成员,每一个实例化对象都以一套自己的非静态成员,而静态成员是共享的。
如何访问
传对应参数(指针或引用)给静态成员函数。
虚函数如何实现
虚函数是为了满足多态与泛型编程性质而引出的,与一般编译时决定有着本质区别。
注意:
- 实现一个虚函数为的是允许基类指针调用子类函数
- 纯虚函数才代表接口(规范作用)
实现原理
编译器为实现虚函数的特性,分别为基类和派生类创建一个虚函数表(VFT),在实例化这些类的对象时,将创建一个隐藏的指针VFT*,指向相应的VFT。可将VFT视为一个包含函数指针的静态数组,其中每个指针都指向相应的虚函数。
虚函数指针
从本质上来说是一个指向函数的指针;其指向用户所定义的虚函数。当由子类初始化的基类。
编译器保证虚函数指针存在与实例中最前面的位置(保证正确取到虚函数的偏移量)
虚函数表(虚函数地址表)
基类和派生类分别有一个虚函数表, 用于存储函数指针,每个指针都指向相应的虚函数。
无虚函数覆盖
继承关系 Derive::VFT
可以得到如下几点:
- 虚函数按照声明顺序放于表中
-
虚函数覆盖
继承关系 Derive::VFT
可以得到如下几点: 派生类可以覆盖基类的虚函数
- 无覆盖的虚函数照旧
多重继承(虚函数覆盖)
子类实例的虚函数表:
可以得到:
1. 每个父类都有自己的虚表
2.子类的成员函数被放到了第一个父类的表中
3.三个父类虚函数表中的f()的位置被替换成了子类的函数指针
可解决不同父类类型的指针指向同一个子类实例,能够准确定位调用的实际函数
安全性
通过父类型指针访问子类(未重载父类虚函数)的虚函数毫无意义
Base1 *b1 = new Derive();
b1->f1(); //编译出错 ,f1仅有子类有
访问non-public函数
若父类虚函数是private或protected的,这些虚函数也会同样存在于虚函数表中。
故可使用访问虚函数表的方式访问这些non-public虚函数。
class Base {
private:
virtual void f() { cout<< "Base::f" <<endl;}
};
class Derive:public Base{
};
typedef void(*func)(void);
int main(){
Derive d;
func _func=(func)*((int *)*(int *)(&d)+0); /*获取虚函数*/
_func();
return 0;
}
此处你可以考虑考虑虚拟继承怎么实现的? 要融会贯通!
虚拟继承不同的编译器实现方式不同,vabc指针可能放在vptr的头端,也可放在尾端,或者直接单独放置
EPOLL 老问题~
看我腾讯TEG面试便可
线程安全相关,STL容器是线程安全的吗,atomic底层如何实现?
线程安全
当访问某个类或方法时,不论如何调用或线程如何交替执行,我们在主程序中都不需要去做任何的同步,这个类或函数的结果都是正确的行为,那么该类或方法就是线程安全的
STL容器时线程安全的嘛?
只有在多个读时才是线程安全的,
同时存在多个读者和写着,并不是线程安全的;
atomic如何实现的?
互斥锁可以解释为线程获取锁,发现锁被占用,就向系统申请锁空闲时唤醒他并立刻休眠。 自旋锁比较简单,当线程发现锁被占用时,会不断循环判断锁的状态,直到获取。
原子操作的颗粒度最小,只限于读写,对于性能的要求很高,如果使用了互斥锁势必在切换线程上耗费大量资源。相比之下,由于读写操作耗时比较小,能够在一个时间片内完成,自旋更适合这个场景。
- 直接操作内存
- getIntVolatile直接获取线程间共享对象
- CAS自旋锁机制
使用atomic是在寄存器,硬件上阻塞