一些大神的总结:
https://github.com/linw7/Skill-Tree
https://blog.nowcoder.net/zhuanlan/3m2ONj
https://www.zhihu.com/column/c_1349860875424116736
1.重载、覆盖与隐藏
函数重载、覆盖(也有叫重写的)与隐藏
成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
隐藏是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

2.多态性
多态性:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。
多态性:程序能通过引用或指针的动态类型获取类型特定行为的能力

3.消息机制
Qt信号与槽:
信号-槽是Qt自定义的一种通信机制(connect(object, signalname, object, slotname))。信号-槽的使用方法,是在普通的函数声明之前,加上signal、slot标记(signals: rettype signalname();,信号函数只要声明、不需要自己写实现。public slots/private slots/protected slots: rettype slotname() {};,槽函数一般要定义函数体来实现动作),然后通过connect函数把信号与槽连接起来。后续只要调用信号函数(通过emit signalname();或者直接调用信号函数 signalname();可以这样是因为emit是一个空的宏),就可以触发连接好的信号或槽函数。连接的时候,前面的是发送者,后面的是接收者。信号与信号也可以连接,这种情况把接收者信号看做槽即可。
信号-槽的实现,借助一个工具:元对象编译器MOC(Meta Object Compiler)。该工具是一个C++预处理程序,它为高层次的事件处理自动生成所需要的附加代码。这个工具被集成在了Qt的编译工具链qmake中,在开始编译Qt工程时,会先去执行MOC,从代码中解析signals、slots、emit等等这些标准C/C++不存在的关键字,以及处理Q_OBJECT、Q_PROPERTY、Q_INVOKABLE等相关的宏,生成一个moc_xxx.cpp的C++文件。比如信号函数只要声明、不需要自己写实现,就是在这个moc_xxx.cpp文件中,自动生成的。MOC之后就是常规的C/C++编译、链接流程了。
图片说明
MOC的本质,其实是一个反射器,即Qt用MOC实现了反射功能。反射的定义:反射是一种计算机处理方式,有程序可以访问、检测和修改它本身状态或行为的这种能力,能提供封装程序集、类型的对象(程序集包含模块,而模块包含类型,类型又包含成员)。简单来说,反射就是运行过程中,获取对象的构造函数、成员函数、成员变量。可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。设计模式中简单工厂模式就体现了反射的思想,代码如下,这里我们通过字符串“banana”和“apple”获取到了对应的banana和apple类的对象,即我们在对类的信息(构造函数)一无所知时也能创建对象。
参考:https://zhuanlan.zhihu.com/p/80539605
linux进程间通信、对象间的通信、观察者模式

4.TCP/UDP
UDP(用户数据报协议)只是在IP的数据报服务之上增加了很少一点的功能,主要时复用、分用和差错检测的功能,UDP主要特点有:1.UDP是无连接的,即发送数据之前不需要建立连接,因此减少了开销和发送数据之前的延时。2.UDP使用尽最大努力的交付,即不保证可靠交付,接收端收到报文后也不需要发回确认,因此主机不需要维持复杂的连接状态表。3.UDP是面向报文的,UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界,UDP一次交付一个完整的报文。4.UDP没有拥塞控制算法,因此网络出现的拥塞不会使源主机的发送速率降低。5.UDP支持一对一、一对多、多对一、多对多的交互通信,TCP只支持端到端通信。6.UDP的首部开销小,只有8个字节,比TCP的20个字节的首部要短。
TCP(传输控制协议)的特点:1.TCP是面向连接的传输层协议,这就是说,应用程序在使用TCP协议前,必须先建立TCP连接(传输完成后也必须释放)。2.TCP连接是点对点的,一条TCP连接只能由两个端点。3.TCP提供可靠交付的服务,TCP连接无差错、不丢失、不重复、按序到达。4.TCP提供全双工通信,为了支持全双工TCP连接的两端都设有发送缓存和接受缓存,用来临时存放双向通信的数据。5.面向字节流,即TCP把引用程序交下来的数据仅仅看成是一连串的无结构的字节流。
停止等待协议能够在不可靠的传输网络上实现可靠的通信,具体特征有:停止等待、超时重传、自动重传请求ARQ。连续ARQ协议和滑动窗口协议是TCP的基础
5.HTTP/HTTPS
https://mp.weixin.qq.com/s/Zr_tIlhAjH7v8I-L5FC31g

6.怎么解决tcp粘包问题
https://www.cnblogs.com/bigox/p/10833462.html
https://blog.csdn.net/weixin_43181521/article/details/108423973

为什么是2MSL而不是MSL?
为什么等待2MSL,从TIME_WAIT到CLOSE?
在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

——————————————————————————————————————————————————
基础题:
1.双栈实现队列
push操作就直接往stack1中push, pop操作需要分类一下:如果stack2为空,那么需要将stack1中的数据转移到stack2中,然后在对stack2进行pop,如果stack2不为空,直接pop就ok。

2.两个有序数组,快速找出相同部分

    private static void Search(int[] m, int[] n) {
        int minLength = Math.min(m.length, n.length);
        int i = 0, j = 0;
        while (j < minLength || i < minLength) {
            if (m[i] == n[j]) {
                System.out.println(m[i]);
                i++;
                j++;
            } else if (m[i] < n[j]) {
                i++;
            } else {
                j++;
            }
        }
    }

3.有一个字符串,里面含有多个空格字符,删除空字符并统计空字符数量
双指针i = 0, j = 0;通过j遍历字符串,遇到空格记录并跳过,直到遇到字符将字符赋值给i指向的字符,指针i加一,继续遍历j指针

4.电脑有仅1G内存,如何在海量数据中快速找到100个目标数据?(海量数据可能有序,也可能无序)
【分块处理->块内排序】

5.单例模式与工厂模式

//单例模式是一种对象创建模式,可以保证为一个类只生成唯一的实例对象
//也就是说,在整个程序空间中,该类只存在一个实例对象

//懒汉式单例模式,每次都会要判断,多线程时存在互斥问题 
class Singelton
{
    private:
        Singelton()
        {
            cout << "Singelton构造函数执行" << endl; 
        }
    public:
        static Singelton* GetInstance()
        {
            if (m_psl == NULL)
            {
                m_psl = new Singelton;
            } 
            return m_psl;
        }
        static void FreeInstance()
        {
            if (m_psl != NULL)
            {
                delete m_psl;
                m_psl = NULL;
            } 
            return;
        }
    private:
        static Singelton* m_psl;
} 
Singelton* Singelton::m_psl = NULL;
int main(void)
{
    Singelton *p1 = Singelton::GetInstance();
    Singelton *p2 = Singelton::GetInstance();
    if (p1 == p2)
    {
        cout << "p1和p2指向同一个对象" << endl; 
    }
    else
    {
        cout << "p1和p2指向不同对象" << endl; 
    }
    Singelton::FreeInstance();

    return 0;
} 
//饿汉式单例模式,不管用不用单例都会创造单例 
class Singelton
{
    private:
        Singelton()
        {
            cout << "Singelton构造函数执行" << endl; 
        }
    public:
        static Singelton* GetInstance()
        {
            return m_psl;
        }
        static void FreeInstance()
        {
            if (m_psl != NULL)
            {
                delete m_psl;
                m_psl = NULL;
            } 
            return;
        }
    private:
        static Singelton* m_psl;
} 
Singelton* Singelton::m_psl = new Singelton;  //单例构造了 
int main(void)
{
    printf("我不是先执行的\n");  //单例先构造 
    Singelton *p1 = Singelton::GetInstance();
    Singelton *p2 = Singelton::GetInstance();
    if (p1 == p2)
    {
        cout << "p1和p2指向同一个对象" << endl; 
    }
    else
    {
        cout << "p1和p2指向不同对象" << endl; 
    }
    Singelton::FreeInstance();

    return 0;
}
//简单工厂模式属于类的创建型模式,又叫做静态工厂方法模式。
//通过专门定义一个工厂来负责创建其他的实例,被创建的实例通常都具有共同的父类 
#include <iostream>
using namespace std;
class Fruit
{
    public:
        virtual void GetFruit()=0;     
};
class Banana : public Fruit
{
    public:
        virtual void GetFruit()
        {
            cout << "我是香蕉" << endl;
        }     
    protected:
    private:
}
class Apple : public Fruit
{
    public:
        virtual void GetFruit()
        {
            cout << "我是苹果" << endl;
        }     
    protected:
    private:
};
class Factory
{
    public:
        Fruit* Create(char *p)
        {
            if (strcmp(p, "banana"))
            {
                return new Banana;
            }
            if (strcmp(p, "apple"))
            {
                return new Banana;
            }
            else
            {
                 cout << "不支持创建" << endl; 
                return NULL;  
            }
        }     
    protected:
    private:
};
int main()
{
    Factory* f = new Factory;
    Fruit* fruit = NULL;

    //工厂生产香蕉 
    fruit = f->Create("banane");
    fruit->GetFruit();
    delete fruit;

    //工厂生产苹果 
    fruit = f->Create("apple"); 
    fruit->GetFruit();
    delete fruit;

    return 0;
}