#完美世界
##c++的析构函数能否为虚函数
父类指针可以指向子类的对象(多态性),如果删除该指针delete []p;就会调用该指针指向的子类析构函数,而子类的析构函数又自动调用父类的析构函数,这样整个子类的对象完全被释放。如果析构函数不被声明成虚函数,则编译器实施静态绑定,在删除父类指针时,只会调用父类的析构函数而不调用子类析构函数,这样就会造成子类对象析构不完全。所以,将析构函数声明为虚函数是十分必要的。
##为什么基类的析构函数是虚函数?
在实现多态时,当用父类操作子类,在析构时防止只析构父类而不析构子类的状况发生。
##B继承A,调用A的析构函数,AB析构顺序;调用B的析构函数,AB析构顺序;
回来之后想了想,好像是这么个思路不知道对不对
B继承了A,调用A的析构函数,那么说明创建了个A对象调用A的构造函数,然后调用A的析构函数,跟B没关系,B不会调用他的构造函数与析构函数;而调用B的析构函数,那么说明创建了个B对象 ,调用了A的构造函数,调用了B的构造函数,然后析构B在析构A;
#迅雷
##哈希表
不会
##十亿数中找相同的数字
##反转链表
ListNode * ReverseList(ListNode * pHead)
{
if(phead == NULL)
{
return NULL;
}
if(phead->next == NULL)
{
return pHead;
}
ListNode * pBefore = pHead;
ListNode * p = pHead->next;
ListNode * pAfter = p->next;
while(pAfter != NULL)
{
p->next = pBefore;
pBefore = p;
pAfter = pAfter->next;
}
p->next = pBefore;
pHead->next = NULL;
return p;
}
##epoll
epoll提供了三个函数,epoll_creat,epoll_ctl和epoll_wait,epoll_creat是创建一个epoll句柄,epoll_ctl是注册要监听的事件类型,epoll_wait则是等待时间的产生
epoll对于线程是安全的
epoll的编码流程
创建epoll描述符
注册epoll事件
等待epoll事件
判断触发epoll事件的描述符和事件
关闭epoll描述符
在这里,我们将select和poll以及epoll都写下
select的几大缺点:
(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
(3)select支持的文件描述符数量太小了,默认是1024
poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。
epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD)
会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。
epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,
而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,
当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。
epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd。
##虚函数
简单地说,那些被virtual关键字修饰的成员函数,就是虚函数。
多态实现的三个条件:
继承,虚函数重写,父类指针指向子类对象
当类中声明虚函数时,编译器会在类中生成一个虚函数表
虚函数表是一个存储类成员函数指针的数据结构
虚函数表是由编译器自动生成与维护的
virtual成员函数会被编译器放入虚函数表中
通过虚函数表指针vptr调用重写函数是在程序运行时进行的,因此需要通过寻址操作才能确定真正应该调用的函数,而普通成员函数是在编译时就确定了调用的函数,在效率上虚函数的效率要低很多
##Tcp的time_wait状态
time_wait状态是四次挥手中server向client发送FIN终止连接后进入的状态。
当处于time_wait状态时,我们无法创建新的连接,由于port被占用。
##内存对齐
对齐原则:
原则1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
原则2:结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
原则3:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。
##C语言的动态联编和静态联编
1.联编是指一个程序模块,代码之间互相关联的过程
2.静态联编,是程序的匹配,链接在编译阶段实现,也成为早期匹配,重载函数使用静态联编
3.动态联编是指程序联编推迟到运行时进行,所以又成为晚期联编(迟联编)switch语句和if语句是动态联编的例子
4.理论联系实际
①c++和c相同,是静态编译型语句
②在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象,所以编译器认为父类指针指向的是父类对象
③由于程序没有运行,所以不可能知道父类指针指向的具体是父类对象还是子类对象,从程序安全的角度,编译器假设父类指针只指向父类对象,因此编的结果为调用父类的成员函数,这样特征就是静态联编
不写virtual关键字是静态联编
动态联编:加了virtual关键字,c++对这个函数特殊处理,在运行的时候,根据具体对象(具体的类型),执行不同对象的函数,实现成多态