C++ 面试题整理

0. C和C++的区别?C++的特性?面向对象编程的好处?

答:c++在c的基础上增添类,C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制),而对于C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。

好处:

1、维护简单:模块化是面向对象编程中的一个特征。实体被表示为类和同一名字空间中具有相同功能的类,我们可以在名字空间中添加一个类而不会影响该名字空间的其他成员。

2、可扩充性:面向对象编程从本质上支持扩充性。如果有一个具有某种功能的类,就可以很快地扩充这个类,创建一个具有扩充的功能的类。

3、代码重用:由于功能是被封装在类中的,并且类是作为一个独立实体而存在的,提供一个类库就非常简单。

C++特性:抽象,封装,继承,多态

1. C++中,一个父类,一个子类,相互有引用关系。如何设计使其使用时,没有内存释放异常和泄漏?

考点:智能指针,循环引用,weak_ptr

普通指针,释放时,智能选择一个对象释放,否则会出现重复释放报错。

shared_ptr使用时,会出现内存泄漏。

需要将对象内的属性,改为weak_ptr类型。

2. 设计一个线程安全的swap函数。

考点:多线程,线程安全,互斥锁

扫描二维码关注公众号,回复: 6138016 查看本文章
void swap(int &a, int &b)
{
    a.lock();
    b.lock();
    tmp = a;
    a = b;
    b = tmp;
}
// 此时,swap(x, y)和swap(y, x)同时执行,就会发生死锁。

void swap(int &a, int &b)
{
    // 先对地址做比较,总是先锁地址小的。便不会死锁
    if (&&a < &&b)
    {
        a.lock();
        b.lock();
    }
    else
    {
        b.lock();
        a.lock();
    }
    tmp = a;
    a = b;
    b = tmp;
}    

3. 有A,B,C三个类,设计一个打印函数,可以灵活的打印,A,B,C三个类的对象。

考点:tuple & 变参模板

template
void Print(T value)
{
    std::cout << value << std::endl;
}

template
void Print(Head head, Rail... rail)
{
    std::cout << head << ", ";
    Print(rail...);
}

int main(int argc, _TCHAR* argv[])
{
    Print(1);
    Print("hello", 1);
    Print(1, "hello");
    Print(1, "hello", 'H');
    getchar();
    return 0;
}

4. TCP和UDP有什么区别

考点:网络协议

     TCP---传输控制协议,提供的是面向连接、可靠的字节流服务。

                 当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。

                 TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

     UDP---用户数据报协议,是一个简单的面向数据报的运输层协议。

                 UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。

                 由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快

5. 多线程,是并发线程越多越好吗?

考点:多线程

不是,线程多了可以提高程序并行执行的速度,但是并不是越多越好,其中,每个线程都要占用内存,多线程就意味着更多的内存资源被占用,其二,从微观上讲,一个cpu不是同时执行两个线程的,他是轮流执行的,所以线程太多,cpu必须不断的在各个线程间快回更换执行,线程间的切换无意间消耗了许多时间,所以cpu有效利用率反而是下降的

6. 如果是单核CPU,还有必要使用多线程吗?使用多线程的场景。

考点:多线程

即使是单核,使用多线程也是有意义的
        1)多线程编码可以让我们的服务/代码更加清晰,有些IO线程收发包,有些Worker线程进行任务处理,有些Timeout线程进行超时检测
         2)如果有一个任务一直占用CPU资源在进行计算,那么此时增加线程并不能增加并发,例如这样的一个代码
         while(1){ i++; }
         该代码一直不停的占用CPU资源进行计算,会使CPU占用率达到100%


         3)通常来说,Worker线程一般不会一直占用CPU进行计算,此时即使CPU是单核,增加Worker线程也能够提高并发,因为这个线程在休息的时候,其他的线程可以继续工作

7. RAII编程思想。

考点:编程技巧

RAII:获取资源即初始化

RAII的主要原则是为将任何堆分配资源(如动态分配内存或系统对象句柄)的所有权提供给其析构函数包含用于删除或释放资源的代码以及任何相关清理代码的堆栈分配对象

8. QT信号槽的原理

https://blog.csdn.net/a844651990/article/details/79311078

9. QT事件与信号槽的区别

   仔细来看,事件与信号其实并无多大差别,从我们对其需求上来说,都只要能注册事件或信号响应函数,在事件或信号产生时能够被通知到即可。但有一项区别在于,事件处理函数的返回值是有意义的,我们要根据这个返回值来确定是否还要继续事件的处理,比如在QT中,事件处理函数如果返回true,则这个事件处理已完成,QApplication会接着处理下一个事件,而如果返回false,那么事件分派函数会继续向上寻找下一个可以处理该事件的注册方法。信号处理函数的返回值对信号分派器来说是无意义的。

    另外还有一个需要我们关注的问题是事件和信号处理时的优先级问题。在QT中,事件因为都是与窗口相关的,所以事件回调时都是从当前窗口开始,一级一级向上派发,直到有一个窗口返回true,截断了事件的处理为止。对于信号的处理则比较简单,默认是没有顺序的,如果需要明确的顺序,可以在信号注册时显示地指明槽的位置。

    在QT中,事件使用了一个事件队列来维护,如果事件的处理中又产生了新的事件,那么新的事件会加入到队列尾,直到当前事件处理完毕后, QApplication再去队列头取下一个事件来处理。而信号的处理方式有些不同,信号处理是立即回调的,也就是一个信号产生后,他上面所注册的所有槽都会立即被回调。这样就会产生一个递归调用的问题,比如某个信号处理器中又产生了一个信号,会使得信号的处理像一棵树一样的展开。

10. tableview,树节点切换时,需要检测是否可以切换。如何实现?

信号只有changed. 需要重写mousepress事件。


11. 

猜你喜欢

转载自blog.csdn.net/d_chunyu/article/details/89819642