一面

忘记录音,大部分题目都忘了,吐了

静态成员函数能否访问普通成员

静态成员函数不传递this指针,没有指针的话不能定位到非静态成员,每一个实例化对象都以一套自己的非静态成员,而静态成员是共享的。

如何访问

传对应参数(指针或引用)给静态成员函数。

虚函数如何实现

虚函数是为了满足多态与泛型编程性质而引出的,与一般编译时决定有着本质区别。
注意:

  1. 实现一个虚函数为的是允许基类指针调用子类函数
  2. 纯虚函数才代表接口(规范作用)

    实现原理

    CVTE(后台开发) - 图1
    编译器为实现虚函数的特性,分别为基类和派生类创建一个虚函数表(VFT),在实例化这些类的对象时,将创建一个隐藏的指针VFT*,指向相应的VFT。

    可将VFT视为一个包含函数指针的静态数组,其中每个指针都指向相应的虚函数。

虚函数指针

从本质上来说是一个指向函数的指针;其指向用户所定义的虚函数。当由子类初始化的基类。
编译器保证虚函数指针存在与实例中最前面的位置(保证正确取到虚函数的偏移量)

虚函数表(虚函数地址表)

基类和派生类分别有一个虚函数表, 用于存储函数指针,每个指针都指向相应的虚函数。

无虚函数覆盖

CVTE(后台开发) - 图2CVTE(后台开发) - 图3
继承关系 Derive::VFT
可以得到如下几点:

  1. 虚函数按照声明顺序放于表中
  2. 父类的虚函数在子类的虚函数前面

    虚函数覆盖

    CVTE(后台开发) - 图4CVTE(后台开发) - 图5
    继承关系 Derive::VFT
    可以得到如下几点:

  3. 派生类可以覆盖基类的虚函数

  4. 无覆盖的虚函数照旧

    多重继承(虚函数覆盖)

    CVTE(后台开发) - 图6
    子类实例的虚函数表:
    CVTE(后台开发) - 图7
    可以得到:
    1. 每个父类都有自己的虚表
    2.子类的成员函数被放到了第一个父类的表中
    3.三个父类虚函数表中的f()的位置被替换成了子类的函数指针
    可解决不同父类类型的指针指向同一个子类实例,能够准确定位调用的实际函数

安全性

通过父类型指针访问子类(未重载父类虚函数)的虚函数毫无意义

  1. Base1 *b1 = new Derive();
  2. b1->f1(); //编译出错 ,f1仅有子类有

但可使用指针的方式访问虚函数表来违反c++语义行为

访问non-public函数

若父类虚函数是private或protected的,这些虚函数也会同样存在于虚函数表中。
故可使用访问虚函数表的方式访问这些non-public虚函数。

  1. class Base {
  2. private:
  3. virtual void f() { cout<< "Base::f" <<endl;}
  4. };
  5. class Derive:public Base{
  6. };
  7. typedef void(*func)(void);
  8. int main(){
  9. Derive d;
  10. func _func=(func)*((int *)*(int *)(&d)+0); /*获取虚函数*/
  11. _func();
  12. return 0;
  13. }

此处你可以考虑考虑虚拟继承怎么实现的? 要融会贯通!

虚拟继承不同的编译器实现方式不同,vabc指针可能放在vptr的头端,也可放在尾端,或者直接单独放置

EPOLL 老问题~

看我腾讯TEG面试便可

线程安全相关,STL容器是线程安全的吗,atomic底层如何实现?

线程安全

当访问某个类或方法时,不论如何调用或线程如何交替执行,我们在主程序中都不需要去做任何的同步,这个类或函数的结果都是正确的行为,那么该类或方法就是线程安全的

STL容器时线程安全的嘛?

只有在多个读时才是线程安全的,
同时存在多个读者和写着,并不是线程安全的;

atomic如何实现的?

互斥锁可以解释为线程获取锁,发现锁被占用,就向系统申请锁空闲时唤醒他并立刻休眠。 自旋锁比较简单,当线程发现锁被占用时,会不断循环判断锁的状态,直到获取。

原子操作的颗粒度最小,只限于读写,对于性能的要求很高,如果使用了互斥锁势必在切换线程上耗费大量资源。相比之下,由于读写操作耗时比较小,能够在一个时间片内完成,自旋更适合这个场景。

  • 直接操作内存
  • getIntVolatile直接获取线程间共享对象
  • CAS自旋锁机制

使用atomic是在寄存器,硬件上阻塞