可爱糖葫芦 發表於 2020-5-11 10:01:00

面试-QT版本

<h1><strong>QT信号槽机制的优缺点</strong></h1>
<p><strong><span style="font-family: 宋体">(</span>1<span style="font-family: 宋体">)问题:</span></strong></p>
<p><span style="font-family: 宋体">为什么</span>Qt<span style="font-family: 宋体">使用信号与槽机制而不是传统的回调函数机制进行对象间的通信呢?</span></p>
<p><span style="font-family: 宋体">回调函数的本质是</span>“你想让别人的代码执行你的代码,而别人的代码你又不能动”这种需求下产生的。</p>
<p>回调函数是函数指针的一种用法,如果多个类都关注某个类的状态变化,此时需要维护一个列表,以存放多个回调函数的地址。对于每一个被关注的类,都需要做类似的工作,因此这种做法效率低,不灵活。</p>
<p><strong><span style="font-family: 宋体">(</span>2<span style="font-family: 宋体">)解决办法:</span></strong></p>
<p>Qt<span style="font-family: 宋体">使用信号与槽机制来解决这个问题,程序员只需要指定一个类含有哪些信号函数、哪些槽函数,</span><span style="font-family: Calibri">Qt</span><span style="font-family: 宋体">会处理信号函数和槽函数之间的绑定。当信号函数被调用时,</span><span style="font-family: Calibri">Qt</span><span style="font-family: 宋体">会找到并执行与其绑定的槽函数。允许一个信号函数和多个槽函数绑定,</span><span style="font-family: Calibri">Qt</span><span style="font-family: 宋体">会依次找到并执行与一个信号函数绑定的所有槽函数,这种处理方式更灵活。</span></p>
<p><strong><span style="font-family: 宋体">(</span>3<span style="font-family: 宋体">)优点</span><span style="font-family: Calibri">:</span></strong></p>
<p>Qt<span style="font-family: 宋体">信号与槽机制降低了</span><span style="font-family: Calibri">Qt</span><span style="font-family: 宋体">对象的耦合度</span><span style="font-family: Calibri">.</span></p>
<p><span style="font-family: 宋体">相关资料:</span>https://blog.csdn.net/QIJINGBO123/article/details/86155060</p>
<p>&nbsp;</p>
<h1><strong><span style="font-family: 微软雅黑">多线程情况下</span>, Qt中的信号槽分别在什么线程中执行, 如何控制?</strong></h1>
<p><span style="font-family: 宋体">通过</span>connect<span style="font-family: 宋体">函数的第五个参数</span><span style="font-family: Calibri">connectType</span><span style="font-family: 宋体">来控制。</span></p>
<p>connect<span style="font-family: 宋体">用于连接</span><span style="font-family: Calibri">qt</span><span style="font-family: 宋体">的信号和槽,在</span><span style="font-family: Calibri">qt</span><span style="font-family: 宋体">编程过程中不可或缺。它其实有第五个参数,只是一般使用默认值,在满足某些特殊需求的时候可能需要手动设置。</span>&nbsp;</p>
<p><strong>Qt::AutoConnection</strong><span style="font-family: 宋体"><strong>:</strong> 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用</span><span style="font-family: Calibri">Qt::DirectConnection</span><span style="font-family: 宋体">类型。如果接收者和发送者不在一个线程,则自动使用</span><span style="font-family: Calibri">Qt::QueuedConnection</span><span style="font-family: 宋体">类型。</span>&nbsp;</p>
<p><strong>Qt::DirectConnection</strong><span style="font-family: 宋体"><strong>:</strong>槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。</span>&nbsp;</p>
<p><strong>Qt::QueuedConnection</strong><span style="font-family: 宋体"><strong>:</strong>槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。</span>&nbsp;</p>
<p><strong>Qt::BlockingQueuedConnection</strong><span style="font-family: 宋体"><strong>:</strong>槽函数的调用时机与</span><span style="font-family: Calibri">Qt::QueuedConnection</span><span style="font-family: 宋体">一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。</span>&nbsp;</p>
<p><strong>Qt::UniqueConnection</strong><span style="font-family: 宋体"><strong>:</strong>这个</span><span style="font-family: Calibri">flag</span><span style="font-family: 宋体">可以通过按位或(</span><span style="font-family: Calibri">|</span><span style="font-family: 宋体">)与以上四个结合在一起使用。当这个</span><span style="font-family: Calibri">flag</span><span style="font-family: 宋体">设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。</span></p>
<p><span style="font-family: 宋体">相关资料:</span>https://blog.csdn.net/QIJINGBO123/article/details/86155060</p>
<p>&nbsp;</p>
<h1><strong>Qt 信号槽机制</strong></h1>
<p><strong>自定义信号槽注意事项:</strong></p>
<p><span style="font-family: 宋体">(</span>1<span style="font-family: 宋体">)发送者和接收者都需要是</span><span style="font-family: Calibri">QObject</span><span style="font-family: 宋体">的子类(当然,槽函数是全局函数、</span><span style="font-family: Calibri">Lambda </span><span style="font-family: 宋体">表达式等无需接收者的时候除外);</span></p>
<p><span style="font-family: 宋体">(</span>2<span style="font-family: 宋体">)使用 </span><span style="font-family: Calibri">signals </span><span style="font-family: 宋体">标记信号函数,信号是一个函数声明,返回 </span><span style="font-family: Calibri">void</span><span style="font-family: 宋体">,不需要实现函数代码;</span></p>
<p><span style="font-family: 宋体">(</span>3<span style="font-family: 宋体">)槽函数是普通的成员函数,作为成员函数,会受到 </span><span style="font-family: Calibri">public</span><span style="font-family: 宋体">、</span><span style="font-family: Calibri">private</span><span style="font-family: 宋体">、</span><span style="font-family: Calibri">protected </span><span style="font-family: 宋体">的影响;</span></p>
<p><span style="font-family: 宋体">(</span>4<span style="font-family: 宋体">)使用 </span><span style="font-family: Calibri">emit </span><span style="font-family: 宋体">在恰当的位置发送信号;</span></p>
<p><span style="font-family: 宋体">(</span>5<span style="font-family: 宋体">)使用</span><span style="font-family: Calibri">QObject::connect()</span><span style="font-family: 宋体">函数连接信号和槽;</span></p>
<p><span style="font-family: 宋体">(</span>6<span style="font-family: 宋体">)任何成员函数、</span><span style="font-family: Calibri">static </span><span style="font-family: 宋体">函数、全局函数和 </span><span style="font-family: Calibri">Lambda </span><span style="font-family: 宋体">表达式都可以作为槽函数。</span></p>
<p><strong>信号槽的多种用法:</strong></p>
<p><span style="font-family: 宋体">(</span>1<span style="font-family: 宋体">)一个信号可以和多个槽相连</span></p>
<p>  如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的。</p>
<p><span style="font-family: 宋体">(</span>2<span style="font-family: 宋体">)多个信号可以连接到一个槽</span></p>
<p>  只要任意一个信号发出,这个槽就会被调用。</p>
<p><span style="font-family: 宋体">(</span>3<span style="font-family: 宋体">)一个信号可以连接到另外的一个信号</span></p>
<p><span style="font-family: 宋体">  当第一个信号发出时,第二个信号被发出。除此之外,这种信号</span>-<span style="font-family: 宋体">信号的形式和信号</span><span style="font-family: Calibri">-</span><span style="font-family: 宋体">槽的形式没有什么区别。</span></p>
<p><span style="font-family: 宋体">(</span>4<span style="font-family: 宋体">)槽可以被取消链接</span></p>
<p><span style="font-family: 宋体">  这种情况并不经常出现,因为当一个对象</span>delete<span style="font-family: 宋体">之后,</span><span style="font-family: Calibri">Qt</span><span style="font-family: 宋体">自动取消所有连接到这个对象上面的槽。</span></p>
<p><span style="font-family: 宋体">(</span>5<span style="font-family: 宋体">)使用</span><span style="font-family: Calibri">Lambda </span><span style="font-family: 宋体">表达式</span></p>
<p><span style="font-family: 宋体">在使用</span> Qt 5 <span style="font-family: 宋体">的时候,能够支持 </span><span style="font-family: Calibri">Qt 5 </span><span style="font-family: 宋体">的编译器都是支持 </span><span style="font-family: Calibri">Lambda </span><span style="font-family: 宋体">表达式的。</span></p>
<p>相关资料:https://blog.csdn.net/QIJINGBO123/article/details/86155060</p>
<p>&nbsp;</p>
<h1><strong>继承与派生的区别</strong></h1>
<p class="p"><strong>1<span style="font-family: 宋体">、角度不同</span></strong></p>
<p class="p">继承是从子类的角度讲的,派生是从基类的角度讲的。</p>
<p class="p"><strong>2<span style="font-family: 宋体">、定义不同</span></strong></p>
<p class="p"><span style="font-family: 宋体">派生指江河的源头产生出支流。引申为从一个主要事物的发展中分化出来。继承</span>&nbsp;<span style="font-family: 宋体">是面向对象软件技术当中的一个概念,与多态、抽象共为面向对象的三个基本特征。 继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。</span></p>
<p class="p">https://blog.csdn.net/weixin_42325069/article/details/84105347</p>
<p class="p">&nbsp;</p>
<h1><strong><span style="font-family: 微软雅黑">单继承和多继承</span></strong></h1>
<p><strong><span style="font-family: 宋体">单继承(派生类只从一个直接基类继承)时派生类的定义:</span></strong></p>
<p><span style="font-size: 12px; color: rgba(0, 0, 255, 1)"><strong>class <span style="font-family: 宋体">派生类名:继承方式 基类名</span></strong></span></p>
<p><span style="font-size: 12px; color: rgba(0, 0, 255, 1)"><strong>{</strong></span></p>
<p><span style="font-size: 12px; color: rgba(0, 0, 255, 1)"><strong><span style="font-family: 宋体">新增成员声明;</span></strong></span></p>
<p><span style="font-size: 12px; color: rgba(0, 0, 255, 1)"><strong>}</strong></span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: 宋体">多继承时派生类的定义:</span></strong></p>
<p><span style="font-size: 12px; color: rgba(0, 0, 255, 1)"><strong>class <span style="font-family: 宋体">派生类名:继承方式</span><span style="font-family: Calibri">1 </span><span style="font-family: 宋体">基类名</span><span style="font-family: Calibri">1</span><span style="font-family: 宋体">,继承方式</span><span style="font-family: Calibri">2 </span><span style="font-family: 宋体">基类名</span><span style="font-family: Calibri">2</span><span style="font-family: 宋体">,</span><span style="font-family: Calibri">…</span></strong></span></p>
<p><span style="font-size: 12px; color: rgba(0, 0, 255, 1)"><strong>{</strong></span></p>
<p><span style="font-size: 12px; color: rgba(0, 0, 255, 1)"><strong><span style="font-family: 宋体">成员声明;</span></strong></span></p>
<p><span style="font-size: 12px; color: rgba(0, 0, 255, 1)"><strong>}</strong></span></p>
<p><span style="font-family: 宋体"><span style="color: rgba(255, 0, 0, 1)"><strong>注意:</strong></span>每一个</span>“<span style="font-family: 宋体">继承方式</span><span style="font-family: Calibri">”</span><span style="font-family: 宋体">,只用于限制对紧随其后之基类的继承。</span></p>
<p>https://blog.csdn.net/weixin_42325069/article/details/84105347</p>
<p>&nbsp;</p>
<h1><strong><span style="font-family: 微软雅黑">三种继承方式:公有继承,私有继承和保护继承</span></strong></h1>
<p><strong><span style="font-family: 宋体">公有继承</span>(public)</strong></p>
<p>1<span style="font-family: 宋体">)继承的访问控制</span></p>
<p><span style="font-family: 宋体">基类的</span>public<span style="font-family: 宋体">和</span><span style="font-family: Calibri">protected</span><span style="font-family: 宋体">成员:访问属性在派生类中保持不变;</span></p>
<p><span style="font-family: 宋体">基类的</span>private<span style="font-family: 宋体">成员:不可直接访问。</span></p>
<p><strong>2<span style="font-family: 宋体">)访问权限</span></strong></p>
<p><span style="font-family: 宋体">派生类中的成员函数:可以直接访问基类中的</span>public<span style="font-family: 宋体">和</span><span style="font-family: Calibri">protected</span><span style="font-family: 宋体">成员,但不能直接访问基类的</span><span style="font-family: Calibri">private</span><span style="font-family: 宋体">成员;</span></p>
<p><span style="font-family: 宋体">通过派生类的对象:只能访问</span>public<span style="font-family: 宋体">成员。</span></p>
<p><strong>3<span style="font-family: 宋体">)公有派生类对象可以被当作基类的对象使用,反之则不可。</span></strong></p>
<p>派生类的对象可以隐含转换为基类对象;</p>
<p>派生类的对象可以初始化基类的引用;</p>
<p>派生类的指针可以隐含转换为基类的指针。</p>
<p>通过基类对象名、指针只能使用从基类继承的成员,派生类新增的成员就不能使用了。</p>
<p>https://blog.csdn.net/weixin_42325069/article/details/84105347</p>
<p>&nbsp;</p>
<h1><strong>Qt4与Qt5的三个区别</strong></h1>
<p><strong>1.<span style="font-family: 宋体">新增</span><span style="font-family: Calibri">widgets</span><span style="font-family: 宋体">模块</span></strong></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span style="font-family: 宋体">在</span><span style="font-family: Calibri">Qt4</span><span style="font-family: 宋体">中,</span><span style="font-family: Calibri">Qt</span><span style="font-family: 宋体">提供的全部图形界面相关类都包含在</span><span style="font-family: Calibri">Qt Gui</span><span style="font-family: 宋体">模块中,但</span><span style="font-family: Calibri">QT5</span><span style="font-family: 宋体">将一些图形界面类移到了</span><span style="font-family: Calibri">QT widgets</span><span style="font-family: 宋体">模块中。所以在</span><span style="font-family: Calibri">Pro</span><span style="font-family: 宋体">文件中,需要增加一句话:</span></p>
<p>greaterThan(QT_MAJOR_VERSION, 4):QT += widgets</p>
<p><span style="font-family: 宋体">意思是如果</span>Qt<span style="font-family: 宋体">版本大于</span><span style="font-family: Calibri">Qt4</span><span style="font-family: 宋体">,则需要增加</span><span style="font-family: Calibri">widgets</span><span style="font-family: 宋体">模块。</span></p>
<p><strong>2.<span style="font-family: 宋体">信号与槽的语法</span></strong></p>
<p>&nbsp;Qt4<span style="font-family: 宋体">中关联信号与槽一般这样写:</span></p>
<p>connect(sender, SINGAL(valueChanged(QString, QString)), receiver, SLOT(showValue(QString)));</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; <span style="font-family: 宋体">但这样写,没有编译器检查,有时编译器通过但应该调用的槽函数没有执行。这是编译器不能给出错误信息,只能在运行时看是否有警告。</span></p>
<p>Qt5<span style="font-family: 宋体">中关联信号与槽是这样写:</span></p>
<p>connect(sender, &amp;Sender::valueChanged, receiver, &amp;Receiver::showValue);</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="font-family: 宋体">这种写法支持编译器检查,能够在编译时就发现错误;并支持类型的隐式转换。</span></p>
<p><strong>3.<span style="font-family: 宋体">对</span><span style="font-family: Calibri">C++11</span><span style="font-family: 宋体">的支持</span></strong></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Qt5<span style="font-family: 宋体">支持</span><span style="font-family: Calibri">C++11</span><span style="font-family: 宋体">,但有些编译器默认不开启。所以需要在</span><span style="font-family: Calibri">Pro</span><span style="font-family: 宋体">文件中增加一行:</span></p>
<p><span style="font-size: 12px"><strong><span style="color: rgba(0, 0, 255, 1)">CONFIG &nbsp;+= &nbsp;c++11</span></strong></span></p>
<p>https://blog.csdn.net/c1n2k3000/article/details/97620480</p>
<p>&nbsp;</p>
<h1><strong><span style="font-family: 微软雅黑">多态</span></strong></h1>
<p><span style="font-family: 宋体">多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。</span></p>
<p>C++<span style="font-family: 宋体">中,实现多态有以下方法:</span><span style="font-family: 宋体">虚函数</span><span style="font-family: 宋体">,</span><span style="font-family: 宋体">抽象类</span><span style="font-family: 宋体">,覆盖,模板(重载和多态无关)。</span></p>
<p>&nbsp;</p>
<h1><strong>C++ 类(纯虚函数和抽象类)</strong></h1>
<p>a. <span style="font-family: 宋体">纯虚函数是一个在基类中只有声明的虚函数</span><span style="font-family: Arial">,</span><span style="font-family: 宋体">在基类中无定义。要求在任何派生类中都定义自己的版本</span><span style="font-family: Arial">; </span></p>
<p>b. <span style="font-family: 宋体">纯虚函数为各派生类提供一个公共界面</span><span style="font-family: Arial">(</span><span style="font-family: 宋体">接口的封装和设计</span><span style="font-family: Arial">,</span><span style="font-family: 宋体">软件的模块功能划分</span><span style="font-family: Arial">); </span></p>
<p>c. <span style="font-family: 宋体">纯虚函数声明形式</span><span style="font-family: Arial">:</span></p>
<p>virtual void func()=0; &nbsp;//<span style="font-family: 宋体">纯虚函数</span></p>
<p>d. <span style="font-family: 宋体">一个具有纯虚函数的类称为抽象类。</span></p>
<p><span style="font-family: 宋体">结论</span>:</p>
<p>(1). <span style="font-family: 宋体">抽象类对象不能做函数参数</span><span style="font-family: Arial">,</span><span style="font-family: 宋体">不能创建对象</span><span style="font-family: Arial">,</span><span style="font-family: 宋体">不能作为函数返回类型</span><span style="font-family: Arial">;</span></p>
<p>(2).<span style="font-family: 宋体">可以声明抽象类指针</span><span style="font-family: Arial">,</span><span style="font-family: 宋体">可以声明抽象类的引用</span><span style="font-family: Arial">;</span></p>
<p>(3). <span style="font-family: 宋体">子类必须继承父类的纯虚函数才能创建对象。</span></p>
<p>https://blog.csdn.net/wue1206/article/details/81283280</p>
<p>&nbsp;</p>
<h1><strong>QMainForm是从哪里派生的?</strong></h1>
<p class="pre">QMainWindow::QWidget::QObject</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong>Qwidget、Qobejct实现了哪些功能</strong></h1>
<p class="pre"><strong>QObject</strong></p>
<ol>
<li>信号和槽<span style="font-family: 宋体">的非常强大的机制</span>,<span style="font-family: 宋体">使用</span>connect()<span style="font-family: 宋体">把信号和槽连接起来并且可以用</span>disconnect()<span style="font-family: 宋体">来破坏这种连接。为了避免从不结束的通知循环,你可以调用</span>blockSignals()<span style="font-family: 宋体">临时地阻塞信号。保护函数</span>connectNotify()<span style="font-family: 宋体">和</span>disconnectNotify()<span style="font-family: 宋体">使跟踪连接成为可能。</span></li>
<li>QObject<span style="font-family: 宋体">可以通过</span>event()<span style="font-family: 宋体">接收事件并且过滤其它对象的事件。详细情况请参考</span>installEventFilter()<span style="font-family: 宋体">和</span>eventFilter()<span style="font-family: 宋体">。一个方便的处理者,</span>childEvent()<span style="font-family: 宋体">,能够被重新实现来捕获子对象事件。</span></li>
<li><span style="font-family: 宋体">最后但不是最不重要的一点,</span>QObject<span style="font-family: 宋体">提供了</span><span style="font-family: Calibri">Qt</span><span style="font-family: 宋体">中最基本的定时器,关于定时器的高级支持请参考</span>QTimer。</li>
<li>注意Q_OBJECT宏对于任何实现信号、槽和属性的对象都是强制的。</li>
<li><span style="font-family: 宋体">所有的</span>Qt<span style="font-family: 宋体">窗口部件继承了</span><span style="font-family: Calibri">QObject</span><span style="font-family: 宋体">。方便的函数</span>isWidgetType()<span style="font-family: 宋体">返回这个对象实际上是不是一个窗口部件。它比</span>inherits( "QWidget" )<span style="font-family: 宋体">快得多。</span></li>
</ol>
<p class="pre"><strong>&nbsp;QWidget</strong></p>
<ol>
<li>QWidget<span style="font-family: 宋体">类是所有用户界面对象的基类。</span></li>
<li>Widget<span style="font-family: 宋体">是用户界面的基本单元:它从窗口系统接收鼠标,键盘和其他事件,并在屏幕上绘制自己。每个</span><span style="font-family: Verdana">Widget</span><span style="font-family: 宋体">都是矩形的,它们按照</span><span style="font-family: Verdana">Z-order</span><span style="font-family: 宋体">进行排序。</span></li>
</ol>
<p class="pre"><img src="https://images.cnblogs.com/cnblogs_com/FKdelphi/883780/o_200511020327QT%E7%B1%BB%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB%E5%9B%BE.png" alt="" width="1055" height="552"></p>
<p class="pre">http://focus.blog.chinaunix.net/uid-22666248-id-1746350.html</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong>C++指针和引用及区别</strong>&nbsp;</h1>
<p class="pre"><strong>1.变量</strong></p>
<p class="pre"><span style="font-family: 宋体">变量在内存中的操作其实是需要经过</span>2个步骤的:</p>
<p class="pre">找出与变量名相对应的内存地址。</p>
<p class="pre">根据找到的地址,取出该地址对应的内存空间里面的值进行操作。</p>
<p class="pre"><strong>2.指针</strong></p>
<p class="pre">指针的特殊之处在于:指针变量相对应的内存空间存储的值恰好是某个内存地址。这也是指针变量区别去其他变量的特征之一。</p>
<p class="pre"><strong>3.引用</strong></p>
<p class="pre">引用是一种特殊的指针。引用是一个指向其它对象的常量指针,它保存着所指对象的存储地址。并且使用的时候会自动解引用,而不需要像使用指针一样显式提领。</p>
<p class="pre"><strong>4.指针和引用的区别总结</strong></p>
<p class="pre">①指针有自己的一块空间,而引用只是一个别名;</p>
<p class="pre">②使用sizeof看一个指针的大小是4,而引用则是被引用对象的大小;</p>
<p class="pre">③指针可以被初始化为NULL,而引用必须被初始化且必须是一个已有对象的引用;</p>
<p class="pre">④作为参数传递时,指针需要被解引用才可以对对象进行操作,而直接对引用的修改都会改变引用所指向的对象;</p>
<p class="pre">⑤可以有const指针,但是没有const引用;</p>
<p class="pre">⑥指针在使用中可以指向其它对象,但是引用只能是一个对象的引用,不能被改变;</p>
<p class="pre">⑦指针可以有多级指针(**p),而引用至于一级;</p>
<p class="pre">⑧指针和引用使用++运算符的意义不一样;</p>
<p class="pre">⑨如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄露。&nbsp;</p>
<p class="pre">https://www.cnblogs.com/WindSun/p/11434417.html</p>
<p class="pre">https://blog.csdn.net/cherrydreamsover/article/details/81839010</p>
<p class="pre">&nbsp;&nbsp;</p>
<h1 class="pre"><strong><span style="font-family: 微软雅黑">参数传值、指针、引用有什么区别,在什么场景常用哪种传递方式?</span></strong></h1>
<p class="pre">传值、传址、传引用的区别,哪个更高效?</p>
<p class="pre"><strong>1.传值</strong></p>
<p class="pre"><span style="font-family: 宋体">这种传递方式中,实参和形参是两个不同的地址空间,参数传递的实质是将原函数中变量的值,复制到被调用函数形参所在的存储空间中,这个形参的地址空间在函数执行完毕后,会被回收掉。整个被调用函数对形参的操作,只影响形参对应的地址空间,不影响原来函数中的变量的值,因为这两个不是同一个存储空间。</span></p>
<p class="pre">即使形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。</p>
<p class="pre"><strong>2.传址</strong></p>
<p class="pre"><span style="font-family: 宋体">这种参数传递方式中,实参是变量的地址,形参是指针类型的变量,在函数中对指针变量的操作,就是对实参(变量地址)所对应的变量的操作,函数调用结束后,原函数中的变量的值将会发生改变。</span></p>
<p class="pre">被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。</p>
<p class="pre"><strong>3.传引用</strong></p>
<p class="pre"><span style="font-family: 宋体">这种参数传递方式中,形参是引用类型变量,其实就是实参的一个别名,在被调用函数中,对引用变量的所有操作等价于对实参的操作,这样,整个函数执行完毕后,原先的实参的值将会发生改变。</span></p>
<p class="pre">被调函数对形参做的任何操作都影响了主调函数中的实参变量。</p>
<p class="pre"><strong>4.哪一种更高效?</strong></p>
<p class="pre">在内置类型当中三种传递方式的效率上都差不多;</p>
<p class="pre">在自定义类型当中,传引用的更高效一些,因为它没有对形参进行一次拷贝</p>
<p class="pre">https://blog.csdn.net/cherrydreamsover/article/details/81839010</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong>const与#define有什么区别</strong></h1>
<p class="pre"><span style="font-family: 宋体">(</span>1)const和#define都可以定义常量,但是const用途更广。</p>
<p class="pre"><span style="font-family: 宋体">(</span>2)const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。<br><span style="font-family: 宋体">(</span>3) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong>struct和class有什么区别?</strong></h1>
<p class="pre">C++中,class与struct都可以定义一个类。他们有以下两点区别:</p>
<p class="pre">1.默认继承权限,如果不指定,来自class的继承按照private继承处理,来自struct的继承按照public继承处理;</p>
<p class="pre">2.成员的默认访问权限。class的成员默认是private权限,struct默认是public权限。</p>
<p class="pre"><span style="font-family: 宋体">以上两点也是</span>struct和class最基本的差别,也是最本质的差别;&nbsp;</p>
<p class="pre"><span style="font-family: 宋体">但是在</span>C++中,struct进行了扩展,现在它已经不仅仅是一个包含不同数据类型的数据结构了,它包括了更多的功能。</p>
<p class="pre">Struct能包含成员函数、有自己的构造函数、可以有析构函数、支持继承、支持多态、支持Private、Protected、Public关键字。&nbsp;</p>
<p class="pre"><span style="font-family: 宋体">如果是</span>class的父类是struct关键字描述的,那么默认访问属性是什么?</p>
<p class="pre"><span style="font-family: 宋体">当出现这种情况时,到底默认是</span>public继承还是private继承,取决于子类而不是基类。</p>
<p class="pre">class可以继承自struct修饰的类;同时,struct也可以继承自class修饰的类,继承属性如下列描述:</p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>class A{};</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>class B:A{}; // private 继承</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>struct B:A{}; // public 继承</strong></span></p>
<p class="pre"><span style="font-family: 宋体">最后,那么到底是使用</span>struct,还是使用class呢?</p>
<p class="pre"><span style="font-family: 宋体">一般来说,两个关键字都是可以的,但是由于编程规范的问题,如果要定义的是一种数据结构,那么用</span>struct,如果是一种对象的话,那么用class。</p>
<p class="pre">&nbsp;https://www.cnblogs.com/ZhenXin0101/p/11451694.html</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong>tdcall、stdcall、pascall是什么?C++默认是哪种?</strong></h1>
<p class="pre">__cdecl、__stdcall是声明的函数调用协议。主要是传参和弹栈方面的不同。&nbsp;</p>
<p class="pre"><strong>__cdecl:</strong></p>
<p class="pre"><span style="font-family: 宋体">一般</span>c++用的是__cdecl</p>
<p class="pre">函数参数按照从右到左的顺序入栈</p>
<p class="pre">由调用函数者把参数弹出栈以清理堆栈</p>
<p class="pre">PS:那么为什么还需要_cdecl呢?当我们遇到这样的函数如fprintf()它的参数是可变的,不定长的。&nbsp;</p>
<p class="pre"><strong>__stdcall:</strong></p>
<p class="pre">windows里大都用的是__stdcall(API) </p>
<p class="pre">函数参数按照从右到左的顺序入栈</p>
<p class="pre">被调用的函数在返回前清理传送参数的栈&nbsp;</p>
<p class="pre"><strong>__fastcall:</strong></p>
<p class="pre">约定用于对性能要求非常高的场合</p>
<p class="pre"><span style="font-family: 宋体">约定将函数的从左边开始的两个大小不大于</span>4个字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数仍旧自右向左压栈传送,</p>
<p class="pre">被调用的函数在返回前清理传送参数的堆栈&nbsp;</p>
<p class="pre">https://blog.csdn.net/p312011150/article/details/82229672</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong>static_cast, dynamic_cast, reinterpret_cast, const_cast区别比较</strong></h1>
<p class="pre"><strong>static_cast &lt;new_type&gt; (expression) 静态转换</strong></p>
<p class="pre">static_cast最接近于C风格转换了,但在无关类的类指针之间转换上,有安全性的提升</p>
<p class="pre"><span style="font-family: 宋体">该运算符把</span>exdivssion转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:</p>
<p class="pre">①用于类层次结构中基类和子类之间指针或引用的转换。</p>
<p class="pre">  进行上行转换(把子类的指针或引用转换成基类表示)是安全的;</p>
<p class="pre">  进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。</p>
<p class="pre">②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。</p>
<p class="pre">③把空指针转换成目标类型的空指针。</p>
<p class="pre">④把任何类型的表达式转换成void类型。</p>
<p class="pre"><span style="font-family: 宋体">注意:</span>static_cast不能转换掉exdivssion的const、volitale、或者__unaligned属性。</p>
<p class="pre">&nbsp;</p>
<p class="pre"><strong>dynamic_cast &lt;new_type&gt; (expression) 动态转换</strong></p>
<p class="pre"><span style="font-family: 宋体">动态转换确保类指针的转换是合适完整的,它有两个重要的约束条件,其一是要求</span>new_type为指针或引用,其二是下行转换时要求基类是多态的(基类中包含至少一个虚函数)。</p>
<p class="pre"><span style="font-family: 宋体">该运算符把</span>exdivssion转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;</p>
<p class="pre"><span style="font-family: 宋体">如果</span>type-id是类指针类型,那么exdivssion也必须是一个指针,如果type-id是一个引用,那么exdivssion也必须是一个引用。</p>
<p class="pre">dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。</p>
<p class="pre"><span style="font-family: 宋体">在类层次间进行上行转换时,</span>dynamic_cast和static_cast的效果是一样的;</p>
<p class="pre"><span style="font-family: 宋体">在进行下行转换时,</span>dynamic_cast具有类型检查的功能,比static_cast更安全。</p>
<p class="pre">&nbsp;</p>
<p class="pre"><strong>reinterpret_cast &lt;new_type&gt; (expression) 重解释转换</strong></p>
<p class="pre"><span style="font-family: 宋体">这个转换是最</span>“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现</p>
<p class="pre">&nbsp;</p>
<p class="pre"><strong>const_cast &lt;new_type&gt; (expression) 常量向非常量转换</strong></p>
<p class="pre">这个转换好理解,可以将常量转成非常量。</p>
<p class="pre">&nbsp;</p>
<p class="pre">https://blog.csdn.net/chenlycly/article/details/38713981</p>
<p class="pre">https://blog.csdn.net/u012411498/article/details/80804755</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong>C++内存分配有几种方式?</strong></h1>
<p class="pre">内存的三种分配方式:</p>
<p class="pre">1. <strong>从静态存储区分配:</strong>此时的内存在程序编译的时候已经分配好,并且在程序的整个运行期间都存在。全局变量,static变量等在此存储。</p>
<p class="pre">2.<strong> 在栈区分配:</strong>相关代码执行时创建,执行结束时被自动释放。局部变量在此存储。栈内存分配运算内置于处理器的指令集中,效率高,但容量有限。</p>
<p class="pre">3. <strong>在堆区分配:</strong>动态分配内存。用new/malloc时开辟,delete/free时释放。生存期由用户指定,灵活。但有内存泄露等问题。</p>
<p class="pre"><strong>常见内存错误及对策</strong></p>
<p class="pre"><strong>1. 内存分配未成功,却被使用。</strong></p>
<p class="pre"><span style="font-family: 宋体">对策:使用内存之前检查是否分配成功。用</span>p!=NULL判断。</p>
<p class="pre"><strong>2. 内存分配成功,未初始化就被使用。</strong></p>
<p class="pre"><span style="font-family: 宋体">内存的缺省值没有统一的标准。大部分编译器以</span>0作为初始值,但不完全是。</p>
<p class="pre">对策:内存初始化时赋初值。</p>
<p class="pre"><strong>3. 内存操作越界。</strong></p>
<p class="pre">对策:只能是小心了。</p>
<p class="pre"><strong>4. 释放了内存,仍然使用。</strong></p>
<p class="pre"><span style="font-family: 宋体">(</span>1) 使用显示delete和free的野指针。</p>
<p class="pre"><span style="font-family: 宋体">对策:释放完内存,将指针置为</span>NULL。</p>
<p class="pre"><span style="font-family: 宋体">(</span>2) 使用隐式delete和free的野指针。主要是指函数返回指向栈内存的指针或引用。</p>
<p class="pre">对策:当然是不要返回就可以了。</p>
<p class="pre"><strong>5. 未释放内存,导致内存泄露。</strong></p>
<p class="pre"><span style="font-family: 宋体">用</span>new/malloc开辟了内存,没用delete/free释放.</p>
<p class="pre"><span style="font-family: 宋体">对策:</span>new和delete的个数一定相同;malloc和free的个数一定相同;new[]和[]delete一定对应。</p>
<p class="pre">https://zhidao.baidu.com/question/2058022112316039427.html</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong><span style="font-family: 微软雅黑">模板的实现可以放在</span>cpp里吗?为什么?</strong></h1>
<p class="pre"><span style="font-family: 宋体">答:模板声明和实现要放在一个文件。因为放在</span>CPP里面实现会编译不过。</p>
<p class="pre">https://blog.csdn.net/woyaoxuechengxu/article/details/103095670</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong>C++中#ifndef, #define, #endif的作用和使用的注意事项</strong></h1>
<p class="pre">答:其实这几句代码的主要作用的官方解释是:为了防止头文件的重复包含和编译。</p>
<p class="pre"><span style="font-family: 宋体">具体来说就是,当你在设计一个很大很大的工程时,可能很多文件里面都会包含同一个头文件,可能你需要使用该头文件的目的完全是相同的,可是该头文件在声明时,如果没有加上上面三句代码在代码段的前后,当你将整个工程统一编译,希望链接成一个完整的可执行文件时,就会出现大量错误,因为每一个相同的头文件都会进行所谓的</span>“重定义”;而加上上面那三句,则不会出现“重定义”的情况。</p>
<p class="pre"><span style="font-family: 宋体">通俗来说,我们可以认为以上语句是一个判决条件,即类似于</span>if语句,当执行#ifndef XXX_H_语句时,去判断xxx.h头文件是否已经被定义过,如果是,就把#ifndef XXX_H_一直到#endif之间的代码段跳过,如果不是,则执行#ifndef XXX_H_一直到#endif之间的代码段。</p>
<p class="pre">&nbsp;</p>
<p class="pre"><span style="font-family: 宋体">对于编写这些语句时,一般习惯将头文件名全部使用相应的大写字母,然后把</span>.改成_,在头文件名的前后都加下划线,即编写xxx.h的语句时,就如下定义:</p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>#ifndef _XXX_H_</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>#define _XXX_H_</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>……</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>#endif</strong></span>&nbsp;</p>
<p class="pre"><strong>注意事项:</strong></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>#ifndef AAA</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>#define AAA</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>...</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>int i;</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>...</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>#endif</strong></span></p>
<p class="pre">里面有一个变量定义</p>
<p class="pre"><span style="font-family: 宋体">在</span>vc中链接时就出现了i重复定义的错误,而在c中成功编译。</p>
<p class="pre">&nbsp;</p>
<p class="pre"><strong>解决方法:</strong></p>
<p class="pre">(1).把源程序文件扩展名改成.c。</p>
<p class="pre">(2).推荐解决方案:</p>
<p class="pre">.h中只声明 extern int i;在.cpp中定义</p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>&lt;x.h&gt;</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>#ifndef __X_H__</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>#define __X_H__</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>extern int i;</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>#endif //__X_H__</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>&lt;x.c&gt;</strong></span></p>
<p class="pre"><span style="color: rgba(0, 0, 255, 1); font-size: 12px"><strong>int i;</strong></span></p>
<p class="pre">&nbsp;</p>
<p class="pre"><strong>注意问题:</strong></p>
<p class="pre"><span style="font-family: 宋体">变量一般不要定义在</span>.h文件中。&nbsp;</p>
<p class="pre">https://blog.csdn.net/leowinbow/article/details/82884518</p>
<p class="pre">https://blog.csdn.net/myyllove/article/details/83067808</p>
<p class="pre">&nbsp;</p>
<h1 class="pre"><strong>extern关键字在哪里使用?</strong></h1>
<p class="pre">A.置于变量或者函数前,以标示变量或者函数的定义在别处,提示编译器遇到此变量和函数时在其他地方寻找其定义。</p>
<p class="pre">B.可用来进行链接指定。&nbsp;</p>
<p class="pre">https://www.cnblogs.com/Camilo/p/3765494.html</p>

</div>
<div id="MySignature" role="contentinfo">
    <div id="AllanboltSignature">   
      <div>作者:疯狂Delphi</div>
      <div>出处:https://www.cnblogs.com/FKdelphi/</div>
      <div>本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.</div>
</div>
<div class="div_masklayer" id="div_masklayer"></div>
<div class="div_popup" id="Div_popup">
<p class="mid">欢迎关注我,一起进步!扫描下方二维码即可加我</p>
<img class="img_zfb" id="img_zfb" width="150" src="https://images.cnblogs.com/cnblogs_com/FKdelphi/1101510/o_251208113944_QQ.png">
<img class="img_zfb" id="img_zfb" width="150" src="https://images.cnblogs.com/cnblogs_com/FKdelphi/1101510/o_251208115029_WX.png">
</div><br><br>
来源:https://www.cnblogs.com/FKdelphi/p/12867341.html
頁: [1]
查看完整版本: 面试-QT版本