中望面经

1.多态,运行时多态(虚函数表和继承),静态多态(重载和模板编程)
2.如何实现对象只能分配在栈上:c++中,类的对象建立分为两种,

  • 静态建立:由编译器在栈上为对象开辟空间,直接调用类的构造函数。
    A a;
  • 动态建立:由new关键字将对象建立在堆空间上,首先执行 operator new()函数,在堆上搜索合适的内存并分配,第二步是调用构造函数构造对象。即间接的调用类的构造函数。
    A a = new A;
    (1)只有使用new关键字才能在堆上建立对象,那么我们就可以将operator new()函数自行声明为私有函数即可,或者设置为delete。
    1
    2
    3
    4
    5
    6
    7
    8
    class A{
    private;
    void* operator new(size_t t){} //设置为私有
    void operator delete(void *ptr){}
    public:
    A(){}
    ~A(){}
    }

(2)只在堆上分配新对象
即不能直接调用类的构造函数。首先要知道,当对象建立在栈上面时, 是由编译器分配内存空间的,当对象使用完以后,编译器会调用析构函数来释放对象所占的空间。实际上,编译器在为类对象分配栈空间时, 会检查类的析构函数的访问性(其他非静态函数也会检查),如果类的析构函数是私有的,则编程器不会在栈空间上为类对象分配内存。因此,我们只需要将析构函数设为私有,类对象就无法建立在栈上了。

1
2
3
4
5
6
7
class A{
public:
A(){}
void destroy(delete this;)
private:
~A(){}
}

注意,由于new表达式会在分配内存以后调用构造函数,因此构造函数必须是公有的,同时由于delete此时无法访问私有的析构函数,因此必须提供一个destroy函数,来进行内存空间的释放。
3.c++11新特性
auto,智能指针,移动语义(右值引用),完美转发
4.内联函数和宏的区别

  • 内联函数是函数,有参数类型检查,更为安全
  • 内联函数由编译器进行处理,而宏定义由预处理器进行处理
  • 内联函数处理时被插入到对应代码区域,而宏定义只是简单的文本替换

5.多线程
半同步半反应线程池
主线程充当异步线程,负责监听所有socket上的事件,若有新请求到来,主线程接收之以得到新的连接socket,然后往epoll内核事件表中注册该socket上的读写事件,并将数据封装成请求对象插入到请求队列中;所有工作线程睡眠在请求队列上,当有任务到来时,通过竞争(如互斥锁)获得任务的接管权

6.Linux进程调度和内存管理
7.设计模式
工厂模式和单例模式,适配器模式和策略模式
8.lambda表达式
9.手撕strcpy(不用任何库函数)
10.快排的 算法原理+手撕代码。
11.读代码说输出结果:一个简单的子类继承父类的代码
子类析构时,首先执行子类析构函数体的代码,然后执行子类成员对象所在类的析构函数,最后按照子类继承各个父类的次序,倒序各个父类的析构函数
https://zhuanlan.zhihu.com/p/371322392

12.栈溢出的原因
内存中栈一般存放,函数地址、函数参数、局部变量等信息存储于栈内存;
1>函数调用层次过深,每调用一次,函数的参数、局部变量等信息就压一次栈。
2>局部变量体积太大