<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>future&#39;s blog</title>
  
  
  <link href="https://future.thisis.host/atom.xml" rel="self"/>
  
  <link href="https://future.thisis.host/"/>
  <updated>2025-08-22T10:57:47.355Z</updated>
  <id>https://future.thisis.host/</id>
  
  <author>
    <name>future</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Integrate KTextEditor into Cantor(2)</title>
    <link href="https://future.thisis.host/2025/08/22/Integrate%20KTextEditor%20into%20Cantor(2)/"/>
    <id>https://future.thisis.host/2025/08/22/Integrate%20KTextEditor%20into%20Cantor(2)/</id>
    <published>2025-08-22T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.355Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Integrate-KTextEditor-into-Cantor-2"><a href="#Integrate-KTextEditor-into-Cantor-2" class="headerlink" title="Integrate KTextEditor into Cantor(2)"></a>Integrate KTextEditor into Cantor(2)</h1><p>Over the past few months, I’ve been working on an important refactor in Cantor: <strong>migrating the editor for command entries</strong> from our in-house <code>QTextDocument</code> implementation to the powerful <strong>KTextEditor</strong> framework. In my previous update, I described how Phase 1 laid the foundation—command cells were migrated to use <code>KTextEditor::View</code>, enabling basic syntax highlighting and a modern editing experience.</p><p>Today, I’m excited to share that <strong>Phase 2 is now complete</strong>! With this milestone, the migration of command entries to KTextEditor is fully in place, ensuring that all existing functionality works smoothly without regressions. This achievement provides a solid foundation for future enhancements while keeping Cantor stable and reliable for everyday use.</p><h2 id="What’s-New-in-Phase-2"><a href="#What’s-New-in-Phase-2" class="headerlink" title="What’s New in Phase 2"></a>What’s New in Phase 2</h2><p>With Phase 2 now complete, command entries are fully integrated into KTextEditor. Along the way, we introduced three major upgrades to Cantor’s core architecture, paving the way for a more consistent, powerful, and future-ready user experience.</p><h3 id="🔹-Unified-Highlighting-Framework"><a href="#🔹-Unified-Highlighting-Framework" class="headerlink" title="🔹 Unified Highlighting Framework"></a>🔹 Unified Highlighting Framework</h3><p>All syntax highlighting in Cantor is now powered by <strong>KSyntaxHighlighting</strong>, the same robust engine behind Kate and KWrite. This change ensures that every backend (such as Python, Maxima, R, Octave, etc.) benefits from a <strong>consistent, accurate, and highly reliable highlighting system</strong>.</p><p>Previously, each backend shipped with its own ad-hoc rules that were difficult to maintain and often inconsistent in style. With the new centralized approach, Cantor handles highlighting uniformly, not only providing a smoother user experience but also laying the groundwork for future support of <strong>custom themes and user-defined keywords</strong>.</p><hr><h3 id="🔹-Unified-Completion-Infrastructure"><a href="#🔹-Unified-Completion-Infrastructure" class="headerlink" title="🔹 Unified Completion Infrastructure"></a>🔹 Unified Completion Infrastructure</h3><p>Code completion has likewise been consolidated into a <strong>common framework coordinated through KTextEditor</strong>. In the past, each backend had its own incomplete and sometimes inconsistent completion logic. Now, all completion requests are handled in a <strong>unified, predictable manner</strong>, with backend-specific intelligent suggestions seamlessly integrated.</p><p>The result is less duplicated code, easier maintenance, and—most importantly—a more <strong>cohesive user experience</strong>. Whether you are writing Python scripts or Maxima formulas, code completion now behaves consistently, making Cantor feel smarter and more reliable.</p><hr><h3 id="🔹-Reduced-Code-Redundancy"><a href="#🔹-Reduced-Code-Redundancy" class="headerlink" title="🔹 Reduced Code Redundancy"></a>🔹 Reduced Code Redundancy</h3><p>By adopting KTextEditor as the core for command entry editing, we eliminated a significant amount of <strong>custom code that had been written in Cantor over the years to handle code completion and highlighting for the different supported languages</strong>.</p><p>This streamlining improves maintainability, reduces potential bug risks, and makes Cantor’s codebase <strong>more approachable for new contributors</strong>. Developers no longer need to reimplement low-level editor features, allowing them to focus on advancing <strong>high-level functionality</strong>. In short: <strong>less boilerplate, more room for innovation</strong>.</p><hr><h2 id="Functional-demonstration-new-and-old-comparison-take-a-look"><a href="#Functional-demonstration-new-and-old-comparison-take-a-look" class="headerlink" title="Functional demonstration: new and old comparison, take a look!"></a>Functional demonstration: new and old comparison, take a look!</h2><p>Thanks to the new <strong>KSyntaxHighlighting</strong> backend, we can now temporarily change the theme of command entries, demonstrating future possibilities.</p><p>Please note that this is currently a preview feature; global “sheet themes” (applying themes uniformly to the entire sheet,) are our next steps.</p><ul><li><p><strong><code>Breeze Dark</code></strong></p><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/Breeze%20Dark.png"></p></li><li><p><strong><code>Github Dark</code></strong></p></li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/Github%20Dark.png"></p><ul><li><strong><code>Breeze Light</code></strong></li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/Breeze%20Light.png"></p><p>By integrating KTextEditor, Cantor now provides a <strong>unified</strong> and <strong>reliable</strong> code completion experience for all backends (such as Python, R, and Maxima).</p><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/com.png"></p><p>Cantor also supports consistent multi-cell handling, with themes and syntax highlighting applied uniformly.</p><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/multi.png"></p><h2 id="Why-This-Matters"><a href="#Why-This-Matters" class="headerlink" title="Why This Matters"></a>Why This Matters</h2><p>This migration is not just a technical change under the hood—it directly impacts how Cantor evolves:</p><ul><li><strong>Stability first</strong>: by ensuring no regressions during the migration, users can continue to rely on Cantor for daily work without disruption.</li><li><strong>Consistency across backends</strong>: highlighting and completion now feel the same, no matter which computational engine you choose.</li><li><strong>Future-proof foundation</strong>: less redundant code and more reliance on KDE Frameworks means Cantor can keep pace with new features in KTextEditor and the broader KDE ecosystem.</li></ul><hr><h2 id="What’s-Next"><a href="#What’s-Next" class="headerlink" title="What’s Next"></a>What’s Next</h2><p>With command entries now fully migrated, the door is open for exciting new improvements:</p><ul><li><strong>Theming support</strong>: enabling custom color schemes and styles, giving users the ability to tailor Cantor’s appearance to their preferences.</li></ul><ul><li><strong>Vi mode integration</strong>: bringing modal editing from Kate into Cantor.</li><li><strong>Spell checking</strong>: powered by Sonnet, useful for Markdown and explanatory text inside worksheets.</li><li><strong>Smarter backend completions</strong>: richer suggestions, function signatures, and inline documentation.</li><li><strong>Performance work</strong>: optimizing for very large worksheets and heavy computations.</li></ul><h3 id="Theming-support-planned"><a href="#Theming-support-planned" class="headerlink" title="Theming support (planned)"></a>Theming support (planned)</h3><p>For now, Cantor will keep the <strong>Default</strong> theme, which uses the desktop palette. This preserves the familiar look and behavior.</p><p>Next, we plan to introduce a <strong>Worksheet Theme</strong> setting. Users will be able to:</p><ul><li>Stay with <strong>Default</strong> (desktop palette, as before), or</li><li>Choose a theme from <strong>KTextEditor&#x2F;KSyntaxHighlighting</strong>, just like in Kate.</li></ul><p>The selected theme will apply consistently across the worksheet—including command entries and results—for a unified appearance. Instead of relying on hardcoded colors or the system palette, Cantor will use the color roles provided by KTextEditor and KSyntaxHighlighting.</p><p>This approach avoids performance overhead from repeatedly reading theme files, ensures instant updates when switching themes, and lays the foundation for richer customization in the future—such as clearer distinctions between prompts, results, and errors, all within a consistent global style.</p><hr>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Integrate-KTextEditor-into-Cantor-2&quot;&gt;&lt;a href=&quot;#Integrate-KTextEditor-into-Cantor-2&quot; class=&quot;headerlink&quot; title=&quot;Integrate KTextEditor </summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    <category term="c++" scheme="https://future.thisis.host/categories/notes/c/"/>
    
    <category term="Qt" scheme="https://future.thisis.host/categories/notes/c/Qt/"/>
    
    
    <category term="gsoc" scheme="https://future.thisis.host/tags/gsoc/"/>
    
    <category term="KDE" scheme="https://future.thisis.host/tags/KDE/"/>
    
  </entry>
  
  <entry>
    <title>解析QGraphicsProxyWidget的桥接作用</title>
    <link href="https://future.thisis.host/2025/07/17/%E8%A7%A3%E6%9E%90QGraphicsProxyWidget/"/>
    <id>https://future.thisis.host/2025/07/17/%E8%A7%A3%E6%9E%90QGraphicsProxyWidget/</id>
    <published>2025-07-17T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.357Z</updated>
    
    <content type="html"><![CDATA[<h1 id="解析QGraphicsProxyWidget的桥接作用"><a href="#解析QGraphicsProxyWidget的桥接作用" class="headerlink" title="解析QGraphicsProxyWidget的桥接作用"></a>解析QGraphicsProxyWidget的桥接作用</h1><p><code>Qt</code>是一个用于构建图形用户界面(GUI)和跨平台应用程序的“超级工具箱”。<code>Qt</code>提供了一套标准化的”零件“，只需要用这些零件组装一次，应用程序就能在所有主流的操作系统上运行。</p><p>在我们深入今天的主题之前，对于初次接触Qt的同学，理解其设计的“三大基石”至关重要。</p><h2 id="Qt的三大基石"><a href="#Qt的三大基石" class="headerlink" title="Qt的三大基石"></a>Qt的三大基石</h2><h3 id="QObject"><a href="#QObject" class="headerlink" title="QObject"></a>QObject</h3><p>在<code>Qt</code>中，几乎所有有意义的对象(窗口、按钮、定时器等)都继承自**<code>QObject</code><strong>这个始祖类。<code>QObject</code>之所以如此特别，是因为它是通往Qt</strong>元对象系统（Meta-Object System）**的大门。</p><p><strong>元对象系统是什么？</strong> 你可以把它想象成每个<code>QObject</code>都随身携带的一张详细的“身份信息卡”。这张卡片不是C++原生就有的，而是Qt通过一个名为<strong>MOC（Meta-Object Compiler）</strong>的预处理器工具，在编译前为你的代码自动生成的。这张“身份卡”上记录了：</p><ul><li>对象的类名是什么（<code>className()</code>）。</li><li>它能发出哪些<strong>信号</strong>。</li><li>它有哪些可供调用的<strong>槽函数</strong>。</li></ul><p>正是因为有了这张预先生成好的“信息卡”，Qt才能够在程序运行时，动态地查询对象的信息，并实现下面要讲的、极其灵活的信号与槽通信机制。</p><h3 id="信号与槽-singal-Slots"><a href="#信号与槽-singal-Slots" class="headerlink" title="信号与槽(singal &amp; Slots)"></a>信号与槽(singal &amp; Slots)</h3><p>这是Qt框架的灵魂，是一种无与伦比的对象间通信机制。让我们用一个生活中的例子来理解它：</p><ul><li><strong>传统方式（函数调用）：</strong> 你按下一个电灯开关，开关必须<strong>明确知道</strong>灯泡在哪里，并且调用灯泡的<code>turnOn()</code>方法。开关和灯泡“耦合”得非常紧，换个灯泡可能就要改动开关的“接线”。</li><li><strong>Qt的方式（信号与槽）：</strong><ul><li>一个<code>QPushButton</code>（按钮）被点击时，它不会去找具体要干什么事的对象，它只是向外大喊一声：“<strong>我被点击了！</strong>”（这就是**信号 <code>clicked()</code>**）。</li><li>而另一个对象，比如一个窗口，有一个“耳朵”在听，这个耳朵就是<strong>槽函数</strong>（例如<code>handleButtonClick()</code>）。</li><li>我们只需要一行代码 <code>connect(button, &amp;QPushButton::clicked, window, &amp;MyWindow::handleButtonClick);</code> 就建立了一条“连接”。</li></ul></li></ul><p>从此，按钮只管发出信号，窗口只管接收并处理。它们彼此完全独立，一个按钮的点击信号可以连接到多个槽，一个槽也可以接收来自多个信号。这种<strong>“解耦”</strong>的设计是构建复杂、可维护UI的基石。</p><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/250721_15h15m00s_screenshot.png"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">graph TD</span><br><span class="line">    subgraph &quot;对象 (Objects)&quot;</span><br><span class="line">        Button[&quot;QPushButton&lt;br/&gt;(信号源)&quot;]</span><br><span class="line">        Label[&quot;QLabel&lt;br/&gt;(接收者)&quot;]</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    subgraph &quot;机制 (Mechanism)&quot;</span><br><span class="line">        Signal[&quot;clicked() 信号&quot;]</span><br><span class="line">        Slot[&quot;setText() 槽&quot;]</span><br><span class="line">        Connect[&quot;connect(...) 函数&lt;br/&gt;&lt;b&gt;(负责连接)&lt;/b&gt;&quot;]</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    UserClick[&quot;用户点击&quot;] --&gt; Button</span><br><span class="line">    Button -- 发出 --&gt; Signal</span><br><span class="line">    </span><br><span class="line">    subgraph &quot;连接的建立 (Setup Time)&quot;</span><br><span class="line">      Connect -.-&gt; Signal</span><br><span class="line">      Connect -.-&gt; Slot</span><br><span class="line">    end</span><br><span class="line">    </span><br><span class="line">    subgraph &quot;信号的触发 (Runtime)&quot;</span><br><span class="line">      Signal -- 触发 --&gt; Slot</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    Slot -- 操作 --&gt; Label</span><br><span class="line"></span><br><span class="line">    style Connect fill:#d5e8d4,stroke:#82b366</span><br></pre></td></tr></table></figure><h3 id="事件循环-The-Event-Loop"><a href="#事件循环-The-Event-Loop" class="headerlink" title="事件循环(The Event Loop)"></a>事件循环(The Event Loop)</h3><p>GUI程序和命令行程序不同，它不会从头执行到尾然后退出。它必须一直运行，等待用户的操作。这就是<strong>事件循环</strong>的职责。</p><p>把它想象成一个<strong>兢兢业业的前台接待员</strong> (<code>QApplication::exec()</code>)：</p><ol><li><strong>等待：</strong> 接待员坐在那里，循环等待。没有事情发生时，程序就“打个盹”，不消耗CPU。</li><li><strong>事件：</strong> 一个“事件”发生了（比如，一位访客到来，代表用户的一次鼠标点击）。</li><li><strong>分发：</strong> 接待员看到访客的预约单，上面写着“找三楼的按钮经理”，于是他把访客（事件）<strong>引导</strong>给了正确的对象（那个被点击的按钮）。</li><li><strong>处理：</strong> “按钮经理”处理完访客的事务（比如发出<code>clicked()</code>信号），然后告诉接待员“我处理完了”。</li><li>接待员回到座位，继续等待下一个事件。</li></ol><p>这个“等待-分发-处理”的循环，就是所有GUI应用能够灵敏响应我们操作的核心机制。</p><h2 id="“组建集”与“画布”"><a href="#“组建集”与“画布”" class="headerlink" title="“组建集”与“画布”"></a>“组建集”与“画布”</h2><p>在Qt中，构建用户界面的两个体系是<code>QWidget</code>(控件)体系和<code>QGraphicsView</code>(场景)体系。首先我们需要知道<code>QGraphicsProxyWidget</code>为和存在。</p><h3 id="QWidget体系"><a href="#QWidget体系" class="headerlink" title="QWidget体系"></a>QWidget体系</h3><p><code>QWidget</code>是我们最先接触，也是最常用的UI构建方式。它的核心思想是<strong>“组件集（Component Set）”</strong>，我们可以将其比作一个<strong>结构严谨、等级分明的“城市”</strong>。</p><ul><li><strong>核心单元与父子关系：</strong> 这个“城市”的基本建筑单元是<code>QWidget</code>及其子类（<code>QPushButton</code>, <code>QLineEdit</code>等）。它们之间存在着严格的<strong>父子关系</strong>。子控件（child widget）在视觉上被“框”在父控件（parent widget）的矩形区域内，无法超出。当父控件被移动、隐藏或销毁时，其所有子控件也会随之移动、隐藏或销毁。这种层级关系构成了UI的骨架。</li><li><strong>布局管理（Layouts）：</strong> 为了让“城市”的建筑排列整齐，<code>QWidget</code>体系引入了<strong>布局管理器</strong>（<code>QLayout</code>的子类，如<code>QVBoxLayout</code>, <code>QHBoxLayout</code>, <code>QGridLayout</code>）。布局管理器如同城市的“规划局”，它接管了其内部所有控件的尺寸和位置。你只需要告诉“规划局”需要放入哪些控件，以及一些基本规则（如间距、对齐方式），它就会自动计算每个控件的最佳大小和位置，并在窗口尺寸变化时智能地重新调整布局，确保UI的响应式和美观。</li><li><strong>事件处理（Event Handling）：</strong> <code>QWidget</code>的事件处理是<strong>“直接分发”</strong>的。在Linux上，每个顶层<code>QWidget</code>都是一个受窗口管理器管理的<strong>原生窗口</strong>，拥有独立的窗口句柄。当操作系统捕获到一个鼠标点击或键盘输入时，它能根据事件发生的屏幕坐标，准确地判断出事件属于哪个原生窗口。该事件随后被Qt的事件循环接收，并几乎直接地派发给目标<code>QWidget</code>。控件通过重写虚函数（如<code>mousePressEvent()</code>, <code>keyPressEvent()</code>, <code>paintEvent()</code>）来响应这些事件。</li><li><strong>绘制模型（Painting Model）：</strong> 其绘制模型是<strong>“独立且光栅化”</strong>的。每个<code>QWidget</code>都拥有一块独立的内存区域，称为“后备存储（Backing Store）”。当需要重绘时（由<code>paintEvent</code>触发），每个控件只负责绘制自己矩形区域内的像素。最终，由窗口系统或父控件将这些独立的绘制结果<strong>合成（Composite）</strong>在一起，形成我们看到的完整窗口。</li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/250721_15h15m09s_screenshot.png"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">graph TD</span><br><span class="line">    subgraph 操作系统屏幕</span><br><span class="line">        A[&quot;QMainWindow&lt;br/&gt;(顶层Widget, 原生窗口句柄: XID/HWND)&quot;]</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    subgraph A [QMainWindow]</span><br><span class="line">        B[QMenuBar]</span><br><span class="line">        C[QToolBar]</span><br><span class="line">        D[CentralWidget]</span><br><span class="line">        E[QStatusBar]</span><br><span class="line">    end</span><br><span class="line">    </span><br><span class="line">    subgraph D [CentralWidget]</span><br><span class="line">        F&#123;&quot;QGridLayout&lt;br/&gt;(布局管理器)&quot;&#125;</span><br><span class="line">        G[QPushButton]</span><br><span class="line">        H[QLineEdit]</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    A --&gt; B</span><br><span class="line">    A --&gt; C</span><br><span class="line">    A --&gt; D</span><br><span class="line">    A --&gt; E</span><br><span class="line">    </span><br><span class="line">    D --&gt; F</span><br><span class="line">    F --&gt; G</span><br><span class="line">    F --&gt; H</span><br><span class="line"></span><br><span class="line">    style A fill:#dae8fc,stroke:#6c8ebf,stroke-width:2px</span><br><span class="line">    style F fill:#e1d5e7,stroke:#9673a6,stroke-width:1px,stroke-dasharray: 5 5</span><br><span class="line">   </span><br></pre></td></tr></table></figure><h3 id="QGraphicsView体系"><a href="#QGraphicsView体系" class="headerlink" title="QGraphicsView体系"></a>QGraphicsView体系</h3><p>与<code>QWidget</code>的严谨不同，<code>QGraphicsView</code>提供了一个极其自由、动态的创作环境，其核心思想是<strong>“画布（Canvas）”</strong>或<strong>“场景图（Scene Graph）”</strong>。我们可以将其比作一个<strong>拥有“上帝视角”的数字创作空间</strong>。</p><p>这个世界由三个核心组件构成：</p><ol><li><strong><code>QGraphicsScene</code> (场景 - 逻辑世界):</strong><ul><li>这是“无限大的宇宙”或“数据模型”。它是一个逻辑容器，容纳着成千上万个图形项（<code>QGraphicsItem</code>）。</li><li>场景本身不关心如何被显示，它只负责管理所有item的<strong>逻辑坐标、状态和层次关系</strong>。它使用高效的空间索引算法（如BSP树），能够飞快地查询到特定区域内有哪些item。</li></ul></li><li><strong><code>QGraphicsView</code> (视图 - 观察窗口):</strong><ul><li>这是我们观察场景的“摄像机”或“取景器”。它是一个标准的<code>QWidget</code>，也是整个体系中唯一与操作系统直接交互的原生窗口。</li><li>它的核心职责是将<code>QGraphicsScene</code>中的矢量坐标<strong>映射</strong>到它自己的像素坐标上，并将用户的鼠标、键盘事件<strong>翻译</strong>后传递给场景。</li><li>最强大的一点是，<strong>同一个场景可以被多个视图观察</strong>。你可以创建两个视图，一个显示场景的全貌（如地图），另一个则放大显示场景的某个局部细节（如街道），并且在一个视图中对item的修改会立刻反映在另一个视图中。视图本身还可以旋转和缩放，如同调整摄像机的角度和焦距。</li></ul></li><li><strong><code>QGraphicsItem</code> (图形项 - 世界居民):</strong><ul><li>这些是场景中的“演员”或“居民”，是构成视觉内容的基本单元。它们是<strong>轻量级</strong>的，因为它们没有自己的窗口句柄或事件循环。</li><li>每个<code>QGraphicsItem</code>都知道如何绘制自己（通过<code>paint()</code>方法）、自己的边界范围（<code>boundingRect()</code>）以及精确形状（<code>shape()</code>，用于碰撞检测）。</li><li>它们可以被自由地<strong>移动、缩放、旋转、扭曲</strong>，可以被组合成复杂的复合体，并且拥有Z值来控制其堆叠顺序。</li></ul></li></ol><ul><li><strong>事件处理（Event Handling）：</strong> <code>QGraphicsView</code>的事件处理是<strong>“间接且由场景驱动”</strong>的。所有原生事件首先被<code>QGraphicsView</code>接收。然后，视图会询问场景：“鼠标在<code>(x, y)</code>这个像素位置，对应到你的逻辑世界里是哪个坐标？这个坐标上最顶层的item是谁？”场景利用其高效的索引找到目标item后，<code>QGraphicsView</code>再将事件分发给这个item。整个过程由Qt在应用程序内部完成，操作系统对此一无所知。</li><li><strong>渲染模型（Rendering Model）：</strong> 其渲染是<strong>“集中式”</strong>的。<code>QGraphicsView</code>是唯一的“渲染引擎”。在需要重绘时，它会根据当前的视口范围，要求场景提供所有可见的item列表，然后按照Z值顺序遍历这些item，并调用它们的<code>paint()</code>方法，将它们统一绘制到自己的视口上。这个过程可以无缝地切换到<strong>OpenGL&#x2F;Vulkan后端</strong>，利用GPU进行硬件加速，从而在渲染大量动态对象时保持极高的流畅度。</li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/250721_15h15m24s_screenshot.png"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">graph TD</span><br><span class="line">    subgraph 操作系统屏幕</span><br><span class="line">        A[&quot;QGraphicsView&lt;br/&gt;(顶层Widget, 原生窗口句柄: XID/HWND)&quot;]</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    subgraph A [&quot;QGraphicsView - “取景器”&quot;]</span><br><span class="line">        subgraph B [&quot;QGraphicsScene - “无限画布”&quot;]</span><br><span class="line">            C[&quot;QGraphicsRectItem&lt;br/&gt;(x:10, y:20, rotation:15deg)&quot;]</span><br><span class="line">            D[&quot;QGraphicsTextItem&lt;br/&gt;(x:150, y:100, scale:1.5)&quot;]</span><br><span class="line">            E[&quot;QGraphicsPixmapItem&lt;br/&gt;(x:80, y:180, z-value:1)&quot;]</span><br><span class="line">            F[&quot;QGraphicsEllipseItem&lt;br/&gt;(x:-50, y:90, z-value:2)&quot;]</span><br><span class="line">        end</span><br><span class="line">    end</span><br><span class="line"></span><br><span class="line">    D --- C</span><br><span class="line">    E --- D</span><br><span class="line">    F --- E</span><br><span class="line"></span><br><span class="line">    linkStyle 0,1,2 stroke-width:0px;</span><br><span class="line"></span><br><span class="line">    style A fill:#dae8fc,stroke:#6c8ebf,stroke-width:2px</span><br><span class="line">    style B fill:#d5e8d4,stroke:#82b366,stroke-width:2px,stroke-dasharray: 5 5</span><br><span class="line">    style C fill:#f8cecc,stroke:#b85450</span><br><span class="line">    style D fill:#f8cecc,stroke:#b85450</span><br><span class="line">    style E fill:#f8cecc,stroke:#b85450</span><br><span class="line">    style F fill:#f8cecc,stroke:#b85450</span><br></pre></td></tr></table></figure><h2 id="桥梁-QGraphicsProxywidget"><a href="#桥梁-QGraphicsProxywidget" class="headerlink" title="桥梁(QGraphicsProxywidget)"></a>桥梁(QGraphicsProxywidget)</h2><p>现在，我们已经深刻理解了这两个世界的根本不同：</p><ul><li><strong><code>QWidget</code>体系</strong>：一个由拥有独立“户口”（窗口句柄）的“公民”构成的社会，秩序井然，但缺乏灵活性。</li><li><strong><code>QGraphicsView</code>体系</strong>：一个由没有“户口”的“虚拟灵魂”构成的魔法世界，自由奔放，但缺少现成的、功能丰富的“公民”。</li></ul><p><strong>核心矛盾也因此凸显</strong>：如何将一个功能完备的<code>QWidget</code>“公民”，请到<code>QGraphicsScene</code>这个魔法世界里来，并让它在这里依然能行动、能交互，享受缩放和旋转的“魔法”？</p><p>这就是<code>QGraphicsProxyWidget</code>需要登场的原因。它，就是为了连接这两个平行宇宙而生的<strong>“次元之桥”</strong>。</p><h3 id="核心翻译机制"><a href="#核心翻译机制" class="headerlink" title="核心翻译机制"></a>核心翻译机制</h3><p><code>QGraphicsProxyWidget</code>的桥接作用并非魔法，而是一套精密的、在用户空间实现的“合成器”，其核心是两大翻译机制。</p><p><strong>事件流的捕获与”再注入”</strong></p><p>一个控件不仅要能看，还要能用。<code>QGraphicsProxyWidget</code>通过一个巧妙的事件重定向流程保证了交互性。</p><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/250721_15h15m44s_screenshot.png"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">sequenceDiagram</span><br><span class="line">    participant U as 用户</span><br><span class="line">    participant OS as 操作系统 (X11/Wayland)</span><br><span class="line">    participant V as QGraphicsView</span><br><span class="line">    participant P as QGraphicsProxyWidget</span><br><span class="line">    participant W as QPushButton (被代理)</span><br><span class="line"></span><br><span class="line">    U-&gt;&gt;OS: 点击鼠标</span><br><span class="line">    OS-&gt;&gt;V: 转发原生鼠标事件</span><br><span class="line">    V-&gt;&gt;P: 投递QGraphicsSceneMouseEvent (场景坐标)</span><br><span class="line">    P-&gt;&gt;P: **内部翻译**: &lt;br/&gt;1. 转换坐标系&lt;br/&gt;2. 转换事件类型</span><br><span class="line">    P-&gt;&gt;W: **“再注入”**伪造的QMouseEvent (控件坐标)</span><br><span class="line">    W-&gt;&gt;W: 像往常一样处理点击, 发出clicked()信号</span><br></pre></td></tr></table></figure><p>如上图所示，<code>QGraphicsProxyWidget</code>像一个海关，它“拦截”了来自<code>QGraphicsScene</code>的事件，经过一番“翻译”和“伪装”后，再“注入”给它所代理的<code>QWidget</code>。被代理的控件对此毫无察觉，以为自己生活在普通的窗口环境中。</p><p><strong>绘制机制的重定向</strong></p><p><code>QGraphicsProxyWidget</code>采用了“离屏渲染”的技术，让<code>QWidget</code>在不知情的情况下将自己画在一张“影子画布”上。</p><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/250721_15h16m00s_screenshot.png"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">graph TD</span><br><span class="line">    A[&quot;QGraphicsScene请求重绘代理项&quot;] --&gt; B&#123;&quot;QGraphicsProxyWidget::paint() 被调用&quot;&#125;;</span><br><span class="line">    B --&gt; C[&quot;&lt;b&gt;步骤一：&lt;/b&gt;在内存中准备一块&#x27;影子画布&#x27;&lt;br/&gt;(QPixmap)&quot;];</span><br><span class="line">    C --&gt; D[&quot;&lt;b&gt;步骤二：&lt;/b&gt;调用内部widget-&gt;render(...)&lt;br/&gt;命令控件将自己画在这块画布上&quot;];</span><br><span class="line">    D --&gt; E[&quot;&lt;b&gt;步骤三：&lt;/b&gt;QPushButton完成绘制&lt;br/&gt;&#x27;影子画布&#x27;上现在有了按钮的图像&quot;];</span><br><span class="line">    E --&gt; F[&quot;&lt;b&gt;步骤四：&lt;/b&gt;ProxyWidget将最终的画布内容&lt;br/&gt;作为一个普通图片绘制到场景中&lt;br/&gt;(此时可应用旋转、缩放等变换)&quot;];</span><br><span class="line">    F --&gt; G[&quot;绘制完成&quot;];</span><br><span class="line"></span><br><span class="line">    style E fill:#d5e8d4,stroke:#82b366</span><br></pre></td></tr></table></figure><p>这个过程，<code>QGraphicsProxyWidget</code>像一个技艺高超的画家，它先让<code>QWidget</code>在一张不对外展示的画纸上画好自画像，然后它再拿起这张画，进行艺术加工（变换），最后贴到<code>QGraphicsScene</code>这个大展板上。</p><p><strong>构建强大的UI</strong></p><p>掌握了<code>QGraphicsProxyWidget</code>，我们就能构建出许多传统<code>QWidget</code>布局难以实现的复杂UI。最典型的就是<strong>节点编辑器</strong>。</p><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/250721_15h16m10s_screenshot.png"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">graph TD</span><br><span class="line">    subgraph QGraphicsScene [&quot;画布: 节点编辑器&quot;]</span><br><span class="line">        subgraph NodeA [&quot;QGraphicsItem: 节点 &#x27;向量运算&#x27;&quot;]</span><br><span class="line">            P1[&quot;QGraphicsProxyWidget&quot;] --&gt; W1[&quot;QLabel: &#x27;输入A&#x27;&quot;]</span><br><span class="line">            P2[&quot;QGraphicsProxyWidget&quot;] --&gt; W2[&quot;QLineEdit&quot;]</span><br><span class="line">            P3[&quot;QGraphicsProxyWidget&quot;] --&gt; W3[&quot;QLabel: &#x27;输入B&#x27;&quot;]</span><br><span class="line">            P4[&quot;QGraphicsProxyWidget&quot;] --&gt; W4[&quot;QLineEdit&quot;]</span><br><span class="line">            P5[&quot;QGraphicsProxyWidget&quot;] --&gt; W5[&quot;QLabel: &#x27;操作&#x27;&quot;]</span><br><span class="line">            P6[&quot;QGraphicsProxyWidget&quot;] --&gt; W6[&quot;QComboBox: [Add, Multiply, ...]&quot;]</span><br><span class="line">        end</span><br><span class="line">        subgraph NodeB [&quot;QGraphicsItem: 节点 &#x27;输出&#x27;&quot;]</span><br><span class="line">             P7[&quot;QGraphicsProxyWidget&quot;] --&gt; W7[&quot;QLabel: &#x27;结果&#x27;&quot;]</span><br><span class="line">             P8[&quot;QGraphicsProxyWidget&quot;] --&gt; W8[&quot;QLineEdit (只读)&quot;]</span><br><span class="line">        end</span><br><span class="line">        NodeA -- 连接线 --&gt; NodeB</span><br><span class="line">    end</span><br></pre></td></tr></table></figure><h3 id="“过路费”"><a href="#“过路费”" class="headerlink" title="“过路费”"></a>“过路费”</h3><p>这套精密的机制并非没有代价。</p><ul><li><strong>内存开销</strong>：每个<code>QGraphicsProxyWidget</code>都需要一块<code>QPixmap</code>作为“影子画布”。如果你的场景中有成千上万个复杂的代理控件，这部分内存占用会相当可观。</li><li><strong>CPU开销</strong>：相比于一个只执行简单绘图命令的<code>QGraphicsItem</code>，代理项的<code>QWidget::render()</code>调用（本质上是软件光栅化）和频繁的事件翻译都会带来额外的CPU开销。</li></ul><p>因此，<code>QGraphicsProxyWidget</code>是一个“大杀器”，而不是“常规武器”。<strong>如果一个功能可以通过自定义一个轻量级的<code>QGraphicsItem</code>来实现，那么就优先选择它</strong>。只有当你需要嵌入一个功能极其复杂、如果重写为<code>QGraphicsItem</code>则成本过高的现有<code>QWidget</code>时，<code>QGraphicsProxyWidget</code>才是你的最佳选择。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>从始至终，<code>QGraphicsProxyWidget</code>的核心使命就是：在两个不同就阿狗的图形与时间系统之间，充当一个高性能的<strong>实时翻译官</strong>和<strong>用户空间合成器</strong>。</p><ol><li><strong>绘制重定向（Painting Redirection）</strong>：<code>QGraphicsProxyWidget</code> 通过接管被代理<code>QWidget</code>的绘制目标，将其从屏幕的“后备存储”重定向到一块内存中的“离屏画布”（<code>QPixmap</code>）。它巧妙地利用 <code>QWidget::render()</code> 函数，命令控件在这块“影子画布”上完成所有绘制。随后，它再将这张已经画好的、光栅化的位图作为一张普通的纹理，绘制到<code>QGraphicsScene</code>的最终渲染目标上。这个过程，在应用层面实现了一套独立的<strong>离屏渲染与位图合成（Off-screen Rendering &amp; Blitting）</strong>流程。</li><li><strong>事件流重塑（Event Stream Remodeling）</strong>：它在事件传递的路径上设立了一个“检查点”。所有发往其在场景中所在位置的<code>QGraphicsScene</code>事件都会被它捕获。它会基于场景图的变换（Transform）信息，将事件的坐标系、类型和参数从<code>QGraphicsScene</code>的语境，精确地“翻译”成<code>QWidget</code>内部的局部语境，并构造成一个全新的、标准的<code>QWidget</code>事件。最后，它通过Qt的事件系统，将这个“伪造”的事件<strong>重新注入（Re-inject）</strong>到被代理控件的事件队列中，从而“欺骗”<code>QWidget</code>，使其相信自己正与操作系统直接交互。</li><li><strong>几何状态同步（Geometry State Synchronization）</strong>：<code>QGraphicsProxyWidget</code>持续监听其内部<code>QWidget</code>的尺寸策略（Size Policy）和几何变化。当<code>QWidget</code>因内部布局变化而希望改变大小时，代理项会相应地更新自己在<code>QGraphicsScene</code>中的边界框（Bounding Rectangle）。反之，当代理项在场景中被用户或动画系统缩放、变形时，它也会将这种几何变换信息传递给内部的<code>QWidget</code>，触发其布局的重新计算。这种<strong>双向的几何状态同步</strong>，保证了两个世界在视觉和布局上的一致性。</li></ol><p>综上所述，<code>QGraphicsProxyWidget</code>并非一个简单的容器，而是一个精密的<strong>运行时适配器（Runtime Adapter）</strong>。它以一定的内存和CPU开销为代价，通过在用户空间模拟<code>QWidget</code>的绘制环境和事件来源，实现了在矢量化、可变换的场景图中嵌入和复用功能完备的光栅化组件这一高难度任务，是Qt框架中“组合优于继承”和“适配器模式”的绝佳体现。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;解析QGraphicsProxyWidget的桥接作用&quot;&gt;&lt;a href=&quot;#解析QGraphicsProxyWidget的桥接作用&quot; class=&quot;headerlink&quot; title=&quot;解析QGraphicsProxyWidget的桥接作用&quot;&gt;&lt;/a&gt;解析QGr</summary>
      
    
    
    
    
  </entry>
  
  <entry>
    <title>Integrate KTextEditor into Cantor</title>
    <link href="https://future.thisis.host/2025/07/15/Intergrate%20KTextEditor%20into%20Cantor/"/>
    <id>https://future.thisis.host/2025/07/15/Intergrate%20KTextEditor%20into%20Cantor/</id>
    <published>2025-07-15T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.355Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Integrate-KTextEditor-into-Cantor"><a href="#Integrate-KTextEditor-into-Cantor" class="headerlink" title="Integrate KTextEditor into Cantor"></a>Integrate KTextEditor into Cantor</h1><h2 id="Project-Introduction"><a href="#Project-Introduction" class="headerlink" title="Project Introduction"></a>Project Introduction</h2><p><a href="https://apps.kde.org/cantor/">Cantor</a> is a powerful scientific computing front-end in the KDE ecosystem, providing users with a unified and friendly interface for mathematical and statistical analysis.</p><p>Currently, Cantor’s worksheet cells are based on a custom implementation using <code>QTextDocument</code>. While this approach meets basic needs, it has revealed its limitations in terms of feature expansion and long-term maintenance. To fundamentally enhance the editing experience, simplify the codebase, and embrace the advanced technology of the KDE Frameworks, this project plans to deeply integrate the feature-rich <strong>KTextEditor</strong> component into Cantor, completely replacing the existing cell implementation.</p><p>This core upgrade will bring a suite of long-awaited, powerful features to Cantor, including:</p><ul><li><strong>Enhanced Multi-line Editing</strong>: Significantly improves the editing experience for complex, multi-line code blocks. This includes more robust syntax highlighting, accurate bracket matching, and a more stable editing environment, resolving key issues present in the current implementation.</li></ul><ul><li><strong>Vi Mode</strong>: Provides native Vi-style text editing for users accustomed to Vim’s efficient workflow, significantly improving editing speed.</li><li><strong>Improved Syntax Highlighting</strong>: Supports more comprehensive and precise code coloring rules, making complex mathematical and programming expressions clearer and easier to read.</li><li><strong>Smart Auto-indent</strong>: Enhances code formatting capabilities, making it exceptionally convenient to write structured scripts and multi-line formulas.</li><li><strong>Code Completion</strong>: Intelligently suggests variables, functions, and keywords, thereby speeding up input and reducing syntax errors.</li><li><strong>Spell Check</strong>: Ensures the accuracy of text comments and documentation, which is crucial for writing rigorous formula explanations and reports.</li></ul><p>By integrating KTextEditor, Cantor will not only optimize the user’s workflow but also reduce code redundancy and improve the project’s overall maintainability. This move will further strengthen the Cantor and KDE ecosystems, providing users with a smoother and more unified experience across different KDE applications.</p><h2 id="Why-this-is-needed"><a href="#Why-this-is-needed" class="headerlink" title="Why this is needed"></a>Why this is needed</h2><p>As scientific computing demands become increasingly complex, a modern, full-featured editor is essential for boosting productivity. The current custom implementation has become a bottleneck hindering Cantor’s future development:</p><ol><li><strong>High Maintenance Cost</strong>: Maintaining a custom editor component consumes significant development resources and struggles to keep pace with the advancements in modern editors.</li><li><strong>Difficult to Extend</strong>: Implementing complex features like Vi mode or advanced code completion on the existing architecture is akin to “reinventing the wheel”—it’s inefficient and prone to introducing new bugs.</li><li><strong>Failure to Leverage the Ecosystem</strong>: The KDE Frameworks already provide the very mature and powerful KTextEditor component. Not utilizing it is a waste of available resources. Integrating KTextEditor means Cantor can directly benefit from the years of effort and refinement the entire KDE community has invested in this component.</li></ol><h2 id="Current-Status-Phase-1-Complete"><a href="#Current-Status-Phase-1-Complete" class="headerlink" title="Current Status: Phase 1 Complete"></a>Current Status: Phase 1 Complete</h2><p>The first phase of the project has been completed. We have successfully introduced Cantor into the core of KTextEditor and achieved the following key results:</p><ul><li><p><strong>Core replacement completed</strong>：We created a new <code>WorksheetTextEditorItem</code> class, which acts as a proxy for <code>KTextEditor::View</code>, successfully replacing the old <code>QTextDocument</code>-based cell implementation.</p></li><li><p><strong>Basic functions available</strong>：Users can already perform basic operations such as text input and code execution in the new cells, proving the feasibility of the integration solution.</p><ul><li>short text</li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/2.png"></p><ul><li>multi-line display</li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/For%20long%20text%2C%20we%20can%20use%20multiple%20cells%20to%20display%20and%20run%20(3).png"></p></li><li><p><strong>integration of KTextEditor features</strong>：Basic syntax highlighting and text editing features are now available in new cells.</p><ul><li><code>Python</code></li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/python.png"></p><ul><li><code>Maxima</code></li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/maxima3.png"></p><ul><li><code>Lua</code></li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/lua.png"></p></li></ul><p><strong>Event Handling and UI Interaction</strong>: Core user interactions such as mouse events and drag-and-drop functionality for worksheet entries are working as expected within the new framework.</p><ul><li><code>drag</code></li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/dr.png"></p><ul><li><code>shotcut key</code></li></ul><p><img src="https://pub-a7510641c4c0427886fce394cb093861.r2.dev/1.gif"></p><h2 id="The-Road-Ahead-The-Plan-for-Phase-2"><a href="#The-Road-Ahead-The-Plan-for-Phase-2" class="headerlink" title="The Road Ahead: The Plan for Phase 2"></a>The Road Ahead: The Plan for Phase 2</h2><p>With the foundation now firmly in place, the second phase of the project will focus on unlocking the full potential of KTextEditor and refining the user experience. The planned work includes:</p><ul><li><strong>Activating Advanced Editor Features</strong>: We will progressively enable and configure KTextEditor’s sophisticated features, including <strong>Vi Mode</strong>, <strong>integrated Spell Check</strong>, and <strong>smart indentation rules</strong>, ensuring they are seamlessly integrated into the Cantor workflow.</li><li><strong>Connecting Backend-driven Code Completion</strong>: A major goal is to connect Cantor’s various computation backends (e.g., Python, R, Octave) to the KTextEditor code completion framework. This will provide users with context-aware, intelligent suggestions.</li><li><strong>Bug Fixing and UX Polishing</strong>: We will systematically address any remaining issues from the initial integration, focusing on perfecting UI&#x2F;UX details like focus management, text selection, and context menu consistency.</li><li><strong>Comprehensive Testing</strong>: Rigorous regression testing will be conducted across all features—new and existing—to guarantee the stability and reliability of Cantor following this major architectural upgrade.</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Integrate-KTextEditor-into-Cantor&quot;&gt;&lt;a href=&quot;#Integrate-KTextEditor-into-Cantor&quot; class=&quot;headerlink&quot; title=&quot;Integrate KTextEditor into</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    <category term="c++" scheme="https://future.thisis.host/categories/notes/c/"/>
    
    <category term="Qt" scheme="https://future.thisis.host/categories/notes/c/Qt/"/>
    
    
    <category term="gsoc" scheme="https://future.thisis.host/tags/gsoc/"/>
    
    <category term="KDE" scheme="https://future.thisis.host/tags/KDE/"/>
    
  </entry>
  
  <entry>
    <title>Chatroom 记录</title>
    <link href="https://future.thisis.host/2024/07/27/%E6%80%BB%E7%BB%93/"/>
    <id>https://future.thisis.host/2024/07/27/%E6%80%BB%E7%BB%93/</id>
    <published>2024-07-27T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.357Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Future-聊天室"><a href="#Future-聊天室" class="headerlink" title="Future 聊天室"></a>Future 聊天室</h1><h2 id="功能"><a href="#功能" class="headerlink" title="功能"></a>功能</h2><h3 id="账号管理"><a href="#账号管理" class="headerlink" title="账号管理"></a>账号管理</h3><ul><li>实现登录、注册、注销</li><li>实现找回密码（提高）</li></ul><h3 id="好友管理"><a href="#好友管理" class="headerlink" title="好友管理"></a>好友管理</h3><ul><li>实现好友的添加、删除、查询操作</li><li>实现显示好友在线状态</li><li>禁止不存在好友关系的用户间的私聊</li><li>实现屏蔽好友消息</li><li>实现好友间聊天</li></ul><h3 id="群管理"><a href="#群管理" class="headerlink" title="群管理"></a>群管理</h3><ul><li>实现群组的创建、解散</li><li>实现用户申请加入群组</li><li>实现用户查看已加入的群组</li><li>实现群组成员退出已加入的群组</li><li>实现群组成员查看群组成员列表</li><li>实现群主对群组管理员的添加和删除</li><li>实现群组管理员批准用户加入群组</li><li>实现群组管理员&#x2F;群主从群组中移除用户</li><li>实现群组内聊天功能</li></ul><h3 id="聊天功能"><a href="#聊天功能" class="headerlink" title="聊天功能"></a>聊天功能</h3><ul><li>实现查看历史消息记录</li><li>实现用户间在线聊天</li><li>实现在线用户对离线用户发送消息，离线用户上线后获得通知</li><li>实现在线发送文件</li><li>实现在线用户对离线用户发送文件，离线用户上线后获得通知&#x2F;接收</li><li>实现后台发送文件</li><li>实现用户在线时,消息的实时通知<ul><li>收到好友请求</li><li>收到私聊</li><li>收到加群申请</li></ul></li></ul><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><ul><li>使用 C++编程语言</li><li>使用 I&#x2F;O 多路复用完成本项目<ul><li>C++：Epoll ET 模式</li></ul></li><li>使用数据库完成数据存储<ul><li>Redis 和 mysql</li><li>历史消息采用redis做告诉缓存，mysql来存储大量历史消息</li></ul></li><li>数据库中数据的存储和取用使用序列化和反序列化完成(Json)</li><li>支持大量客户端同时访问</li><li>实现服务器日志，记录服务器的状态信息</li><li>C&#x2F;S 双端均支持在 CLI&#x2F;Web 自行指定 IP:Port</li><li>实现具有高稳定性的客户端和服务器，防止在用户非法输入时崩溃或异常<ul><li>实现 TCP 心跳检测</li></ul></li></ul><h2 id="遇到的问题"><a href="#遇到的问题" class="headerlink" title="遇到的问题"></a>遇到的问题</h2><ul><li><p>在客户端因某些原因异常退出时，服务端将无法正常处理其他请求.</p><ul><li>开始时服务端没有将新连接的描述符设置为非阻塞模式，导致客户端异常退出时服务端的接收<code>recv</code>一直在阻塞着读取，且无法处理其他请求</li></ul></li><li><p>如何往线程池中传入<strong>类</strong>的<code>成员函数</code>.</p><ul><li><pre><code class="c++">auto task = []()&#123;     类的成员函数 &#125; m_pool.submit(task);<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">* `Tcp`传输为字节流传输，采用在每条消息前面加上`长度`来正确接收每条请求.</span><br><span class="line">* 在代码中往`redis`数据库中添加好友申请数据时，没有正确插入.</span><br><span class="line">  * 由于好友申请当中包含时间，姓名等信息，中间含有**空格**，在redis的哈希表中无法插入.</span><br><span class="line">  * 经过查阅在redis哈希表中，**空格**可以用`+`代替，在遇到`+`时会被转义为**空格**，或者存储为**十六进制**，但是这种方法在终端中的**空格**为灰色.</span><br><span class="line"></span><br><span class="line">* 在聊天界面如果输入带有`%`，服务器直接挂掉.</span><br><span class="line"></span><br><span class="line">  * ```c++</span><br><span class="line">    int redisAsyncContext::Lpush(const std::string &amp;key, const std::string &amp;value)</span><br><span class="line">    &#123;</span><br><span class="line">        //std::string cmd = &quot;lpush &quot; + key + &quot; &quot; + value;</span><br><span class="line">        this-&gt;m_reply = (redisReply *)redisCommand(this-&gt;m_connettion, &quot;LPUSH %s %s&quot;, key.c_str(), value.c_str());</span><br><span class="line">         // 检查 m_reply 是否为 NULL</span><br><span class="line">        if (this-&gt;m_reply == NULL) &#123;</span><br><span class="line">            std::cerr &lt;&lt; &quot;Error: redisCommand returned NULL&quot; &lt;&lt; std::endl;</span><br><span class="line">            return -1; // 或其他合适的错误值</span><br><span class="line">        &#125;</span><br><span class="line">    </span><br><span class="line">        // 检查 m_reply 类型</span><br><span class="line">        if (this-&gt;m_reply-&gt;type != REDIS_REPLY_INTEGER) &#123;</span><br><span class="line">            std::cerr &lt;&lt; &quot;Error: Expected integer reply&quot; &lt;&lt; std::endl;</span><br><span class="line">            freeReplyObject(this-&gt;m_reply);</span><br><span class="line">            return -1; // 或其他合适的错误值</span><br><span class="line">        &#125;</span><br><span class="line">        int num  = this-&gt;m_reply-&gt;integer;</span><br><span class="line">        freeReplyObject(this-&gt;m_reply);</span><br><span class="line">        std::cout &lt;&lt; &quot;G&quot; &lt;&lt; std::endl;</span><br><span class="line">        return num;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure></code></pre></li><li><p>在执行下面两句是，<code>%</code>会被替换为cmd.c_str(),导致无法将消息插入历史记录表，导致出现错误.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">std::string cmd = <span class="string">&quot;lpush &quot;</span> + key + <span class="string">&quot; &quot;</span> + value;</span><br><span class="line"><span class="keyword">this</span>-&gt;m_reply = (redisReply *)<span class="built_in">redisCommand</span>(<span class="keyword">this</span>-&gt;m_connettion, cmd.<span class="built_in">c_str</span>());</span><br></pre></td></tr></table></figure></li><li><p>只要更改为下面即没有问题</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>-&gt;m_reply = (redisReply *)<span class="built_in">redisCommand</span>(<span class="keyword">this</span>-&gt;m_connettion, <span class="string">&quot;LPUSH %s %s&quot;</span>, key.<span class="built_in">c_str</span>(), value.<span class="built_in">c_str</span>());</span><br></pre></td></tr></table></figure></li></ul></li><li><p>在某次测试时，新注册账号id为<code>0614897828</code>,导致与该账号聊天的账号进入聊天界面时，<code>0614897828</code>发送的消息会在他人界面显示为通知消息.</p><ul><li>由于与人聊天时会在数据库中创建有排序集合来记录某人正在聊天的人的id.运行时通过查看发现，其余账号与<code>0614897828</code>聊天时，数据库中记录账号为<code>614897828</code>.</li><li>更换为首位非0的id就不会出现该问题.</li><li>redis会将有序集合中的<code>score</code>字段字符串中的0去除.将从字符串的首位非0开始存储.</li></ul></li><li><p>在进入好友私聊界面时，客户端新建了来接收消息，同时主线程发消息，主线程通过判断用户是否键入<code>Esc</code>来退出聊天界面，在输入<code>Esc</code>时，接收消息线程无法正确回收，无法退出聊天界面.</p><ul><li>在接收消息线程中来判断标志位来结束该线程，主线程在键入<code>Esc</code>时，将标志位设置为<code>false</code>,但由于客户端的<code>recv</code>为阻塞，导致无法及时获取到标志位的更改.</li><li>在键入<code>Esc</code>时，服务器向客户端发送退出信号，这样就可以正确及时的获取到标志位的更改，从而正确退出.</li></ul></li><li><p>在进行发送文件时，服务器会先将文件存储在本地，但是服务器存储的文件会<code>多写入一些信息</code>，导致接收文件大小<code>偏大</code>.</p><ul><li>由于在用户登陆进入之后，会有一个线程每5秒向服务器送送刷新请求，导致服务器会将刷新请求当作文件内容写入文件，导致接收文件不一致</li><li>在进入文件收发菜单后，关闭实时刷新，在文件结束后，再将实时刷新打开.</li></ul></li><li><p>实现后台发送文件，由于会有实时刷新的存在，会导致文件发送不准确.</p><ul><li>在发送文件时，重新创建一个<code>socket</code>连接到服务器，在将发送这个文件交给另外一个线程</li><li>初始时在用户选择发送文件时开始线程，但会导致主线程与发送线程会同时运行菜单.主线程继续循环菜单，而发送线程运行获取发送文件的信息。<ul><li>更改线程开始时间，在用户选择发送文件时，获取到发送文件信息后，在启动线程.</li><li>新连接的<code>socket</code>发送文件后，服务器不用手动断开连接，服务器有<code>心跳检测</code>，会在一段时间后断开.</li></ul></li></ul></li></ul><h1 id="eventfd"><a href="#eventfd" class="headerlink" title="eventfd"></a>eventfd</h1><p><a href="https://juejin.cn/post/6989608237226000391">详解</a></p><p>是一个Linux系统调用，也是一种进程间通信(IPC)机制，主要通过<strong>使用文件描述符</strong>生成和使用事件通知.</p><p>提供了一种在不同进程之间或同一进程内的线程之间的同步事件的方法.</p><h1 id="异常处理"><a href="#异常处理" class="headerlink" title="异常处理"></a>异常处理</h1><p>异常是程序在执行期间产生的问题。c++异常是指在程序运行时发生的特殊情况.</p><p>异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字：<strong>try、catch、throw</strong></p><p>关键字：<strong>try、catch、throw</strong>。</p><ul><li><strong>throw:</strong> 当问题出现时，程序会抛出一个异常。这是通过使用 <strong>throw</strong> 关键字来完成的。</li></ul><ul><li><p><strong>catch:</strong> 在您想要处理问题的地方，通过异常处理程序捕获异常。<strong>catch</strong> 关键字用于捕获异常</p></li><li><p><strong>try:</strong> <strong>try</strong> 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块</p></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span></span><br><span class="line">&#123;</span><br><span class="line">   <span class="comment">// 保护代码</span></span><br><span class="line">&#125;<span class="built_in">catch</span>( ExceptionName e1 )</span><br><span class="line">&#123;</span><br><span class="line">   <span class="comment">// catch 块</span></span><br><span class="line">&#125;<span class="built_in">catch</span>( ExceptionName e2 )</span><br><span class="line">&#123;</span><br><span class="line">   <span class="comment">// catch 块</span></span><br><span class="line">&#125;<span class="built_in">catch</span>( ExceptionName eN )</span><br><span class="line">&#123;</span><br><span class="line">   <span class="comment">// catch 块</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="nlohmann-json"><a href="#nlohmann-json" class="headerlink" title="nlohmann::json"></a>nlohmann::json</h1><p><a href="https://readdevdocs.com/blog/tech/C++%20nlohmann%20json%E5%BA%93%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B.html#google_vignette">链接</a></p><h1 id="SIGPIPE"><a href="#SIGPIPE" class="headerlink" title="SIGPIPE"></a>SIGPIPE</h1><p><code>SIGPIPE</code> 是一种信号，当一个进程尝试向一个已经关闭的或不可写的管道或套接字写数据时，会触发这个信号。默认情况下，接收到 <code>SIGPIPE</code> 信号的进程会终止。这在网络编程中会导致一些问题，因为如果客户端断开连接，服务器进程在写入数据时会因为这个信号而意外退出。</p><p>在网络编程中，特别是使用套接字进行通信时，忽略 <code>SIGPIPE</code> 信号是一个常见的做法。这样可以防止进程因为 <code>SIGPIPE</code> 信号而意外终止。相反，程序可以通过检测 <code>send</code> 或 <code>write</code> 操作的返回值来处理错误，从而使程序更加健壮。</p><h1 id="后续问题"><a href="#后续问题" class="headerlink" title="后续问题"></a>后续问题</h1><ol><li><p>初始客户端构思方面的缺陷，导致实时消息没有线程及时接收。</p><p>当前处理方式为服务端将通知消息放入数据库当中，客户端在登陆之后，增加一个线程来定时执行刷新函数，刷新数据库中的通知消息</p><p>可以优化为在客户端登陆之后，采用多线程的方式来处理相关操作.</p></li><li><p>目前只有在历史消息这一操作涉及到<code>redis+mysql</code>的处理方式.</p><p>可以将一些重要信息也采用<code>redis+mysql</code>的处理方式(涉及到<code>redis</code>的存储方式，redis存储于内存当中，会造成数据丢失的情况)</p><p>可以考虑将redis全部做为缓存的形式，将重要信息与历史消息类似，达到一定情况下放入mysql,使数据更加的持久化.</p></li></ol><h1 id="后续学习"><a href="#后续学习" class="headerlink" title="后续学习"></a>后续学习</h1><ol><li><p>继续学习<code>epoll</code>的相关内容.</p></li><li><p>了解其余网络框架，使得该项目的服务端更加的健壮.</p></li><li><p>了解消息队列的信息同步的问题.</p></li><li><p>熟悉零拷贝的过程，以及零拷贝的具体实现.</p></li><li><p>序列化的相关协议，<code>json</code>与其他序列化的区别、<code>json</code>的优点，以及为什么不用其他的序列化</p></li><li><p>数据库的深入学习，了解<code>redis</code>的缓存穿透、缓存雪崩、缓存击穿。加强对<code>mysql</code>数据库的学习.</p></li><li><p>加强对网络协议相关知识的学习.</p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Future-聊天室&quot;&gt;&lt;a href=&quot;#Future-聊天室&quot; class=&quot;headerlink&quot; title=&quot;Future 聊天室&quot;&gt;&lt;/a&gt;Future 聊天室&lt;/h1&gt;&lt;h2 id=&quot;功能&quot;&gt;&lt;a href=&quot;#功能&quot; class=&quot;headerli</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    
    <category term="c++" scheme="https://future.thisis.host/tags/c/"/>
    
    <category term="chatroom" scheme="https://future.thisis.host/tags/chatroom/"/>
    
  </entry>
  
  <entry>
    <title>类型转换</title>
    <link href="https://future.thisis.host/2024/05/17/%E5%BC%BA%E5%88%B6%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2/"/>
    <id>https://future.thisis.host/2024/05/17/%E5%BC%BA%E5%88%B6%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2/</id>
    <published>2024-05-17T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.357Z</updated>
    
    <content type="html"><![CDATA[<h1 id="强制类型转换"><a href="#强制类型转换" class="headerlink" title="强制类型转换"></a>强制类型转换</h1><p>C++提供了四个强制类型转换的关键字：</p><ul><li><code>static_cast</code></li><li><code>const_cast</code></li><li><code>reinterpret_cast</code></li><li>&#96;&#96;dynamic_cast&#96;</li></ul><h2 id="static-cast"><a href="#static-cast" class="headerlink" title="static_cast"></a>static_cast</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">static_cast</span>&lt;目标类型&gt;(表达式)</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> num = <span class="number">2</span>;</span><br><span class="line"><span class="type">double</span> result =<span class="built_in">static_cast</span>&lt;<span class="type">double</span>&gt;(num);</span><br></pre></td></tr></table></figure><p>该运算符将<strong>表达式</strong>转换为<strong>目标类型</strong>。但没有进行运行时类型检查来保证转换的<strong>安全性</strong>。</p><p><strong>主要用法</strong></p><ol><li>用于类层次结构中父类和子类之间指针或引用的转换.进行上行转换是安全的（即将子类的指针或引用转换成父类是正确的）；进行下行转换的时候，由于没有动态类型检查，所以是不安全的。<strong>继承必须为public</strong></li><li>用于基本类型之间的转换，如<code>int</code>与<code>char</code>，<strong>安全性也需要程序员来保证</strong></li><li>把空指针转换为目标类型的空指针</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span>  <span class="title">print</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Person &quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> : <span class="keyword">public</span> Person</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">print</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Son &quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">print1</span><span class="params">(Person *p)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    p-&gt;<span class="built_in">print</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Son s;</span><br><span class="line">    <span class="built_in">print1</span>(<span class="built_in">static_cast</span>&lt;Person *&gt;(&amp;s));</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="const-cast"><a href="#const-cast" class="headerlink" title="const_cast"></a>const_cast</h2><p><code>const_cast</code>是c++中专用于处理与const相关的强制类型转换的关键字</p><p>其功能为：为一个变量重新设定其const描述.</p><p>即：<code>const_cast</code>可以为一个变量强行增加或删除其const限定.</p><p>需要明确的是，即使用户通过const_cast强行去除了const属性，也不代表当前变量从不可变变为了可变。const_cast只是使得用户接管了编译器对于const限定的管理权，故用户必须遵守“不修改变量”的承诺。如果违反此承诺，编译器也不会因此而引发编译时错误，但可能引发运行时错误。</p><ol><li>const_cast可用于更改const成员函数内的非const类成员。</li><li>const_cast可用于将const数据传递给不接收const的函数。</li><li>const_cast&lt;&gt;里边的内容必须是引用或者指针。</li><li>const_cast也可以用来抛弃<code>volatile</code>和<code>__unaligned</code>属性。</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Student</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"><span class="type">int</span> roll;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="built_in">Student</span>(<span class="type">int</span> r) :<span class="built_in">roll</span>(r) &#123;&#125;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">fun</span><span class="params">()</span> <span class="type">const</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">(<span class="built_in">const_cast</span>&lt;Student*&gt; (<span class="keyword">this</span>))-&gt;roll = <span class="number">5</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">getRoll</span><span class="params">()</span> </span>&#123; <span class="keyword">return</span> roll; &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="function">Student <span class="title">student</span><span class="params">(<span class="number">3</span>)</span></span>;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;Old roll number: &quot;</span> &lt;&lt; student.<span class="built_in">getRoll</span>() &lt;&lt; std::endl;</span><br><span class="line">    student.<span class="built_in">fun</span>();</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;New roll number: &quot;</span> &lt;&lt; student.<span class="built_in">getRoll</span>() &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// const_cast只能调节类型限定符，不能更改基础类型</span></span><br><span class="line">    <span class="type">int</span> a1 = <span class="number">40</span>;</span><br><span class="line">    <span class="comment">//const int* b1 = &amp;a1;</span></span><br><span class="line">    <span class="comment">//char* c1 = const_cast &lt;char*&gt; (b1); // 编译程序时出错</span></span><br><span class="line"></span><br><span class="line">    <span class="type">const</span> <span class="keyword">volatile</span> <span class="type">int</span>* d1 = &amp;a1;</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;typeid of d1 &quot;</span> &lt;&lt; <span class="built_in">typeid</span>(d1).<span class="built_in">name</span>() &lt;&lt; <span class="string">&#x27;\n&#x27;</span>; <span class="comment">// int const volatile *</span></span><br><span class="line">    <span class="type">int</span>* e1 = <span class="keyword">const_cast</span> &lt;<span class="type">int</span>*&gt; (d1);</span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;typeid of e1 &quot;</span> &lt;&lt; <span class="built_in">typeid</span>(e1).<span class="built_in">name</span>() &lt;&lt; <span class="string">&#x27;\n&#x27;</span>; <span class="comment">// int *</span></span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在const成员函数<code>fun()</code>中，编译器将<code>“this”</code>视为<code>“ const student const this”</code>，即<code>“this”</code>是指向常量对象的常量指针，因此编译器不允许通过以下方式更改数据成员“这个”指针。const_cast将<code>“this”</code>指针的类型更改为<code>“student const this”</code>。</p><p>const_cast比简单类型转换更安全。从某种意义上讲，如果强制类型与原始对象不相同，则强制转换不会发生，这是比较安全的。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a=<span class="number">20</span>;</span><br><span class="line"><span class="type">const</span> <span class="type">int</span> *p=&amp;a;</span><br><span class="line"><span class="type">char</span> *c1=<span class="built_in">const_cast</span>&lt;<span class="type">char</span>*&gt; (p);<span class="comment">//编译时程序出错</span></span><br></pre></td></tr></table></figure><h2 id="reinterpret-cast"><a href="#reinterpret-cast" class="headerlink" title="reinterpret_cast"></a><strong>reinterpret_cast</strong></h2><p><code>reinterpret</code>,即重新解释.</p><p>该强制类型转换的作用是提供某个变量在底层数据上的重新解释.</p><p>当我们对一个变量使用<code>reinterpret_cast</code>后，编译器将无视任何不合理行为，强行将被转换变量的内存数据重解释为某个新的类型。用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。转换时，执行的是逐个比特复制的操作。 它不检查指针类型和指针所指向的数据是否相同。</p><p><strong>需要注意的是，<code>reinterpret_cast</code>要求转换的两个数据所占用的内存大小一致</strong>，否则会引发编译时错误.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">data_type *var_name = <span class="keyword">reinterpret_cast</span> &lt;data_type *&gt;(pointer_variable);</span><br></pre></td></tr></table></figure><p>使用 reinterpret_cast 的目的：</p><ol><li>reinterpret_cast是一种非常特殊且危险的类型转换操作符。并且建议使用适当的数据类型使用它，即（指针数据类型应与原始数据类型相同）。</li><li>它可以将任何指针类型转换为任何其他数据类型。</li><li>当我们要使用位时使用它。</li><li>它仅用于将任何指针转换为原始类型。</li><li>布尔值将转换为整数值，即0表示false，1表示true。</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">A</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> a;</span><br><span class="line">    <span class="built_in">A</span>(<span class="type">int</span> i) :<span class="built_in">a</span>(i) &#123;&#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">fun_a</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;In class A\n&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">B</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> b;</span><br><span class="line">    <span class="built_in">B</span>(<span class="type">int</span> i) :<span class="built_in">b</span>(i) &#123;&#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">fun_b</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        std::cout &lt;&lt; <span class="string">&quot;In class B\n&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">testReinterpretCast</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    B *x = <span class="keyword">new</span> <span class="built_in">B</span>(<span class="number">5</span>);</span><br><span class="line">    A* y = <span class="built_in">reinterpret_cast</span>&lt;A*&gt;(x);</span><br><span class="line">    y-&gt;<span class="built_in">fun_a</span>();                      <span class="comment">// In class A</span></span><br><span class="line">    std::cout &lt;&lt; y-&gt;a &lt;&lt; std::endl;  <span class="comment">// 5</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="dynamic-cast"><a href="#dynamic-cast" class="headerlink" title="dynamic_cast"></a>dynamic_cast</h2><p><code>dynamic</code>用于在运行时实现向下类型转换。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">dynamic_cast</span> &lt;type-id&gt; (expression)</span><br></pre></td></tr></table></figure><p>将<code>expression</code>转换为<code>type-id</code>类型,<code>type-id</code>必须是类的指针，类的引用或者是<strong>void</strong>,</p><p>如果<code>type-id</code>是一个指针，那么<code>expression</code>也是一个指针，是<strong>引用</strong>的话同为<strong>引用</strong></p><p>特点如下：</p><ol><li>它是在运行是进行处理的，其余三个都是在编译时完成. 运行时进行类型检查</li><li>不能用于内置的基本数据类型之间的强制转换</li><li>dynamic_cast 要求 &lt;&gt; 内所描述的目标类型必须为指针或引用。dynamic_cast 转换如果成功的话返回的是指向类的指针或引用，转换失败的话则会返回 <code>nullptr</code>。</li><li>在类的转换时，在类层次上进行向上转换（子类指针指向父类指针），与<code>static_cast</code>的效果是一样的。在进行父类指针向子类指针的转换时，<code>dynamic_cast</code>具有类型检查的功能，比<code>static_cast</code>更安全。</li><li>向下转换的成功与否还与将要转换的类型有关，<strong>即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同</strong>，否则转换失败。在C++中，编译期的类型转换有可能会在运行时出现错误，特别是涉及到类对象的指针或引用操作时，更容易产生错误。<code>dynamic_cast</code>操作符则可以在运行期对可能产生问题的类型转换进行测试。</li><li>使用 dynamic_cast 进行转换的，<strong>基类中一定要有虚函数</strong>，否则编译不通过（类中存在虚函数，就说明它有想要让基类指针或引用指向派生类对象的情况，此时转换才有意义）。<strong>这是由于运行时类型检查需要运行时类型信息，而这个信息存储在类的虚函数表中，只有定义了虚函数的类才有虚函数表。</strong></li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">AA</span> &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">print</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;in class AA&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">BB</span> :<span class="keyword">public</span> AA &#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">print</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;in class BB&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">testDynamicCast</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    AA* a1 = <span class="keyword">new</span> BB; <span class="comment">// a1是A类型的指针指向一个B类型的对象</span></span><br><span class="line">    AA* a2 = <span class="keyword">new</span> AA; <span class="comment">// a2是A类型的指针指向一个A类型的对象</span></span><br><span class="line"></span><br><span class="line">    BB* b1, * b2, * b3, * b4;</span><br><span class="line"></span><br><span class="line">    b1 = <span class="built_in">dynamic_cast</span>&lt;BB*&gt;(a1);<span class="comment">// not null，向下转换成功，a1 之前指向的就是 B 类型的对象，所以可以转换成 B 类型的指针。</span></span><br><span class="line">    <span class="keyword">if</span> (b1 == <span class="literal">nullptr</span>) </span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;b1 is null&quot;</span> &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">else</span>               </span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;b1 is not null&quot;</span> &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    b2 = <span class="built_in">dynamic_cast</span>&lt;BB*&gt;(a2);<span class="comment">// null，向下转换失败</span></span><br><span class="line">    <span class="keyword">if</span> (b2 == <span class="literal">nullptr</span>) </span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;b2 is null&quot;</span> &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">else</span>               </span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;b2 is not null&quot;</span> &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 用 static_cast，Resharper C++ 会提示修改为 dynamic_cast</span></span><br><span class="line">    b3 = <span class="built_in">static_cast</span>&lt;BB*&gt;(a1);<span class="comment">// not null</span></span><br><span class="line">    <span class="keyword">if</span> (b3 == <span class="literal">nullptr</span>) </span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;b3 is null&quot;</span> &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">else</span>               </span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;b3 is not null&quot;</span> &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    b4 = <span class="built_in">static_cast</span>&lt;BB*&gt;(a2);<span class="comment">// not null</span></span><br><span class="line">    <span class="keyword">if</span> (b4 == <span class="literal">nullptr</span>) </span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;b4 is null&quot;</span> &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">else</span>               </span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;b4 is not null&quot;</span> &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    a1-&gt;<span class="built_in">print</span>();<span class="comment">// in class BB</span></span><br><span class="line">    a2-&gt;<span class="built_in">print</span>();<span class="comment">// in class AA</span></span><br><span class="line"></span><br><span class="line">    b1-&gt;<span class="built_in">print</span>();<span class="comment">// in class BB</span></span><br><span class="line">    <span class="comment">//b2-&gt;print();    // null 引发异常</span></span><br><span class="line">    b3-&gt;<span class="built_in">print</span>();<span class="comment">// in class BB</span></span><br><span class="line">    b4-&gt;<span class="built_in">print</span>();<span class="comment">// in class AA</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><a href="https://mqjyl2012.gitbook.io/algorithm/c-cpp/c++-syntax/type-conversion">详细</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;强制类型转换&quot;&gt;&lt;a href=&quot;#强制类型转换&quot; class=&quot;headerlink&quot; title=&quot;强制类型转换&quot;&gt;&lt;/a&gt;强制类型转换&lt;/h1&gt;&lt;p&gt;C++提供了四个强制类型转换的关键字：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;static_cast&lt;/co</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    <category term="c++" scheme="https://future.thisis.host/categories/notes/c/"/>
    
    
    <category term="c++" scheme="https://future.thisis.host/tags/c/"/>
    
    <category term="类型转换" scheme="https://future.thisis.host/tags/%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2/"/>
    
  </entry>
  
  <entry>
    <title>lambda</title>
    <link href="https://future.thisis.host/2024/05/10/lambda/"/>
    <id>https://future.thisis.host/2024/05/10/lambda/</id>
    <published>2024-05-10T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.355Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Lambda表达式"><a href="#Lambda表达式" class="headerlink" title="Lambda表达式"></a>Lambda表达式</h1><p>匿名函数是很多高级语言都支持的概念，如lisp语言在1958年首先采用匿名函数。匿名函数有函数体，但没有函数名。C++11中引入了lambda表达式。利用<code>lambda</code>表达式可以编写内嵌的匿名函数，用以替换独立函数或者函数对象，并且使代码更可读。但是从本质上来讲，<code>lambda</code>表达式只是一种语法糖，因为所有其能完成的工作都可以用其它稍微复杂的代码来实现。但是它简便的语法却给<code>C++</code>带来了深远的影响。如果从广义上说，<code>lamdba</code>表达式产生的是函数对象。</p><blockquote><p>相同类似功能我们也可以使用<strong>函数对象</strong>或者<strong>函数指针</strong>实现：函数对象能维护状态，但语法开销大，而函数指针语法开销小，却没法保存范围内的状态。lambda表达式正是结合了两者的优点。 </p></blockquote><h2 id="声明Lambda表达式"><a href="#声明Lambda表达式" class="headerlink" title="声明Lambda表达式"></a>声明Lambda表达式</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 完整语法</span></span><br><span class="line">[capture list] (params list) <span class="built_in">mutable</span>(optional) <span class="built_in">constexpr</span>(optional)(c+<span class="number">+17</span>) exception attribute -&gt; <span class="keyword">return</span> type &#123; function body &#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 可选的简化语法</span></span><br><span class="line">[capture list] (params list) -&gt; <span class="keyword">return</span> type &#123;function body&#125;;  <span class="comment">//1</span></span><br><span class="line">[capture list] (params list) &#123;function body&#125;;<span class="comment">//2</span></span><br><span class="line">[capture list] &#123;function body&#125;;<span class="comment">//3</span></span><br></pre></td></tr></table></figure><ul><li>capture list：捕获外部变量列表，不能省略；</li><li>params list：形参列表，可以省略（但是后面必须紧跟函数体）；</li><li>mutable指示符： 可选，将<code>lambda</code>表达式标记为<code>mutable</code>后，函数体就可以修改传值方式捕获的变量；</li><li>constexpr：可选，C++17，可以指定<code>lambda</code>表达式是一个常量函数；</li><li>exception：异常设定， 可选，指定<code>lambda</code>表达式可以抛出的异常；</li><li>attribute：可选，指定<code>lambda</code>表达式的特性；</li><li>return type：返回类型</li><li>function body：函数体</li></ul><p>标号1. 函数声明了一个const类型的表达式，此声明不可改变capture list中的捕获的值。</p><p>标号2. 函数省略了返回值，此时如果function body内含有return语句，则按return语句返回类型决定返回值类型，若无则返回值为void类型。</p><p>标号3. 函数无参数列表，意味无参函数。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">vector&lt;<span class="type">int</span>&gt; vec&#123;<span class="number">1</span>,<span class="number">0</span>,<span class="number">9</span>,<span class="number">5</span>,<span class="number">3</span>,<span class="number">3</span>,<span class="number">7</span>,<span class="number">8</span>,<span class="number">2</span>&#125;;</span><br><span class="line"></span><br><span class="line"><span class="built_in">sort</span>(lbvec.<span class="built_in">begin</span>(), lbvec.<span class="built_in">end</span>(), [](<span class="type">int</span> a, <span class="type">int</span> b) -&gt; <span class="type">bool</span> &#123; <span class="keyword">return</span> a &lt; b; &#125;);  </span><br></pre></td></tr></table></figure><h2 id="捕获外部变量"><a href="#捕获外部变量" class="headerlink" title="捕获外部变量"></a>捕获外部变量</h2><p><code>lambda</code>表达式最前面的方括号的意义何在？其实这是<code>lambda</code>表达式一个很Hong要的功能，就是闭包。这里我们先讲一下<code>lambda</code>表达式的大致原理：每当你定义一个<code>lambda</code>表达式后，编译器会自动生成一个匿名类（这个类当然重载了<code>()</code>运算符），我们称为闭包类型（closure type）。那么在运行时，这个<code>lambda</code>表达式就会返回一个<strong>匿名的闭包实例</strong>，其实一个右值。所以，我们上面的<code>lambda</code>表达式的结果就是一个个闭包。闭包的一个强大之处是其可以通过传值或者引用的方式捕捉<strong>其封装作用域内的变量</strong>，前面的方括号就是用来定义捕捉模式以及变量，我们又将其称为<code>lambda</code>捕捉块。</p><p>Lambda表达式可以捕获外面变量，但需要我们提供一个谓词函数（[capture list]在声明表达式最前）。类似参数传递方式：值传递、引入传递、指针传递。在Lambda表达式中，外部变量捕获方式也类似：<strong>值捕获、引用捕获、隐式捕获</strong>。</p><h3 id="值捕获"><a href="#值捕获" class="headerlink" title="值捕获"></a>值捕获</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = <span class="number">123</span>;</span><br><span class="line"><span class="keyword">auto</span> f = [a] &#123; cout &lt;&lt; a &lt;&lt; endl; &#125;; </span><br><span class="line"><span class="built_in">f</span>(); <span class="comment">// 输出：123</span></span><br><span class="line">a = <span class="number">321</span>;</span><br><span class="line"><span class="built_in">f</span>(); <span class="comment">// 输出：123</span></span><br></pre></td></tr></table></figure><p>值捕获和参数传递中的<strong>值传递</strong>类似，被捕获的值在Lambda表达式创建时通过<strong>值拷贝</strong>的方式传入，类中会相应添加对应类型的非静态数据成员。在运行时，会用复制的值初始化这些成员变量，从而生成闭包。因此<strong>Lambda表达式函数体中不能修改该外部变量的值</strong>； 因为函数调用运算符的重载方法是<code>const</code>属性的。同样，函数体外对于值的修改也不会改变被捕获的值。 想改动传值方式捕获的值，那么就要使用<code>mutable</code>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> add_x = [x](<span class="type">int</span> a) <span class="keyword">mutable</span> &#123; x *= <span class="number">2</span>; <span class="keyword">return</span> a + x; &#125;;  <span class="comment">// 复制捕捉x</span></span><br><span class="line">    </span><br><span class="line">cout &lt;&lt; <span class="built_in">add_x</span>(<span class="number">10</span>) &lt;&lt; endl; <span class="comment">// 输出：30</span></span><br></pre></td></tr></table></figure><p> 因为一旦将<code>lambda</code>表达式标记为<code>mutable</code>，那么实现的函数调用运算符是非const属性的。</p><h3 id="引用捕获"><a href="#引用捕获" class="headerlink" title="引用捕获"></a>引用捕获</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = <span class="number">123</span>;</span><br><span class="line"><span class="keyword">auto</span> f = [&amp;a] &#123; cout &lt;&lt; a &lt;&lt; endl; &#125;; </span><br><span class="line">a = <span class="number">321</span>;</span><br><span class="line"><span class="built_in">f</span>(); <span class="comment">// 输出：321</span></span><br></pre></td></tr></table></figure><p>引用捕获的变量使用的实际上就是该引用所绑定的对象，因此引用对象的改变会改变函数体内对该对象的引用的值。 对于引用捕获方式，无论是否标记<code>mutable</code>，都可以在<code>lambda</code>表达式中修改捕获的值。</p><h3 id="隐式捕获"><a href="#隐式捕获" class="headerlink" title="隐式捕获"></a>隐式捕获</h3><p>隐式捕获有两种方式，分别是 [&#x3D;]：以值补获的方式捕获外部<strong>所有变量</strong> [&amp;]：表示以引用捕获的方式捕获外部<strong>所有变量</strong>。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> a = <span class="number">123</span>, b=<span class="number">321</span>;</span><br><span class="line"><span class="keyword">auto</span> df = [=] &#123; cout &lt;&lt; a &lt;&lt; b &lt;&lt; endl; &#125;;    <span class="comment">// 值捕获</span></span><br><span class="line"><span class="keyword">auto</span> rf = [&amp;] &#123; cout &lt;&lt; a &lt;&lt; b &lt;&lt; endl; &#125;;    <span class="comment">// 引用捕获</span></span><br></pre></td></tr></table></figure><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><table><thead><tr><th>捕获外部变量形式</th><th></th></tr></thead><tbody><tr><td>[ ]</td><td>不捕获任何变量（无参函数）</td></tr><tr><td>[变量1,&amp;变量2, …]</td><td>值(引用)形式捕获指定的多个外部变量</td></tr><tr><td>[this]</td><td>值捕获this指针</td></tr><tr><td>[&#x3D;, &amp;x]</td><td>变量x以引用形式捕获，其余变量以传值形式捕获</td></tr><tr><td>[*this]</td><td>通过传值方式捕获当前对象</td></tr><tr><td>[&amp;, x]</td><td>默认以引用捕获所有变量，但是x是例外，通过值捕获</td></tr></tbody></table><blockquote><p>既然只使用一次，那直接写全代码不就行了，为啥要函数呢？——因为lambda可以捕获局部变量</p></blockquote><p>在上面的捕获方式中，注意最好不要使用<code>[=]</code>和<code>[&amp;]</code>默认捕获所有变量。首先说默认引用捕获所有变量，你有很大可能会出现悬挂引用（Dangling references），因为引用捕获不会延长引用的变量的声明周期：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::function&lt;<span class="title">int</span><span class="params">(<span class="type">int</span>)</span>&gt; <span class="title">add_x</span><span class="params">(<span class="type">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="keyword">return</span> [&amp;](<span class="type">int</span> a) &#123;<span class="keyword">return</span> x+a;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>因为参数<code>x</code>仅是一个临时变量，函数调用后就被销毁，但是返回的<code>lambda</code>表达式却引用了该变量，但调用这个表达式时，引用的是一个垃圾值，所以会产生没有意义的结果。如果通过传值的方式来解决上面的问题：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::function&lt;<span class="title">int</span><span class="params">(<span class="type">int</span>)</span>&gt; <span class="title">add_x</span><span class="params">(<span class="type">int</span> x)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> [=](<span class="type">int</span> a) &#123; <span class="keyword">return</span> x + a; &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用默认传值方式可以便面悬挂引用问题.但是采用默认值捕获所有变量仍然有风险。例如当在类中捕获私有变量，当返回值为lambda表达式时，无法捕获到私有变量，但当指定为[&#x3D;]时，会捕获到<code>this</code>指针的副本，当类已经调用析构函数，使用该指针仍然不安全.</p><h2 id="参数"><a href="#参数" class="headerlink" title="参数"></a>参数</h2><ul><li>参数列表中不能有默认参数</li><li>不支持可变参数</li><li>所有参数必须要参数名（相当于不可以有占位参数）</li></ul><h2 id="返回类型"><a href="#返回类型" class="headerlink" title="返回类型"></a>返回类型</h2><p>单一的return语句可以推断返回类型；多语句则默认返回void，否则报错，应指定返回类型</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 正确，单一return语句</span></span><br><span class="line"><span class="built_in">transform</span>(vi.<span class="built_in">begin</span>(),vi.<span class="built_in">end</span>(),vi.<span class="built_in">begin</span>(), </span><br><span class="line">    [] (<span class="type">int</span> i) &#123; </span><br><span class="line">    <span class="keyword">return</span> i&lt;<span class="number">0</span>? -i; i;</span><br><span class="line">    &#125;</span><br><span class="line">);</span><br><span class="line"><span class="comment">// 错误。不能推断返回类型</span></span><br><span class="line"><span class="built_in">transform</span>(vi.<span class="built_in">begin</span>(),vi.<span class="built_in">end</span>(),vi.<span class="built_in">begin</span>(), </span><br><span class="line">    [] (<span class="type">int</span> i) &#123; </span><br><span class="line">        <span class="keyword">if</span> (I&lt;<span class="number">0</span>) <span class="keyword">return</span> -i;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">return</span> i;</span><br><span class="line">    &#125;</span><br><span class="line">);</span><br><span class="line"><span class="comment">// 正确，尾置返回类型</span></span><br><span class="line"><span class="built_in">transform</span>(vi.<span class="built_in">begin</span>(),vi.<span class="built_in">end</span>(),vi.<span class="built_in">begin</span>(), </span><br><span class="line">    [] (<span class="type">int</span> i) -&gt;<span class="type">int</span>&#123; </span><br><span class="line">        <span class="keyword">if</span> (I&lt;<span class="number">0</span>) </span><br><span class="line">            <span class="keyword">return</span> -i;</span><br><span class="line">        <span class="keyword">else</span> </span><br><span class="line">            <span class="keyword">return</span> i;</span><br><span class="line">    &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h2 id="赋值"><a href="#赋值" class="headerlink" title="赋值"></a>赋值</h2><p>auto和function可接受lambda表达式的返回：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> x =<span class="number">8</span>,y=<span class="number">9</span>;</span><br><span class="line"><span class="keyword">auto</span> add = [](<span class="type">int</span> a,<span class="type">int</span> b)&#123;<span class="keyword">return</span> a+b;&#125;;</span><br><span class="line">std::function&lt;<span class="type">int</span>(<span class="type">int</span>,<span class="type">int</span>)&gt; Add = [=] (<span class="type">int</span> a,<span class="type">int</span> b)&#123;<span class="keyword">return</span> a+b&#125;;</span><br></pre></td></tr></table></figure><p>lambda表达式产生的类不含有默认构造函数、赋值运算符、默认析构函数。至于闭包类中是否有对应成员，<code>C++</code>标准中给出的答案是：不清楚的，看来与具体实现有关。还有一点要注意：<code>lambda</code>表达式是不能被赋值的：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> a = [] &#123; cout &lt;&lt; <span class="string">&quot;A&quot;</span> &lt;&lt; endl; &#125;;</span><br><span class="line"><span class="keyword">auto</span> b = [] &#123; cout &lt;&lt; <span class="string">&quot;B&quot;</span> &lt;&lt; endl; &#125;;</span><br><span class="line"></span><br><span class="line">a = b;   <span class="comment">// 非法，lambda无法赋值</span></span><br><span class="line"><span class="keyword">auto</span> c = a;   <span class="comment">// 合法，生成一个副本</span></span><br></pre></td></tr></table></figure><p>因为禁用了赋值操作符：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ClosureType&amp; <span class="keyword">operator</span>=(<span class="type">const</span> ClosureType&amp;) = <span class="keyword">delete</span>;</span><br></pre></td></tr></table></figure><p>但是没有禁用复制构造函数，所以可以用一个<code>lambda</code>表达式去初始化另外一个<code>lambda</code>表达式而产生副本。并且<code>lambda</code>表达式也可以赋值给相对应的函数指针，这也使得你完全可以把<code>lambda</code>表达式看成对应<strong>函数类型的指针</strong>。</p><h2 id="新特性"><a href="#新特性" class="headerlink" title="新特性"></a>新特性</h2><p>在<code>C++14</code>中，<code>lambda</code>又得到了增强，一个是泛型<code>lambda</code>表达式，一个是<code>lambda</code>可以捕捉表达式。</p><h3 id="lambda捕捉表达式"><a href="#lambda捕捉表达式" class="headerlink" title="lambda捕捉表达式"></a>lambda捕捉表达式</h3><p><code>lambda</code>表达式可以按复制或者引用捕获在其作用域范围内的变量。而有时候，我们希望捕捉不在其作用域范围内的变量，而且最重要的是我们希望捕捉右值。所以<code>C++14</code>中引入了表达式捕捉，其允许用任何类型的表达式初始化捕捉的变量：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 利用表达式捕获，可以更灵活地处理作用域内的变量</span></span><br><span class="line"><span class="type">int</span> x = <span class="number">4</span>;</span><br><span class="line"><span class="keyword">auto</span> y = [&amp;r = x, x = x + <span class="number">1</span>] &#123; r += <span class="number">2</span>; <span class="keyword">return</span> x * x; &#125;();</span><br><span class="line"><span class="comment">// 此时 x 更新为6，y 为25</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 直接用字面值初始化变量</span></span><br><span class="line"><span class="keyword">auto</span> z = [str = <span class="string">&quot;string&quot;</span>]&#123; <span class="keyword">return</span> str; &#125;();</span><br><span class="line"><span class="comment">// 此时z是const char* 类型，存储字符串 string</span></span><br></pre></td></tr></table></figure><p>可以看到捕捉表达式扩大了<code>lambda</code>表达式的捕捉能力，有时候你可以用<code>std::move</code>初始化变量。这对不能复制只能移动的对象很重要，比如<code>std::unique_ptr</code>，因为其不支持复制操作，你无法以值方式捕捉到它。但是利用<code>lambda</code>捕捉表达式，可以通过移动来捕捉它：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> myPi = std::<span class="built_in">make_unique</span>&lt;<span class="type">double</span>&gt;(<span class="number">3.1415</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">auto</span> circle_area = [pi = std::<span class="built_in">move</span>(myPi)](<span class="type">double</span> r) &#123; <span class="keyword">return</span> *pi * r * r; &#125;;</span><br><span class="line">cout &lt;&lt; <span class="built_in">circle_area</span>(<span class="number">1.0</span>) &lt;&lt; endl; <span class="comment">// 3.1415</span></span><br></pre></td></tr></table></figure><p><a href="https://mqjyl2012.gitbook.io/algorithm/c-cpp/advanced-c++/lambda">原文章</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;Lambda表达式&quot;&gt;&lt;a href=&quot;#Lambda表达式&quot; class=&quot;headerlink&quot; title=&quot;Lambda表达式&quot;&gt;&lt;/a&gt;Lambda表达式&lt;/h1&gt;&lt;p&gt;匿名函数是很多高级语言都支持的概念，如lisp语言在1958年首先采用匿名函数。匿名</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    
    <category term="c++" scheme="https://future.thisis.host/tags/c/"/>
    
    <category term="lambda" scheme="https://future.thisis.host/tags/lambda/"/>
    
  </entry>
  
  <entry>
    <title>随笔</title>
    <link href="https://future.thisis.host/2024/05/03/%E5%AE%9E%E7%8E%B0/"/>
    <id>https://future.thisis.host/2024/05/03/%E5%AE%9E%E7%8E%B0/</id>
    <published>2024-05-03T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.357Z</updated>
    
    <content type="html"><![CDATA[<h1 id="可变参数模板"><a href="#可变参数模板" class="headerlink" title="可变参数模板"></a>可变参数模板</h1><p>可变参数模板是C++11引入的一个特性，它允许定义一个接受任意数量参数的模板.</p><p>在函数模板或类模板中，我们可以使用可变参数模板来定义接受任意数量参数的函数或类。可变参数模板使用了模板参数包（template parameter pack），它允许我们将零个或多个模板参数打包成一个参数集合。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function">T <span class="title">sum</span><span class="params">(T arg)</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> arg;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T,<span class="keyword">typename</span>...Args&gt;</span></span><br><span class="line"><span class="function">T <span class="title">sum</span><span class="params">(T first ,Args...res)</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> first+<span class="built_in">sum</span>(rest...);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="尾部类型推导"><a href="#尾部类型推导" class="headerlink" title="尾部类型推导"></a>尾部类型推导</h1><p>当需要使用尾部类型推导的时候，通常是因为函数的返回类型依赖于函数参数或其他的上下文.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">auto</span> add=[](<span class="type">int</span> x,<span class="type">int</span> y)-&gt;<span class="type">int</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> x+y;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">auto</span> add=[](<span class="type">int</span> x,<span class="type">int</span> y)-&gt;<span class="keyword">auto</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> x+y;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//函数模板</span></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T, <span class="keyword">typename</span> U&gt;</span></span><br><span class="line"><span class="function"><span class="keyword">auto</span> <span class="title">multiply</span><span class="params">(T x, U y)</span> -&gt; <span class="title">decltype</span><span class="params">(x * y)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x * y;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="std-accumulate"><a href="#std-accumulate" class="headerlink" title="std::accumulate"></a>std::accumulate</h2><p><code>std::accumulate</code> 是 C++ 标准库 <code>&lt;numeric&gt;</code> 头文件中提供的一个算法函数，用于计算给定范围内的元素的总和。它接受一个起始迭代器和一个终止迭代器，以及一个初始值，然后对范围内的元素进行累加，并返回结果。</p><p>它的基本语法如下：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">cppCopy codetemplate&lt; <span class="keyword">class</span> InputIt, <span class="keyword">class</span> T &gt;</span></span><br><span class="line"><span class="function">T <span class="title">accumulate</span><span class="params">( InputIt first, InputIt last, T init )</span></span>;</span><br></pre></td></tr></table></figure><p>其中：</p><ul><li><code>InputIt</code> 是起始迭代器和终止迭代器的类型。</li><li><code>first</code> 是范围的起始迭代器。</li><li><code>last</code> 是范围的终止迭代器（不包括在范围内）。</li><li><code>init</code> 是初始值，用于累加元素。</li></ul><h2 id="decltype"><a href="#decltype" class="headerlink" title="decltype"></a>decltype</h2><p><code>decltype</code> 是 C++11 引入的一个关键字，用于获取表达式的类型。它可以用于声明变量、函数返回类型、模板参数等地方。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">decltype</span>(expression)</span><br></pre></td></tr></table></figure><h1 id="std-bind"><a href="#std-bind" class="headerlink" title="std::bind"></a>std::bind</h1><p><a href="https://en.cppreference.com/w/cpp/utility/functional/bind">链接</a></p><p><strong>std::bind的头文件是 <functional></strong></p><p><a href="https://zhuanlan.zhihu.com/p/428668958">解释</a></p><h1 id="std-result-of"><a href="#std-result-of" class="headerlink" title="std::result_of"></a>std::result_of</h1><p><code>std::result_of</code> 是一个 C++11 标准库中的模板工具，用于获取函数对象的返回类型。它可以用于在编译时确定函数对象的返回类型，而不需要实际调用该函数对象。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;type_traits&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> a, <span class="type">int</span> b)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">// 获取 add 函数的返回类型</span></span><br><span class="line">    <span class="keyword">typedef</span> std::result_of&lt;<span class="keyword">decltype</span>(add)&amp;(<span class="type">int</span>, <span class="type">int</span>)&gt;::type result_type;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 输出返回类型</span></span><br><span class="line">    std::cout &lt;&lt; <span class="string">&quot;Result type: &quot;</span> &lt;&lt; <span class="built_in">typeid</span>(result_type).<span class="built_in">name</span>() &lt;&lt; std::endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>std::result_of</code> 和 <code>decltype</code> 都是用于获取表达式的类型，但它们之间有一些区别：</p><ol><li><strong>用法</strong>：<ul><li><code>std::result_of</code> 用于获取函数对象的返回类型，而不需要实际调用该函数对象。它是一个模板类，需要指定函数对象的类型和参数类型。</li><li><code>decltype</code> 用于获取表达式的类型，可以是任意的表达式，不仅限于函数调用。它是一个关键字，可以直接用于变量声明、返回类型推断等地方。</li></ul></li><li><strong>适用范围</strong>：<ul><li><code>std::result_of</code> 主要用于获取函数对象的返回类型，因此在涉及函数对象的场景下更为常见。</li><li><code>decltype</code> 不仅可以用于函数调用，还可以用于变量声明、表达式的类型推断等场景，更为灵活。</li></ul></li><li><strong>语法</strong>：<ul><li><code>std::result_of</code> 的语法是模板类模板参数，需要传递函数类型和参数类型。</li><li><code>decltype</code> 的语法更为灵活，可以直接对任意表达式使用。</li></ul></li></ol><h1 id="std-filesvstem"><a href="#std-filesvstem" class="headerlink" title="std::filesvstem"></a>std::filesvstem</h1><p><a href="https://en.cppreference.com/w/cpp/filesystem">cppreference</a></p><p><a href="https://blog.csdn.net/qq_40946921/article/details/91394589">csdn</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;可变参数模板&quot;&gt;&lt;a href=&quot;#可变参数模板&quot; class=&quot;headerlink&quot; title=&quot;可变参数模板&quot;&gt;&lt;/a&gt;可变参数模板&lt;/h1&gt;&lt;p&gt;可变参数模板是C++11引入的一个特性，它允许定义一个接受任意数量参数的模板.&lt;/p&gt;
&lt;p&gt;在函数模板或类</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    
    <category term="notes" scheme="https://future.thisis.host/tags/notes/"/>
    
    <category term="c++" scheme="https://future.thisis.host/tags/c/"/>
    
  </entry>
  
  <entry>
    <title>c++ thread notes</title>
    <link href="https://future.thisis.host/2024/04/09/c++%E7%BA%BF%E7%A8%8B%E7%89%B9%E6%80%A7/"/>
    <id>https://future.thisis.host/2024/04/09/c++%E7%BA%BF%E7%A8%8B%E7%89%B9%E6%80%A7/</id>
    <published>2024-04-09T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.355Z</updated>
    
    <content type="html"><![CDATA[<h1 id="C-11线程特性"><a href="#C-11线程特性" class="headerlink" title="C++11线程特性"></a>C++11线程特性</h1><h2 id="std-thread"><a href="#std-thread" class="headerlink" title="std::thread"></a>std::thread</h2><p><a href="https://en.cppreference.com/w/cpp/thread/thread">标准库</a></p><p>C++11引入了<code>std::thread</code>来创建线程，支持对线程join或者detach.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;thread&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">auto</span> func = []() &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; ++i) &#123;</span><br><span class="line">            cout &lt;&lt; i &lt;&lt; <span class="string">&quot; &quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        cout &lt;&lt; endl;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="function">std::thread <span class="title">t</span><span class="params">(func)</span></span>;</span><br><span class="line">    <span class="keyword">if</span> (t.<span class="built_in">joinable</span>()) &#123;</span><br><span class="line">        t.<span class="built_in">detach</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">auto</span> func1 = [](<span class="type">int</span> k) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; k; ++i) &#123;</span><br><span class="line">            cout &lt;&lt; i &lt;&lt; <span class="string">&quot; &quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        cout &lt;&lt; endl;</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="function">std::thread <span class="title">tt</span><span class="params">(func1, <span class="number">20</span>)</span></span>;</span><br><span class="line">    <span class="keyword">if</span> (tt.<span class="built_in">joinable</span>()) &#123; <span class="comment">// 检查线程可否被join</span></span><br><span class="line">        tt.<span class="built_in">join</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">ThreadGuard</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="keyword">enum class</span> <span class="title class_">DeAction</span>&#123;join,detach&#125;;</span><br><span class="line">    <span class="built_in">ThreadGuard</span>(std::thread&amp;&amp; t,DeAction action): <span class="built_in">m_t</span>(<span class="built_in">move</span>(t)) , <span class="built_in">m_action</span>(action)&#123;&#125;;</span><br><span class="line">    ~<span class="built_in">ThreadGuard</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="type">m_t</span>.<span class="built_in">joinable</span>())</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span>(m_action==DeAction::join)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="type">m_t</span>.<span class="built_in">join</span>();</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                <span class="type">m_t</span>.<span class="built_in">detach</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">ThreadGuard</span>(ThreadGuard&amp;&amp;)=<span class="keyword">default</span>;</span><br><span class="line">    ThreadGuard&amp; <span class="keyword">operator</span>=(ThreadGuard&amp;&amp;)=<span class="keyword">default</span>;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    std::thread <span class="type">m_t</span>;</span><br><span class="line">    DeAction m_action;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>c++11还提供了获取线程id，或者系统cpu个数，获取thread native_handle，使得线程休眠等功能</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::thread <span class="title">t</span><span class="params">(func)</span></span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;当前线程ID &quot;</span> &lt;&lt; t.<span class="built_in">get_id</span>() &lt;&lt; endl;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;当前cpu个数 &quot;</span> &lt;&lt; std::thread::<span class="built_in">hardware_concurrency</span>() &lt;&lt; endl;</span><br><span class="line"><span class="keyword">auto</span> handle = t.<span class="built_in">native_handle</span>();<span class="comment">// handle可用于pthread相关操作</span></span><br><span class="line">std::this_thread::<span class="built_in">sleep_for</span>(std::chrono::<span class="built_in">seconds</span>(<span class="number">1</span>));</span><br></pre></td></tr></table></figure><h2 id="std-mutex"><a href="#std-mutex" class="headerlink" title="std::mutex"></a>std::mutex</h2><p>std::mutex是一种线程同步的手段，用于保存多线程同时操作的共享数据。</p><p><a href="https://en.cppreference.com/w/cpp/thread/mutex">文库</a></p><p>mutex分为四种：</p><ul><li><p>std::mutex：独占的互斥量，不能递归使用，不带超时功能</p></li><li><p>std::recursive_mutex：递归互斥量，可重入，不带超时功能</p></li><li><p>std::timed_mutex：带超时的互斥量，不能递归</p></li><li><p>std::recursive_timed_mutex：带超时的互斥量，可以递归使用</p><p>std::mutex</p></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;mutex&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;thread&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line">std::mutex mutex_;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">auto</span> func1 = [](<span class="type">int</span> k) &#123;</span><br><span class="line">        mutex_.<span class="built_in">lock</span>();</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; k; ++i) &#123;</span><br><span class="line">            cout &lt;&lt; i &lt;&lt; <span class="string">&quot; &quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        cout &lt;&lt; endl;</span><br><span class="line">        mutex_.<span class="built_in">unlock</span>();</span><br><span class="line">    &#125;;</span><br><span class="line">    std::thread threads[<span class="number">5</span>];</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; ++i) &#123;</span><br><span class="line">        threads[i] = std::<span class="built_in">thread</span>(func1, <span class="number">200</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">auto</span>&amp; th : threads) &#123;</span><br><span class="line">        th.<span class="built_in">join</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>std::timed_mutex</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;mutex&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;thread&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;chrono&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line">std::timed_mutex timed_mutex_;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">auto</span> func1 = [](<span class="type">int</span> k) &#123;</span><br><span class="line">        timed_mutex_.<span class="built_in">try_lock_for</span>(std::chrono::<span class="built_in">milliseconds</span>(<span class="number">200</span>));</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; k; ++i) &#123;</span><br><span class="line">            cout &lt;&lt; i &lt;&lt; <span class="string">&quot; &quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        cout &lt;&lt; endl;</span><br><span class="line">        timed_mutex_.<span class="built_in">unlock</span>();</span><br><span class="line">    &#125;;</span><br><span class="line">    std::thread threads[<span class="number">5</span>];</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; ++i) &#123;</span><br><span class="line">        threads[i] = std::<span class="built_in">thread</span>(func1, <span class="number">200</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">auto</span>&amp; th : threads) &#123;</span><br><span class="line">        th.<span class="built_in">join</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="std-lock相关"><a href="#std-lock相关" class="headerlink" title="std::lock相关"></a>std::lock相关</h2><p>这里主要介绍两种RAII方式的锁封装，可以动态的释放锁资源，防止线程由于编码失误导致一直持有锁。</p><p>c++11主要有std::lock_guard和std::unique_lock两种方式，使用方式都类似，如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;iostream&gt;</span><br><span class="line">#include &lt;mutex&gt;</span><br><span class="line">#include &lt;thread&gt;</span><br><span class="line">#include &lt;chrono&gt;</span><br><span class="line"></span><br><span class="line">using namespace std;</span><br><span class="line">std::mutex mutex_;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    auto func1 = [](int k) &#123;</span><br><span class="line">        // std::lock_guard&lt;std::mutex&gt; lock(mutex_);</span><br><span class="line">        std::unique_lock&lt;std::mutex&gt; lock(mutex_);</span><br><span class="line">        for (int i = 0; i &lt; k; ++i) &#123;</span><br><span class="line">            cout &lt;&lt; i &lt;&lt; &quot; &quot;;</span><br><span class="line">        &#125;</span><br><span class="line">        cout &lt;&lt; endl;</span><br><span class="line">    &#125;;</span><br><span class="line">    std::thread threads[5];</span><br><span class="line">    for (int i = 0; i &lt; 5; ++i) &#123;</span><br><span class="line">        threads[i] = std::thread(func1, 200);</span><br><span class="line">    &#125;</span><br><span class="line">    for (auto&amp; th : threads) &#123;</span><br><span class="line">        th.join();</span><br><span class="line">    &#125;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>std::lock_guard</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;mutex&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">Mutex</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">lock_guard</span>;</span><br></pre></td></tr></table></figure><p><code>Mutex</code> 是互斥量的类型。</p><p>使用 <code>std::lock_guard</code> 时，只需在需要保护的代码块中创建一个 <code>std::lock_guard</code> 对象，并将需要保护的互斥量传递给它的构造函数。当 <code>std::lock_guard</code> 对象创建时，会自动锁定互斥量，当对象销毁时，会自动解锁互斥量。</p><p><strong>std::unique_lock</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;mutex&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">Mutex</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">unique_lock</span>;</span><br></pre></td></tr></table></figure><p><code>Mutex</code> 是互斥量的类型。</p><p>与 <code>std::lock_guard</code> 不同，<code>std::unique_lock</code> 对象可以在构造时不锁定互斥量，并且可以在后续的代码中手动锁定或解锁。此外，<code>std::unique_lock</code> 还提供了更多的功能，如可延迟锁定、条件变量的支持等。</p><h2 id="std-atomic"><a href="#std-atomic" class="headerlink" title="std::atomic"></a>std::atomic</h2><p>c++11提供了原子类型std::atomic，理论上这个T可以是任意类型，但是我平时只存放整形，别的还真的没用过，整形有这种原子变量已经足够方便，就不需要使用std::mutex来保护该变量啦。看一个计数器的代码：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">OriginCounter</span> &#123; <span class="comment">// 普通的计数器</span></span><br><span class="line">    <span class="type">int</span> count;</span><br><span class="line">    std::mutex mutex_;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">add</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="function">std::lock_guard&lt;std::mutex&gt; <span class="title">lock</span><span class="params">(mutex_)</span></span>;</span><br><span class="line">        ++count;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">sub</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="function">std::lock_guard&lt;std::mutex&gt; <span class="title">lock</span><span class="params">(mutex_)</span></span>;</span><br><span class="line">        --count;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">get</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="function">std::lock_guard&lt;std::mutex&gt; <span class="title">lock</span><span class="params">(mutex_)</span></span>;</span><br><span class="line">        <span class="keyword">return</span> count;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">struct</span> <span class="title class_">NewCounter</span> &#123; <span class="comment">// 使用原子变量的计数器</span></span><br><span class="line">    std::atomic&lt;<span class="type">int</span>&gt; count;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">add</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        ++count;</span><br><span class="line">        <span class="comment">// count.store(++count);这种方式也可以</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">sub</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        --count;</span><br><span class="line">        <span class="comment">// count.store(--count);</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">get</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> count.<span class="built_in">load</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="std-call-once"><a href="#std-call-once" class="headerlink" title="std::call_once"></a>std::call_once</h2><p>c++11提供了std::call_once来保证某一函数在多线程环境中只调用一次，它需要配合std::once_flag使用，直接看使用代码吧：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">std::once_flag onceflag;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">CallOnce</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    std::<span class="built_in">call_once</span>(onceflag, []() &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;call once&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    std::thread threads[<span class="number">5</span>];</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; ++i) &#123;</span><br><span class="line">        threads[i] = std::<span class="built_in">thread</span>(CallOnce);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">auto</span>&amp; th : threads) &#123;</span><br><span class="line">        th.<span class="built_in">join</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="volatile"><a href="#volatile" class="headerlink" title="volatile"></a>volatile</h2><p>volatile通常用来建立内存屏障，volatile修饰的变量，编译器对访问该变量的代码通常不再进行优化，看下面代码：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> *p = xxx;</span><br><span class="line"><span class="type">int</span> a = *p;</span><br><span class="line"><span class="type">int</span> b = *p;</span><br></pre></td></tr></table></figure><p>a和b都等于p指向的值，一般编译器会对此做优化，把*p的放入寄存器，之后a,b都等于寄存器的值，但是如果把中间p地址的值改变，内存值改变了，但a,b还是从寄存器中取的值(不一定，看编译器的优化结果),这不符合需求，所以对p加上<strong>volatile</strong>修饰可以避免此类优化.</p><p>注意：volatile不能解决多线程安全问题，针对特种内存才需要使用volatile，它和atomic的特点如下：</p><ul><li>std::atomic用于多线程访问的数据，且不用互斥量，用于并发编程中</li><li>volatile用于读写操作不可以被优化掉的内存，用于特种内存中</li></ul><h2 id="std-condition-variable"><a href="#std-condition-variable" class="headerlink" title="std::condition_variable"></a>std::condition_variable</h2><p>条件变量是c++11引入的一种同步机制，它可以阻塞一个线程或者个线程，直到有线程通知或者超时才会唤醒正在阻塞的线程，条件变量需要和锁配合使用，这里的锁就是上面介绍的std::unique_lock。</p><p><a href="https://en.cppreference.com/w/cpp/thread/condition_variable">成员函数</a></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CountDownLatch</span> &#123;</span><br><span class="line">   <span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">explicit</span> <span class="title">CountDownLatch</span><span class="params">(<span class="type">uint32_t</span> count)</span> : count_(count);</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">CountDown</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="function">std::unique_lock&lt;std::mutex&gt; <span class="title">lock</span><span class="params">(mutex_)</span></span>;</span><br><span class="line">        --count_;</span><br><span class="line">        <span class="keyword">if</span> (count_ == <span class="number">0</span>) &#123;</span><br><span class="line">            cv_.<span class="built_in">notify_all</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">Await</span><span class="params">(<span class="type">uint32_t</span> time_ms = <span class="number">0</span>)</span> </span>&#123;</span><br><span class="line">        <span class="function">std::unique_lock&lt;std::mutex&gt; <span class="title">lock</span><span class="params">(mutex_)</span></span>;</span><br><span class="line">        <span class="keyword">while</span> (count_ &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (time_ms &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                cv_.<span class="built_in">wait_for</span>(lock, std::chrono::<span class="built_in">milliseconds</span>(time_ms));</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                cv_.<span class="built_in">wait</span>(lock);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="type">uint32_t</span> <span class="title">GetCount</span><span class="params">()</span> <span class="type">const</span> </span>&#123;</span><br><span class="line">        <span class="function">std::unique_lock&lt;std::mutex&gt; <span class="title">lock</span><span class="params">(mutex_)</span></span>;</span><br><span class="line">          <span class="keyword">return</span> count_; </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">private</span>:</span><br><span class="line">    std::condition_variable cv_;</span><br><span class="line">    <span class="keyword">mutable</span> std::mutex mutex_;</span><br><span class="line">    <span class="type">uint32_t</span> count_ = <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ul><li><p><code>notify_one</code></p><ul><li>通知一个线程等待</li></ul></li><li><p><code>notify_all</code></p><ul><li>通知所有线程等待</li></ul></li><li><p><code>wait</code></p><ul><li>阻塞当前线程，直到条件变量被唤醒</li></ul></li><li><p><code>wait_for</code></p><ul><li>阻塞当前线程，知道条件变量被唤醒或指定的超时时间后</li></ul></li><li><p><code>wait_until</code></p><ul><li>阻塞当前线程，直到条件变量被唤醒或到达指定时间点</li></ul></li></ul><h2 id="std-future"><a href="#std-future" class="headerlink" title="std::future"></a>std::future</h2><p>c++11关于异步操作提供了future相关的类，主要有std::future、std::promise和std::packaged_task，std::future比std::thread高级些，std::future作为异步结果的传输通道，通过get()可以很方便的获取线程函数的返回值，std::promise用来包装一个值，将数据和future绑定起来，而std::packaged_task则用来包装一个调用对象，将函数和future绑定起来，方便异步调用。而std::future是不可以复制的，如果需要复制放到容器中可以使用std::shared_future。</p><p><strong>std::promise与std::future配合使用</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;future&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;thread&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">(std::future&lt;<span class="type">int</span>&gt;&amp; fut)</span> </span>&#123;</span><br><span class="line">    <span class="type">int</span> x = fut.<span class="built_in">get</span>();</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;value: &quot;</span> &lt;&lt; x &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    std::promise&lt;<span class="type">int</span>&gt; prom;</span><br><span class="line">    std::future&lt;<span class="type">int</span>&gt; fut = prom.<span class="built_in">get_future</span>();</span><br><span class="line">    <span class="function">std::thread <span class="title">t</span><span class="params">(func, std::ref(fut))</span></span>;</span><br><span class="line">    prom.<span class="built_in">set_value</span>(<span class="number">144</span>);</span><br><span class="line">    t.<span class="built_in">join</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>std::packaged_task与std::future配合使用</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;future&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;thread&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">func</span><span class="params">(<span class="type">int</span> in)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> in + <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="function">std::packaged_task&lt;<span class="title">int</span><span class="params">(<span class="type">int</span>)</span>&gt; <span class="title">task</span><span class="params">(func)</span></span>;</span><br><span class="line">    std::future&lt;<span class="type">int</span>&gt; fut = task.<span class="built_in">get_future</span>();</span><br><span class="line">    std::<span class="built_in">thread</span>(std::<span class="built_in">move</span>(task), <span class="number">5</span>).<span class="built_in">detach</span>();</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;result &quot;</span> &lt;&lt; fut.<span class="built_in">get</span>() &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>std::future用于访问异步操作的结果，而std::promise和std::packaged_task在future高一层，它们内部都有一个future，promise包装的是一个值，packaged_task包装的是一个函数，当需要获取线程中的某个值，可以使用std::promise，当需要获取线程函数返回值，可以使用std::packaged_task。</p><h2 id="async"><a href="#async" class="headerlink" title="async"></a>async</h2><p>async是比future，packaged_task，promise更高级的东西，它是基于任务的异步操作，通过async可以直接创建异步的任务，返回的结果会保存在future中，不需要像packaged_task和promise那么麻烦，关于线程操作应该优先使用async，看一段使用代码：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;functional&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;future&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;thread&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">func</span><span class="params">(<span class="type">int</span> in)</span> </span>&#123; <span class="keyword">return</span> in + <span class="number">1</span>; &#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">auto</span> res = std::<span class="built_in">async</span>(func, <span class="number">5</span>);</span><br><span class="line">    <span class="comment">// res.wait();</span></span><br><span class="line">    cout &lt;&lt; res.<span class="built_in">get</span>() &lt;&lt; endl; <span class="comment">// 阻塞直到函数返回</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>async具体语法如下：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">async(std::launch::async | std::launch::deferred, func, args...);</span><br></pre></td></tr></table></figure><p>第一个参数是创建策略：</p><ul><li>std::launch::async表示任务执行在另一线程</li><li>std::launch::deferred表示延迟执行任务，调用get或者wait时才会执行，不会创建线程，惰性执行在当前线程。</li></ul><p>如果不明确指定创建策略，以上两个都不是async的默认策略，而是未定义，它是一个基于任务的程序设计，内部有一个调度器(线程池)，会根据实际情况决定采用哪种策略。</p><p>若从 std::async 获得的 std::future 未被移动或绑定到引用，则在完整表达式结尾， std::future的析构函数将阻塞直至异步计算完成，实际上相当于同步操作：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">std::<span class="built_in">async</span>(std::launch::async, []&#123; <span class="built_in">f</span>(); &#125;); <span class="comment">// 临时量的析构函数等待 f()</span></span><br><span class="line">std::<span class="built_in">async</span>(std::launch::async, []&#123; <span class="built_in">g</span>(); &#125;); <span class="comment">// f() 完成前不开始</span></span><br></pre></td></tr></table></figure><p><code>注意</code>：关于async启动策略这里网上和各种书籍介绍的五花八门，这里会以cppreference为主。</p><p>有时候我们如果想真正执行异步操作可以对async进行封装，强制使用std::launch::async策略来调用async。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> F, <span class="keyword">typename</span>... Args&gt;</span><br><span class="line"><span class="function"><span class="keyword">inline</span> <span class="keyword">auto</span> <span class="title">ReallyAsync</span><span class="params">(F&amp;&amp; f, Args&amp;&amp;... params)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> std::<span class="built_in">async</span>(std::launch::async, std::forward&lt;F&gt;(f), std::forward&lt;Args&gt;(params)...);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><a href="https://zhuanlan.zhihu.com/p/137914574">原文章</a></p><p><a href="https://zhuanlan.zhihu.com/p/638684473">补充</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;C-11线程特性&quot;&gt;&lt;a href=&quot;#C-11线程特性&quot; class=&quot;headerlink&quot; title=&quot;C++11线程特性&quot;&gt;&lt;/a&gt;C++11线程特性&lt;/h1&gt;&lt;h2 id=&quot;std-thread&quot;&gt;&lt;a href=&quot;#std-thread&quot; class</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    
    <category term="notes" scheme="https://future.thisis.host/tags/notes/"/>
    
    <category term="thread" scheme="https://future.thisis.host/tags/thread/"/>
    
    <category term="c++" scheme="https://future.thisis.host/tags/c/"/>
    
  </entry>
  
  <entry>
    <title>shell 笔记</title>
    <link href="https://future.thisis.host/2024/03/29/shell/"/>
    <id>https://future.thisis.host/2024/03/29/shell/</id>
    <published>2024-03-29T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.356Z</updated>
    
    <content type="html"><![CDATA[<h1 id="shell"><a href="#shell" class="headerlink" title="shell"></a>shell</h1><h2 id="主函数"><a href="#主函数" class="headerlink" title="主函数"></a>主函数</h2><ul><li>先创建一个Shell类型的类</li><li>然后屏蔽信号ctrl+c与ctrl+D</li><li>接着打印提示符，接收命令的输入</li><li>判断该次命令是否含有<code>exit</code> <code>clear</code> <code>!</code>等信息，如果有，执行相应操作</li><li>通过调用解析函数解析本次输入的命令</li></ul><h2 id="屏蔽信号"><a href="#屏蔽信号" class="headerlink" title="屏蔽信号"></a>屏蔽信号</h2><ul><li><p>ctrl  +  C</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">signal</span>(SIGINT, SIG_IGN);<span class="comment">//将该信号的处理方式设置为忽略</span></span><br></pre></td></tr></table></figure></li><li><p>ctrl  +  D</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">struct</span> <span class="title class_">termios</span> term;</span><br><span class="line">   <span class="built_in">tcgetattr</span>(STDIN_FILENO, &amp;term);</span><br><span class="line">   term.c_cc[VEOF] = _POSIX_VDISABLE;</span><br><span class="line">   <span class="built_in">tcsetattr</span>(STDIN_FILENO, TCSANOW, &amp;term);</span><br></pre></td></tr></table></figure></li></ul><blockquote><p>首先定义一个termios类型的结构体，用来存储终端相关的属性信息</p><p>然后通过调用tcgetattr函数将获取终端的相关属性，并将这些属性保存到 **term **结构体中，第一个参数表示标准输入，是一个预定的文件描述符常量</p><p>将结构体中的c_cc数组成员的VEOF设置为禁用. c_cc数组是包含终端特殊字符的数组，VEOF是其中的一个索引，第二个参数是一个特殊的宏，用于禁用该特殊字符</p><p>最后，<code>tcsetattr(STDIN_FILENO, TCSANOW, &amp;term);</code>调用<code>tcsetattr()</code>函数，它用于设置终端的属性。<code>STDIN_FILENO</code>表示标准输入文件描述符，<code>TCSANOW</code>表示立即生效的选项，<code>&amp;term</code>是要设置的终端属性结构体。</p></blockquote><h3 id="tcgetattr"><a href="#tcgetattr" class="headerlink" title="tcgetattr"></a>tcgetattr</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">tcgetattr</span><span class="params">(<span class="type">int</span> fd, <span class="keyword">struct</span> termios *termios_p)</span></span>;</span><br></pre></td></tr></table></figure><p>参数说明：</p><ul><li><p><code>fd</code> 是一个打开的终端设备文件描述符。</p></li><li><p><code>termios_p</code> 是一个指向 <code>termios</code> 结构体的指针，用于存储获取</p><p>到的终端属性。</p></li></ul><p><code>tcgetattr</code> 函数返回一个整数值，表示函数调用的成功与否。如果函数成功执行，返回值为0；如果出现错误，返回值为-1，并设置相应的错误码。在调用该函数时，你需要检查返回值以确保函数调用是否成功。</p><h3 id="tcsetattr"><a href="#tcsetattr" class="headerlink" title="tcsetattr"></a>tcsetattr</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">tcsetattr</span><span class="params">(<span class="type">int</span> fd, <span class="type">int</span> optional_actions, <span class="type">const</span> <span class="keyword">struct</span> termios *termios_p)</span></span>;</span><br></pre></td></tr></table></figure><p>参数说明：</p><ul><li><code>fd</code> 是一个打开的终端设备文件描述符。</li><li><code>optional_actions</code> 是一个表示操作选项的整数值，用于指定何时应用属性的更改。</li><li><code>termios_p</code> 是一个指向 <code>termios</code> 结构体的指针，其中包含了要应用的终端属性。</li></ul><p><code>optional_actions</code> 参数用于指定何时应用属性的更改，它可以取以下三个值之一：</p><ul><li><code>TCSANOW</code>：立即更改属性。</li><li><code>TCSADRAIN</code>：在所有输出都被传输后更改属性。</li><li><code>TCSAFLUSH</code>：在所有输出都被传输后更改属性，并丢弃所有未读的输入。</li></ul><h2 id="print"><a href="#print" class="headerlink" title="print"></a>print</h2><p><strong>getlogin</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">char</span>* <span class="title">getlogin</span><span class="params">(<span class="type">void</span>)</span></span></span><br><span class="line"><span class="function"><span class="comment">//返回一个指向当前登陆用户的用户名的字符串指针</span></span></span><br></pre></td></tr></table></figure><p><strong>strcspn</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">size_t</span> <span class="title">strscpn</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *str1,<span class="type">const</span> <span class="type">char</span> *str2)</span></span>;</span><br><span class="line"><span class="comment">//str1：要搜索的字符串</span></span><br><span class="line"><span class="comment">//str2：要查找的字符集合</span></span><br><span class="line"><span class="comment">//计算字符串中连续不包含指定字符集合的最大前缀长度。</span></span><br></pre></td></tr></table></figure><p><strong>strftime</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">size_t</span> <span class="title">strftime</span><span class="params">(<span class="type">char</span> *str, <span class="type">size_t</span> maxsize, <span class="type">const</span> <span class="type">char</span> *format, <span class="type">const</span> <span class="keyword">struct</span> tm *timeptr)</span></span>;</span><br></pre></td></tr></table></figure><p>参数说明：</p><ul><li><code>str</code> 是一个指向字符数组的指针，用于存储格式化后的时间字符串。</li><li><code>maxsize</code> 是 <code>str</code> 所指向的字符数组的最大容量。</li><li><code>format</code> 是一个格式字符串，用于定义输出的时间格式。</li><li><code>timeptr</code> 是一个指向 <code>struct tm</code> 结构体的指针，其中包含要格式化的时间和日期。</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">chrono::system_clock::<span class="built_in">now</span>();</span><br><span class="line"><span class="comment">//是c++&lt;chrono&gt;头文件中的一个函数调用，用于获取当前的系统时间点</span></span><br><span class="line">chrono::system_clock::<span class="type">to_time_t</span></span><br><span class="line"><span class="comment">//是一个函数模板，将time_point对象转换为time_t的类型</span></span><br></pre></td></tr></table></figure><h2 id="mycd"><a href="#mycd" class="headerlink" title="mycd"></a>mycd</h2><p><strong>getenv</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">char</span>* <span class="title">getenv</span><span class="params">(<span class="type">const</span> <span class="type">char</span>* name)</span></span>;</span><br></pre></td></tr></table></figure><p>参数说明:</p><ul><li>name是一个指向以null结尾的字符串，表示要获取的环境变量的名称.</li></ul><p>根据指定的环境变量的名称，返回对应的环境变量的值。找到则返回一个null结尾的字符串，表示该环境变量的值.否则返回null.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">const</span> <span class="type">char</span>* path = s[<span class="number">1</span>].<span class="built_in">c_str</span>();</span><br><span class="line"><span class="comment">//将string对象转换为c风格的字符串.</span></span><br></pre></td></tr></table></figure><blockquote><p>需要注意的是c_str()返回的指针指向的仍为string内部存储的字符数组，因此需要确保在使用path指针时，string对象仍然有效</p></blockquote><p><strong>get_current_dir_name</strong></p><p>是一个标准的POSIX函数，用于获取当前工作目录的路径</p><p>由于get_current_dir_name( )分配了动态内存，因此使用完毕后需要调用free( )。</p><p><strong>setenv</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">setenv</span><span class="params">(<span class="type">const</span> <span class="type">char</span>* name, <span class="type">const</span> <span class="type">char</span>* value, <span class="type">int</span> overwrite)</span></span>;</span><br></pre></td></tr></table></figure><p>参数说明：</p><ul><li><code>name</code> 是一个指向以 null 结尾的字符串，表示要设置或新建的环境变量的名称。</li><li><code>value</code> 是一个指向以 null 结尾的字符串，表示要设置的环境变量的值。</li><li><code>overwrite</code> 是一个整数值，指示在环境变量已经存在时是否进行覆盖。如果 <code>overwrite</code> 为非零值，则会覆盖现有环境变量；如果 <code>overwrite</code> 为零，则不进行覆盖。</li></ul><h2 id="parse"><a href="#parse" class="headerlink" title="parse"></a>parse</h2><p><code>istringstream</code>是C++标准库中的一个类，他是用于从字符串中进行输入操作的输入流类.</p><p><strong>getline()</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">std::istream&amp; <span class="title">getline</span><span class="params">(std::istream&amp; is, std::string&amp; str, <span class="type">char</span> delim)</span></span>;</span><br></pre></td></tr></table></figure><p>参数说明：</p><ul><li><code>is</code> 是一个输入流对象，表示要从中读取文本的输入流，通常是 <code>std::cin</code>（标准输入）或文件流对象。</li><li><code>str</code> 是一个字符串对象的引用，表示读取的文本将存储在其中。</li><li><code>delim</code> 是一个字符（默认为换行符 <code>\n</code>），表示行的结束符。</li></ul><h3 id="pipe"><a href="#pipe" class="headerlink" title="pipe"></a>pipe</h3><p>“pipe”（管道）是一种在进程间进行通信的机制。它允许一个进程的输出直接成为另一个进程的输入，从而实现进程间的数据传输。</p><ol><li>匿名管道：<ul><li>匿名管道是最常见的管道类型。它是一种单向通信管道，只能在具有父子关系的进程之间使用。父进程创建管道后，可以通过文件描述符进行读取或写入。子进程继承了父进程的文件描述符，从而可以使用相反的操作进行读取或写入。</li><li>匿名管道是一种半双工通信方式，即数据只能在一个方向上流动。如果需要双向通信，需要创建两个匿名管道。</li><li>使用匿名管道的典型流程是：父进程创建管道，然后调用 <code>fork()</code> 创建子进程。父进程关闭不需要的管道端口，子进程关闭另一个不需要的端口。然后父进程可以向管道写入数据，子进程可以从管道读取数据。</li></ul></li><li>命名管道：<ul><li>命名管道也称为FIFO（First-In-First-Out），它提供了一种无关进程关系的进程间通信方式。命名管道在文件系统中有一个与之相关联的路径名，多个进程可以通过这个路径名来进行通信。</li><li>命名管道是一种半双工通信方式，类似于匿名管道，只能在一个方向上流动数据。</li><li>命名管道可以使用 <code>mkfifo</code> 函数创建，也可以使用命令行工具 <code>mkfifo</code> 创建。</li></ul></li></ol><p>管道的使用可以通过系统调用函数来实现，例如 POSIX 标准中的 <code>pipe()</code> 函数。在使用管道时，重要的是要了解管道的读取和写入端口以及数据的流动方向，以确保正确的通信。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">pipe</span><span class="params">(<span class="type">int</span> pipefd[<span class="number">2</span>])</span></span>;</span><br></pre></td></tr></table></figure><blockquote><p><code>pipe()</code> 函数接受一个整型数组 <code>pipefd[2]</code>，用于存储管道的文件描述符。<code>pipefd[0]</code> 表示管道的读取端口，<code>pipefd[1]</code> 表示管道的写入端口。该函数返回值为 0 表示成功，-1 表示失败。</p><p>以下是 <code>pipe()</code> 函数的详细解释：</p><ul><li><code>pipefd</code> 参数是一个包含两个元素的整型数组，用于存储管道的文件描述符。<code>pipefd[0]</code> 是管道的读取端口，用于从管道中读取数据；<code>pipefd[1]</code> 是管道的写入端口，用于向管道中写入数据。</li><li><code>pipe()</code> 函数创建一个匿名管道，并将管道的读取端口和写入端口的文件描述符填充到 <code>pipefd</code> 数组中。</li><li>匿名管道是一种半双工通信方式，数据只能在一个方向上流动。如果需要双向通信，需要创建两个匿名管道。</li><li>管道是内核中的一个缓冲区，用于在相关进程之间传输数据。数据写入管道后，可以从管道的读取端口读取。</li><li>管道的大小是有限的，一旦管道的缓冲区满了，进程写入数据时可能会被阻塞，直到有足够的空间来容纳数据。同样，如果管道为空，从管道读取数据时可能会被阻塞，直到有数据可读。</li><li>如果一个进程关闭了管道的读取端口，而另一个进程关闭了管道的写入端口，这两个进程之间的管道通信将结束。</li></ul></blockquote><h3 id="dup2"><a href="#dup2" class="headerlink" title="dup2"></a>dup2</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">dup2</span><span class="params">(<span class="type">int</span> oldfd, <span class="type">int</span> newfd)</span></span>;</span><br></pre></td></tr></table></figure><blockquote><ul><li><code>oldfd</code> 参数是需要复制的文件描述符。它可以是任何有效的文件描述符，包括标准输入（0）、标准输出（1）和标准错误（2）。</li><li><code>newfd</code> 参数是要复制到的新文件描述符。如果 <code>newfd</code> 已经打开，则会先关闭它，然后将 <code>oldfd</code> 复制到 <code>newfd</code>。</li><li>复制后，<code>newfd</code> 将和 <code>oldfd</code> 指向相同的文件表项，它们共享同一个文件偏移量和文件状态标志。</li><li>如果 <code>newfd</code> 等于 <code>oldfd</code>，则 <code>dup2()</code> 函数不进行任何操作，直接返回 <code>newfd</code>。</li><li><code>dup2()</code> 函数的一个常见用途是重定向标准输入、标准输出和标准错误。例如，可以将标准输出重定向到一个文件，或者将标准错误重定向到一个套接字。</li></ul></blockquote><h2 id="executeCommand"><a href="#executeCommand" class="headerlink" title="executeCommand"></a>executeCommand</h2><p><strong>open</strong></p><ul><li><code>command[i + 1].c_str()</code>：<code>command</code>是一个字符串向量，<code>command[i + 1]</code>表示该向量中的第<code>i + 1</code>个元素。<code>.c_str()</code>将该元素转换为C风格的字符串，以便与<code>open()</code>函数的参数类型匹配。这个参数是要打开的文件的路径。</li><li><code>O_WRONLY</code>：是<code>open()</code>函数的一个打开模式，表示以只写方式打开文件。这意味着你可以向文件写入数据，但不能读取文件的内容。</li><li><code>O_CREAT</code>：是<code>open()</code>函数的一个打开模式，表示如果文件不存在，则创建该文件。如果文件已经存在，<code>open()</code>函数仍然会成功打开文件。</li><li><code>O_TRUNC</code>：是<code>open()</code>函数的一个打开模式，表示如果文件已经存在且以只写方式打开，那么在打开文件时将截断文件的长度为0。这意味着打开文件后，文件中已经存在的内容将被清空。</li><li><code>0644</code>：表示文件的权限。在这里，<code>0644</code>表示文件所有者具有读和写的权限，而其他用户只有读的权限。它是一个八进制数，其中第一个数字<code>0</code>表示这是一个八进制数，后面的三个数字分别表示文件所有者、文件所属组和其他用户的权限。</li></ul><h1 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h1><h2 id="shepp-hpp"><a href="#shepp-hpp" class="headerlink" title="shepp.hpp"></a>shepp.hpp</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;iostream&gt;</span><br><span class="line">using namespace std;</span><br><span class="line">#include &lt;string&gt;</span><br><span class="line">#include &lt;vector&gt;</span><br><span class="line">#include &lt;sstream&gt;</span><br><span class="line">#include &lt;chrono&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;csignal&gt;</span><br><span class="line">#include &lt;algorithm&gt;</span><br><span class="line">#include &lt;termios.h&gt;</span><br><span class="line">#include &lt;cstdlib&gt;</span><br><span class="line">#include &lt;wait.h&gt;</span><br><span class="line">#include &lt;fstream&gt;</span><br><span class="line">#include &lt;sys/stat.h&gt;</span><br><span class="line">#include &lt;fcntl.h&gt;</span><br><span class="line"></span><br><span class="line">class Shell</span><br><span class="line">&#123;</span><br><span class="line">public:</span><br><span class="line">    void print();</span><br><span class="line">    void setlinebuf();</span><br><span class="line">    string retlinebuf();</span><br><span class="line">    void setsignal();</span><br><span class="line">    bool isempty();</span><br><span class="line">    void addHistory(const string&amp; line);</span><br><span class="line">    void setEOF();</span><br><span class="line">    void printHistory();</span><br><span class="line">    void searchAndReplay(const string &amp;keyword);</span><br><span class="line">    void mycd(vector&lt;string&gt; &amp;s);</span><br><span class="line">    void executeCommand(const vector&lt;string&gt; &amp;command);</span><br><span class="line">    void parse(string &amp;s);</span><br><span class="line">private:</span><br><span class="line">    string linebuf;</span><br><span class="line">    vector&lt;string&gt; history;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="func-cpp"><a href="#func-cpp" class="headerlink" title="func.cpp"></a>func.cpp</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;shell.hpp&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Shell::print</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;   cout &lt;&lt; <span class="string">&quot;----------------------------------------------------------------------------&quot;</span> &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;           ___                                                     ___&quot;</span> &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;  ______  /  /___       ______  _____  ___   ___       ____  _____/  /___&quot;</span> &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot; /  __  \\/  __   \\     /  ___ - ___  \\/  /  /  /     /_   / /  __/  __   \\&quot;</span> &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;/  /_/  /  /  /  /    /  /  /  /  /  /  /__/  /       /  /_(__  )  /  /  /&quot;</span> &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;\\______/__/  /__/    /__/  /__/  /__/\\____,  /       /____/____/__/  /__/&quot;</span> &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;                                    /_______/&quot;</span> &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;----------------------------------------------------------------------------&quot;</span> &lt;&lt; endl;</span><br><span class="line">    <span class="type">char</span> cwd [<span class="number">1024</span>];</span><br><span class="line">    <span class="keyword">auto</span> now = chrono::system_clock::<span class="built_in">now</span>();<span class="comment">//返回当前的时间</span></span><br><span class="line">    <span class="type">time_t</span> time = chrono::system_clock::<span class="built_in">to_time_t</span>(now);<span class="comment">//将time_t point转换为time_t类型</span></span><br><span class="line">    tm* timeinfo = std::<span class="built_in">localtime</span>(&amp;time);<span class="comment">//将time_t转换为本地时间年月日,并存储在timeinfo中</span></span><br><span class="line">    <span class="type">char</span> timeStr[<span class="number">9</span>];</span><br><span class="line">    <span class="built_in">strftime</span>(timeStr, <span class="built_in">sizeof</span>(timeStr), <span class="string">&quot;%H:%M:%S&quot;</span>, timeinfo);</span><br><span class="line">    <span class="comment">//std::strftime()将std::tm结构的时间信息格式化为字符串，并将结果存储在指定的字符数组中。这里使用&quot;%H:%M:%S&quot;作为格式字符串</span></span><br><span class="line">    <span class="comment">//，它表示小时、分钟和秒的格式。timeStr是目标字符数组，sizeof(timeStr)用于指定数组的大小，</span></span><br><span class="line">    <span class="comment">//timeinfo是包含时间信息的std::tm结构的指针。</span></span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;# future @ future-arch in &quot;</span> &lt;&lt; <span class="built_in">getcwd</span>(cwd,<span class="number">1024</span>) &lt;&lt; <span class="string">&quot; [&quot;</span> &lt;&lt; timeStr &lt;&lt; <span class="string">&quot;]&quot;</span> &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;$ &quot;</span> ;</span><br><span class="line">    <span class="built_in">fflush</span>(stdout);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> Shell ::<span class="built_in">setlinebuf</span>()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">getline</span>(cin,<span class="keyword">this</span>-&gt;linebuf);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function">string <span class="title">Shell::retlinebuf</span> <span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>-&gt;linebuf;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> Shell:: <span class="built_in">setsignal</span>()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">signal</span>(SIGINT, SIG_IGN);<span class="comment">//忽略ctrl+c的操作</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">bool</span> Shell ::<span class="built_in">isempty</span>() </span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">this</span>-&gt;linebuf.<span class="built_in">empty</span>())</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Shell::addHistory</span><span class="params">(<span class="type">const</span> string&amp; line)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">for</span>(vector&lt;string&gt;::iterator it = history.<span class="built_in">begin</span>(); it != history.<span class="built_in">end</span>();it++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>((*it).<span class="built_in">compare</span>(line) == <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">return</span> ;</span><br><span class="line">    &#125;</span><br><span class="line">    history.<span class="built_in">push_back</span>(line);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> Shell ::<span class="built_in">setEOF</span>()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">struct</span> <span class="title class_">termios</span> term;<span class="comment">//存储终端的相关信息</span></span><br><span class="line">    <span class="built_in">tcgetattr</span>(STDIN_FILENO, &amp;term);<span class="comment">//获取相关信息，并存入结构体</span></span><br><span class="line">    term.c_cc[VEOF] = _POSIX_VDISABLE;<span class="comment">//禁止使用EOF</span></span><br><span class="line">    <span class="built_in">tcsetattr</span>(STDIN_FILENO, TCSANOW, &amp;term);<span class="comment">//将设置存入终端</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Shell::printHistory</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">for</span>(vector&lt;string&gt;::iterator it = <span class="keyword">this</span>-&gt;history.<span class="built_in">begin</span>(); it != <span class="keyword">this</span>-&gt;history.<span class="built_in">end</span>();it++)</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; *it &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~&quot;</span>&lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Shell::searchAndReplay</span><span class="params">(<span class="type">const</span> string&amp; keyword)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">const</span> string&amp; line : history)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (line.<span class="built_in">find</span>(keyword) != string::npos)</span><br><span class="line">        &#123;</span><br><span class="line">            cout &lt;&lt; <span class="string">&quot;Replaying: &quot;</span> &lt;&lt; line &lt;&lt; endl;</span><br><span class="line">            linebuf = line;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Shell::parse</span><span class="params">(string&amp; s)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    vector&lt;vector&lt;string&gt;&gt; tokens;</span><br><span class="line">    <span class="function">istringstream <span class="title">iss</span><span class="params">(s)</span></span>;<span class="comment">//可方便的从字符串中读取数据</span></span><br><span class="line">    string root;</span><br><span class="line">    <span class="keyword">while</span> (<span class="built_in">getline</span>(iss, root, <span class="string">&#x27;|&#x27;</span>))<span class="comment">//将s以|分割开</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="function">istringstream <span class="title">root_iss</span><span class="params">(root)</span></span>;</span><br><span class="line">        vector&lt;string&gt; root_tokens;</span><br><span class="line">        string token;</span><br><span class="line">        <span class="keyword">while</span> (root_iss &gt;&gt; token)<span class="comment">//将单个命令以空格分隔开</span></span><br><span class="line">        &#123;</span><br><span class="line">            root_tokens.<span class="built_in">push_back</span>(token);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        tokens.<span class="built_in">push_back</span>(root_tokens);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (tokens.<span class="built_in">size</span>() == <span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        vector&lt;string&gt;&amp; command = tokens[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">if</span> (command[<span class="number">0</span>] == <span class="string">&quot;cd&quot;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">mycd</span>(command);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">executeCommand</span>(command);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (tokens.<span class="built_in">size</span>() &gt; <span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">int</span> numPipes = tokens.<span class="built_in">size</span>() - <span class="number">1</span>;</span><br><span class="line">        <span class="function">vector&lt;<span class="type">int</span>&gt; <span class="title">pipefds</span><span class="params">(<span class="number">2</span> * numPipes, <span class="number">0</span>)</span></span>; <span class="comment">// 用于存储管道的文件描述符</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; numPipes; ++i)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="built_in">pipe</span>(pipefds.<span class="built_in">data</span>() + i * <span class="number">2</span>) &lt; <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">perror</span>(<span class="string">&quot;pipe()&quot;</span>);</span><br><span class="line">                <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">int</span> commandIndex = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">auto</span>&amp; command : tokens)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="type">pid_t</span> pid = fork();</span><br><span class="line">            <span class="keyword">if</span> (pid &lt; <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">perror</span>(<span class="string">&quot;fork()&quot;</span>);</span><br><span class="line">                <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (pid == <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="comment">// 子进程</span></span><br><span class="line">                <span class="keyword">if</span> (commandIndex != <span class="number">0</span>) <span class="comment">// 不是第一个命令，读取前一个管道的输出</span></span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="keyword">if</span> (<span class="built_in">dup2</span>(pipefds[(commandIndex - <span class="number">1</span>) * <span class="number">2</span>], STDIN_FILENO) &lt; <span class="number">0</span>)</span><br><span class="line">                    &#123;</span><br><span class="line">                        <span class="built_in">perror</span>(<span class="string">&quot;dup2()&quot;</span>);</span><br><span class="line">                        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (commandIndex != numPipes) <span class="comment">// 不是最后一个命令，将输出写入下一个管道</span></span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="keyword">if</span> (<span class="built_in">dup2</span>(pipefds[commandIndex * <span class="number">2</span> + <span class="number">1</span>], STDOUT_FILENO) &lt; <span class="number">0</span>)</span><br><span class="line">                    &#123;</span><br><span class="line">                        <span class="built_in">perror</span>(<span class="string">&quot;dup2()&quot;</span>);</span><br><span class="line">                        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 关闭所有管道的文件描述符</span></span><br><span class="line">                <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span> * numPipes; ++i)</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="built_in">close</span>(pipefds[i]);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (command[<span class="number">0</span>] == <span class="string">&quot;cd&quot;</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="built_in">mycd</span>(command);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">else</span></span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="built_in">executeCommand</span>(command);</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                <span class="built_in">exit</span>(<span class="number">0</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                <span class="comment">// 父进程</span></span><br><span class="line">                ++commandIndex;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 关闭所有管道的文件描述符</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; <span class="number">2</span> * numPipes; ++i)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">close</span>(pipefds[i]);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 等待所有子进程结束</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i &lt; tokens.<span class="built_in">size</span>(); ++i)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">wait</span>(<span class="literal">NULL</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Shell::mycd</span><span class="params">(vector&lt;string&gt;&amp; s)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (s.<span class="built_in">size</span>() &gt; <span class="number">2</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;cd: 函数调用参数过多&quot;</span> &lt;&lt; endl;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (s.<span class="built_in">size</span>() == <span class="number">1</span> || s[<span class="number">1</span>].<span class="built_in">compare</span>(<span class="string">&quot;~&quot;</span>) == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">const</span> <span class="type">char</span>* homeDir = <span class="built_in">getenv</span>(<span class="string">&quot;HOME&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (homeDir)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="built_in">chdir</span>(homeDir) == <span class="number">-1</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">perror</span>(<span class="string">&quot;chdir()&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            cout &lt;&lt; <span class="string">&quot;cd: 无法获取家目录路径&quot;</span> &lt;&lt; endl;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (s[<span class="number">1</span>].<span class="built_in">compare</span>(<span class="string">&quot;-&quot;</span>) == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">const</span> <span class="type">char</span>* lastDir = <span class="built_in">getenv</span>(<span class="string">&quot;OLDPWD&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (lastDir)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="built_in">chdir</span>(lastDir) == <span class="number">-1</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">perror</span>(<span class="string">&quot;chdir()&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            cout &lt;&lt; <span class="string">&quot;cd: 无法找到上一个路径&quot;</span> &lt;&lt; endl;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">const</span> <span class="type">char</span>* path = s[<span class="number">1</span>].<span class="built_in">c_str</span>();</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">chdir</span>(path) == <span class="number">-1</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">perror</span>(<span class="string">&quot;chdir()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 更新环境变量 OLDPWD</span></span><br><span class="line">    <span class="type">char</span>* currentDir = <span class="built_in">get_current_dir_name</span>();<span class="comment">//获取当前工作目录的路径</span></span><br><span class="line">    <span class="keyword">if</span> (currentDir)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">setenv</span>(<span class="string">&quot;OLDPWD&quot;</span>, currentDir, <span class="number">1</span>) == <span class="number">-1</span>)<span class="comment">//设置环境变量</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="built_in">perror</span>(<span class="string">&quot;setenv()&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">free</span>(currentDir);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">perror</span>(<span class="string">&quot;get_current_dir_name()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">Shell::executeCommand</span><span class="params">(<span class="type">const</span> vector&lt;string&gt;&amp; command)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">pid_t</span> pid;</span><br><span class="line">    <span class="built_in">fflush</span>(<span class="literal">NULL</span>);</span><br><span class="line">    pid = fork();</span><br><span class="line">    <span class="keyword">if</span> (pid &lt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">perror</span>(<span class="string">&quot;fork()&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (pid == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        vector&lt;<span class="type">char</span>*&gt; args;</span><br><span class="line">        vector&lt;<span class="type">int</span>&gt; outputFds; <span class="comment">// 存储输出文件描述符的容器</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">size_t</span> i = <span class="number">0</span>; i &lt; command.<span class="built_in">size</span>(); ++i)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (command[i] == <span class="string">&quot;&gt;&quot;</span>) <span class="comment">// 输出重定向：覆盖写入文件</span></span><br><span class="line">            &#123;</span><br><span class="line">                <span class="type">int</span> fd = <span class="built_in">open</span>(command[i + <span class="number">1</span>].<span class="built_in">c_str</span>(), O_WRONLY | O_CREAT | O_TRUNC, <span class="number">0644</span>);</span><br><span class="line">                <span class="keyword">if</span> (fd == <span class="number">-1</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="built_in">perror</span>(<span class="string">&quot;open()&quot;</span>);</span><br><span class="line">                    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                outputFds.<span class="built_in">push_back</span>(fd); <span class="comment">// 将新的文件描述符添加到容器中</span></span><br><span class="line">                <span class="built_in">dup2</span>(fd, STDOUT_FILENO);</span><br><span class="line">                <span class="built_in">close</span>(fd);</span><br><span class="line">                i++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (command[i] == <span class="string">&quot;&gt;&gt;&quot;</span>) <span class="comment">// 输出重定向：追加写入文件</span></span><br><span class="line">            &#123;</span><br><span class="line">                <span class="type">int</span> fd = <span class="built_in">open</span>(command[i + <span class="number">1</span>].<span class="built_in">c_str</span>(), O_WRONLY | O_CREAT | O_APPEND, <span class="number">0644</span>);</span><br><span class="line">                <span class="keyword">if</span> (fd == <span class="number">-1</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="built_in">perror</span>(<span class="string">&quot;open()&quot;</span>);</span><br><span class="line">                    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                outputFds.<span class="built_in">push_back</span>(fd); <span class="comment">// 将新的文件描述符添加到容器中</span></span><br><span class="line">                <span class="built_in">dup2</span>(fd, STDOUT_FILENO);</span><br><span class="line">                <span class="built_in">close</span>(fd);</span><br><span class="line">                i++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (command[i] == <span class="string">&quot;&lt;&quot;</span>) <span class="comment">// 输入重定向</span></span><br><span class="line">            &#123;</span><br><span class="line">                <span class="type">int</span> fd = <span class="built_in">open</span>(command[i + <span class="number">1</span>].<span class="built_in">c_str</span>(), O_RDONLY);</span><br><span class="line">                <span class="keyword">if</span> (fd == <span class="number">-1</span>)</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="built_in">perror</span>(<span class="string">&quot;open()&quot;</span>);</span><br><span class="line">                    <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="built_in">dup2</span>(fd, STDIN_FILENO);</span><br><span class="line">                <span class="built_in">close</span>(fd);</span><br><span class="line">                i++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span> <span class="keyword">if</span> (command[i] == <span class="string">&quot;&lt;&lt;&quot;</span>) <span class="comment">// Here文档</span></span><br><span class="line">            &#123;</span><br><span class="line">                string delimiter = command[i + <span class="number">1</span>];</span><br><span class="line">                string inputText;</span><br><span class="line"></span><br><span class="line">                <span class="keyword">while</span> (<span class="built_in">getline</span>(cin, inputText))</span><br><span class="line">                &#123;</span><br><span class="line">                    <span class="keyword">if</span> (inputText == delimiter)</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    inputText += <span class="string">&quot;\n&quot;</span>;</span><br><span class="line">                    <span class="built_in">write</span>(STDIN_FILENO, inputText.<span class="built_in">c_str</span>(), inputText.<span class="built_in">size</span>());</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                i++;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                args.<span class="built_in">push_back</span>(<span class="built_in">const_cast</span>&lt;<span class="type">char</span>*&gt;(command[i].<span class="built_in">c_str</span>()));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        args.<span class="built_in">push_back</span>(<span class="literal">nullptr</span>); <span class="comment">// execvp 需要以 nullptr 结尾的参数数组</span></span><br><span class="line">        <span class="built_in">execvp</span>(args[<span class="number">0</span>], args.<span class="built_in">data</span>());</span><br><span class="line"></span><br><span class="line">        <span class="comment">// execvp 执行失败时才会执行到这里</span></span><br><span class="line">        <span class="built_in">perror</span>(<span class="string">&quot;execvp()&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">wait</span>(<span class="literal">NULL</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="shell-cpp"><a href="#shell-cpp" class="headerlink" title="shell.cpp"></a>shell.cpp</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;func.cpp&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> num = <span class="number">1</span>;</span><br><span class="line">    Shell mysh;</span><br><span class="line">    mysh.<span class="built_in">setsignal</span>();   </span><br><span class="line">    mysh.<span class="built_in">setEOF</span>();</span><br><span class="line">    <span class="keyword">while</span>(num)</span><br><span class="line">    &#123;</span><br><span class="line">        mysh.<span class="built_in">print</span>();</span><br><span class="line">        mysh.<span class="built_in">setlinebuf</span>();</span><br><span class="line">        string t = mysh.<span class="built_in">retlinebuf</span>();</span><br><span class="line">        <span class="keyword">if</span>(t.<span class="built_in">empty</span>())</span><br><span class="line">        &#123;</span><br><span class="line">            cout &lt;&lt; <span class="string">&quot;No input&quot;</span> &lt;&lt; endl;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span>(t.<span class="built_in">rfind</span>(<span class="string">&quot;exit&quot;</span>)!=string::npos)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span>(t.<span class="built_in">find</span>(<span class="string">&quot;!&quot;</span>)==<span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            string keyword = t.<span class="built_in">substr</span>(<span class="number">1</span>); <span class="comment">//获取去除感叹号的关键字</span></span><br><span class="line">            mysh.<span class="built_in">searchAndReplay</span>(keyword);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span>(t.<span class="built_in">find</span>(<span class="string">&quot;clear&quot;</span>)==<span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            mysh.<span class="built_in">addHistory</span>(t);</span><br><span class="line">            <span class="comment">// cout &lt;&lt; &quot;\033[2J\033[1;1H&quot;;//通过转义序列清除终端，但只能清楚当次的命令</span></span><br><span class="line">            <span class="built_in">system</span>(<span class="string">&quot;clear&quot;</span>);</span><br><span class="line">            num++;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            mysh.<span class="built_in">addHistory</span>(t);</span><br><span class="line">            num++;</span><br><span class="line">        &#125;</span><br><span class="line">        mysh.<span class="built_in">parse</span>(t);</span><br><span class="line">        <span class="keyword">if</span>(num%<span class="number">3</span>==<span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            cout &lt;&lt; <span class="string">&quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~&quot;</span>&lt;&lt; endl;</span><br><span class="line">            cout &lt;&lt; <span class="string">&quot; History Order :&quot;</span> &lt;&lt; endl;</span><br><span class="line">            mysh.<span class="built_in">printHistory</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>后续问题</strong>： </p><ol><li><p>在输入命令全为<code>空格</code>的时候，会直接推出程序，造成程序崩溃.</p><ol><li><p>是在<code>parse</code>中解析命令的时候，由于全为空格，所以会将一个<strong>空字符串</strong>token放入命令数组tokens,导致tokens.size()不为0造成exec函数的执行出现错误</p></li><li><p>所以在开始解析命令的时候加上全为<code>空格</code>的判断.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(std::<span class="built_in">all_of</span>(s.<span class="built_in">begin</span>(),s.<span class="built_in">end</span>(),::isspace))</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>在全为空格的时候直接返回，这样就可以返会空的二维数组.</p></li></ol></li><li><p>缺乏对乱码命令的提示:例如输入”djsakldjalkjsduj”，等命令没有类似<code>zsh : command not found : jdklasjdlak</code>的提示，而是由于exec函数的无法执行出现的提示.</p></li><li><p>对于主题打印的提示，可以将<code>Oh my zsh</code>的打印只放在初始的时候，而不是每一次都打印.</p></li><li><p>另外在输出主机名称时，输出的是固定的作者的主机名称，这里为了偷懒，未使用<code>gethostname()</code>来获取主机名.</p></li><li><p>可以考虑对命令的存储进行改进，运用其他的结构存储，而不是二维数组.</p></li><li><p>增加类与类之间的联系，而不是简单的创造一个类，这样的话就只是相当于类似头文件的作用，并没有过多的用到一些c++的特性之类的东西.</p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;shell&quot;&gt;&lt;a href=&quot;#shell&quot; class=&quot;headerlink&quot; title=&quot;shell&quot;&gt;&lt;/a&gt;shell&lt;/h1&gt;&lt;h2 id=&quot;主函数&quot;&gt;&lt;a href=&quot;#主函数&quot; class=&quot;headerlink&quot; title=&quot;主函数&quot;&gt;&lt;/</summary>
      
    
    
    
    <category term="plan" scheme="https://future.thisis.host/categories/plan/"/>
    
    
    <category term="linux" scheme="https://future.thisis.host/tags/linux/"/>
    
    <category term="plan" scheme="https://future.thisis.host/tags/plan/"/>
    
  </entry>
  
  <entry>
    <title>一次简单的分享</title>
    <link href="https://future.thisis.host/2024/03/17/share/"/>
    <id>https://future.thisis.host/2024/03/17/share/</id>
    <published>2024-03-17T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.355Z</updated>
    
    <content type="html"><![CDATA[<blockquote><h3 id="利用条件表达式完成下面的命题-学习成绩成绩-90分的同学用A表示，学习成绩在60～89分的同学用B表示哦-，学习成绩在60分以下的同学用C表示"><a href="#利用条件表达式完成下面的命题-学习成绩成绩-90分的同学用A表示，学习成绩在60～89分的同学用B表示哦-，学习成绩在60分以下的同学用C表示" class="headerlink" title="利用条件表达式完成下面的命题:学习成绩成绩&gt;&#x3D;90分的同学用A表示，学习成绩在60～89分的同学用B表示哦&#x3D;，学习成绩在60分以下的同学用C表示."></a>利用条件表达式完成下面的命题:学习成绩成绩&gt;&#x3D;90分的同学用A表示，学习成绩在60～89分的同学用B表示哦&#x3D;，学习成绩在60分以下的同学用C表示.</h3><p>int gra&#x3D;0;</p></blockquote><h1 id="class"><a href="#class" class="headerlink" title="class"></a>class</h1><p><code>class</code> 是一种用于创建用户定义的数据类型的关键字。它是面向对象编程（OOP）的基本概念之一。通过使用 <code>class</code>，您可以将数据成员（属性）和成员函数（方法）封装在一个单一的实体中，从而使代码更有组织性和可维护性。</p><p><strong>语法</strong>： class 类名 {访问权限 : 属性\行为}；     </p><p><code>class</code> 的功能与<code>struct</code>类似，但提供了更为丰富的功能.</p><p>class 可以在设计的时，可以把属性和行为放在不同的权限下，加以控制.</p><p><strong>权限的分类</strong>：</p><ul><li>public  公共权限</li><li>protected  保护权限</li><li>private  私有权限</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//公共权限  public</span></span><br><span class="line"><span class="comment">//保护权限  protected</span></span><br><span class="line"><span class="comment">//私有权限  private</span></span><br><span class="line"><span class="comment">//私有权限与保护权限在类内可以访问，在类外不可以访问</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Num</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="type">int</span> m_B;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_C;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">m_A=<span class="number">10</span>;</span><br><span class="line">        m_B=<span class="number">20</span>;</span><br><span class="line">        m_C=<span class="number">30</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">Num m;</span><br><span class="line">    m.m_A=<span class="number">10</span>;</span><br><span class="line">    <span class="comment">//m.m_B=20;//类外不可以访问</span></span><br><span class="line">    <span class="comment">//m.m_C=30;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>class与struct的区别</strong>：</p><ul><li>struct 默认权限为公共</li><li>class 默认权限为私有</li></ul><h2 id="对象的初始化清理"><a href="#对象的初始化清理" class="headerlink" title="对象的初始化清理"></a>对象的初始化清理</h2><p>对象的初始化和清理是两个非常重要的安全问题.</p><p>一个对象或者变量没有初始状态，对其使用后果未知</p><p> 同样的使用完一个对象或变量，没有及时清理，也会造成一定的安全问题</p><blockquote><p>c++利用了<strong>构造函数</strong>和<strong>析构函数</strong>解决上述问题，这两个函数将会被编译器自动调用，完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我们做的事情，因此如果<strong>我们不提供构造和析构，编译器会给我们提供空实现</strong></p></blockquote><h3 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h3><p><strong>构造函数语法：</strong> 类名(){}</p><ol><li>构造函数，没有返回值也不写void</li><li>函数名称与类名相同</li><li>构造函数可以有参数，因此可以发生重载</li><li>程序在调用对象时候会自动调用构造，无需手动调用，而且只会调用一次</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Num</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Num</span>(<span class="type">int</span> a): <span class="built_in">m_A</span>(a)</span><br><span class="line">    &#123;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;gz&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>构造函数的分类：</strong></p><ul><li>按参数<ul><li>有参构造</li><li>无参构造</li></ul></li><li>按类型<ul><li>普通构造</li><li>拷贝构造</li></ul></li></ul><p><strong>构造函数的调用方法</strong>：</p><ul><li><p>括号法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Person P;<span class="comment">//默认构造时后面不要加括号</span></span><br><span class="line"><span class="function">Person <span class="title">p1</span><span class="params">(<span class="number">10</span>)</span></span>;</span><br><span class="line"><span class="function">Person <span class="title">p2</span><span class="params">(p1)</span></span>;</span><br></pre></td></tr></table></figure></li><li><p>显示法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Person p;</span><br><span class="line">Person p1=<span class="built_in">Person</span>(<span class="number">10</span>);</span><br><span class="line">Person P2=<span class="built_in">Person</span>(p2);</span><br></pre></td></tr></table></figure></li><li><p>隐式转换法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Person p4=<span class="number">10</span>;</span><br><span class="line">Person p5=p4;<span class="comment">//相当于Person p5=Person(10);</span></span><br></pre></td></tr></table></figure></li></ul><p><strong>explcit</strong></p><p>在 C++ 中， <code>explicit</code> 关键字用于防止编译器进行隐式类型转换。当您将构造函数或转换函数声明为 <code>explicit</code> 时，这意味着该构造函数或转换函数只能由程序员显式调用，而不能由编译器隐式调用。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">P</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">P</span>()</span><br><span class="line">    &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">P</span>(<span class="type">int</span> a)</span><br><span class="line">    &#123;</span><br><span class="line">        m_A = a;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">explicit</span> <span class="title">P</span><span class="params">(P&amp; a)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_A = a.m_A;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    P p;</span><br><span class="line">    p.m_A = <span class="number">1</span>;</span><br><span class="line">    <span class="comment">//P p1 = p;//会报错，因为声明不可以隐式类型转换</span></span><br><span class="line">    P p1=<span class="built_in">P</span>(<span class="number">1</span>);</span><br><span class="line">    cout &lt;&lt; p<span class="number">1.</span>m_A &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="拷贝构造函数调用时机"><a href="#拷贝构造函数调用时机" class="headerlink" title="拷贝构造函数调用时机"></a>拷贝构造函数调用时机</h4><p>c++拷贝构造函数调用时机</p><ul><li>使用一个创建完毕的对象来初始化一个新对象</li><li>值传递的方式给函数参数传值(做参数)</li><li>以值的方式返回局部对象(做返回值)</li></ul><p><strong>构造函数调用规则</strong>：</p><p>默认情况下，c++编译器至少给一个类添加3个函数</p><p>1.默认构造参数（无参，函数体为空）</p><p>2.默认析构函数（无参，函数体为空）</p><p>3.默认拷贝构造函数，对属性值进行拷贝</p><p><strong>规则如下：</strong></p><ul><li>如果用户定义有参构造函数，c++不在提供默认无参构造，但是会提供默认拷贝构造</li><li>如果用户定义拷贝构造函数，c++不会在提供其他的构造函数</li></ul><h3 id="深浅拷贝"><a href="#深浅拷贝" class="headerlink" title="深浅拷贝"></a>深浅拷贝</h3><p><strong>浅拷贝</strong>：简单的赋值操作</p><p><strong>深拷贝</strong>：在堆区重新申请空间，进行拷贝操作.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Num</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Num</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;gz&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">Num</span>(<span class="type">const</span> Num &amp;other)</span><br><span class="line">    &#123;</span><br><span class="line">        m_A=other.m_A;</span><br><span class="line">        m_B=<span class="keyword">new</span> <span class="built_in">int</span> (*other.m_B);</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;kb&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">Num</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>-&gt;m_B)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span> <span class="keyword">this</span>-&gt;m_B;</span><br><span class="line">            <span class="keyword">this</span>-&gt;m_B=<span class="literal">nullptr</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line">    <span class="type">int</span> *m_B;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Num a;</span><br><span class="line">    a.m_A=<span class="number">1</span>;</span><br><span class="line">    a.m_B=<span class="keyword">new</span> <span class="built_in">int</span>(<span class="number">20</span>);</span><br><span class="line">    <span class="function">Num <span class="title">b</span><span class="params">(a)</span></span>;</span><br><span class="line">    cout &lt;&lt; b.m_A &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; *b.m_B &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; a.m_B &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="class-与-struct"><a href="#class-与-struct" class="headerlink" title="class 与 struct"></a>class 与 struct</h2><p>C++中的 struct 和 class 基本是通用的，唯有几个细节不同：</p><ul><li>使用 class 时，类中的成员默认都是 private 属性的；而使用 struct 时，结构体中的成员默认都是 public 属性的。</li><li>class 继承默认是 private 继承，而 struct 继承默认是 public 继承。</li><li>class 可以使用模板，而 struct 不能。</li></ul><h1 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h1><p><strong>作用</strong>：给变量起别名</p><p><strong>语法</strong>：数据类型 &amp;别名 &#x3D;原名</p><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ul><li>引用必须要初始化</li><li>引用一旦初始化后，就不可以更改</li></ul><p>引用可以简化指针的用法.</p><p><strong>引用做函数参数</strong></p><p><strong>作用</strong>：函数传参时，可以利用引用的技术让形参修饰实参</p><p><strong>优点</strong>：可以简化指针修改实参</p><p>通过引用参数产生的效果按地址传递是一样的。引用的语法更加的简单。</p><p>引用是可以作为函数的返回值存在的.</p><p>不返回局部变量的引用.</p><p>函数的调用可以作为<strong>左值.</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> sum1 = <span class="number">0</span>;</span><br><span class="line"><span class="function"><span class="type">int</span>&amp; <span class="title">sum</span><span class="params">(<span class="type">int</span> &amp;a,<span class="type">int</span> &amp;b)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    sum1 = a + b;</span><br><span class="line">    <span class="keyword">return</span> sum1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b=<span class="number">10</span>;</span><br><span class="line">    <span class="built_in">sum</span>(a,b)=<span class="number">30</span>;</span><br><span class="line">    cout &lt;&lt; sum1 &lt;&lt; endl;    </span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>本质</strong>：引用的本质在c++内部实现是一个指针常量.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">(<span class="type">int</span> &amp;ref)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ref=<span class="number">100</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="comment">//自动转换为int *const ref = &amp;a;指针常量是指针指向不可改，也说明为什么引用不可以改</span></span><br><span class="line">    <span class="type">int</span> &amp;ref=a;</span><br><span class="line">    ref=<span class="number">20</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">func</span>(a);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="左值-右值"><a href="#左值-右值" class="headerlink" title="左值 &amp; 右值"></a>左值 &amp; 右值</h1><p><code>C++</code>中所有的值都必然属于左值、右值二者之一.</p><p><strong>左值</strong>是指表达式结束之后依然存在的持久化对象</p><p><strong>右值</strong>是之表达式结束时就不再存在的临时对象.</p><p>所有的具有变量或者对象都是左值，而右值不具有名称.很难得到左值和右值的真正定义，但是有一个可以区分的便捷方法：<strong>看能否对表达式取地址，如果可以，则为左值，否则为右值。</strong></p><p>右值又分为 <code>将亡值</code>和<code>纯右值</code>。</p><p>纯右值是<code>C++98</code>标准中右值的概念，如非引用返回的函数返回的临时变量值;</p><p>而将亡值则是<code>c++</code>新增的和右值引用相关的表达式，这样的表达式通常是将要移动的对象。<code>&amp;&amp;</code>函数返回值、<code>std::move()</code>函数的返回值等.</p><p>categories来说，c++11前，只有左值(<code>lvalue</code>)和右值(<code>rvalue</code>)；c++11后，任何<code>value categories</code>(值类型)都是下面的三种之一：<code>lvalue</code>， <code>xvalue</code>， <code>prvalue</code>。<code>gvalue</code>为广义左值，包括<code>lvalue</code>和<code>xvalue</code>，<code>rvalue</code>为右值，包括<code>xvalue</code>和<code>prvalue</code>，可见<code>xvalue</code>可以是左值也可以是右值。</p><p><strong>纯右值(</strong><code>prvalue</code><strong>)：纯右值是传统右值的一部分，纯右值是表达式产生的中间值，不能取地址。 纯右值一定会在表达式结束后被销毁。</strong></p><p>一般有以下的条件：</p><ol><li>本身就是纯粹的字面值，如3、false.</li><li>求值结果相当于字面值或是一个不具名的临时变量.</li></ol><p><strong>消亡值(</strong><code>xvalue</code><strong>)是c++11的不具名的右值引用引入的</strong>。 以下情况的表达式求值结果为<code>xvalue</code>，准确的说叫不具名右值引用，这种属于新的”右值”，由右值引用带来，通常用来完成<strong>移动构造</strong>或<strong>移动赋值</strong>的特殊任务。事实上，将亡值不过是C++11提出的一块晦涩的语法糖。它与纯右值在功能上及其相似，如都不能做操作符的左操作数，都可以使用移动构造函数和移动赋值运算符。当一个纯右值来完成移动构造或移动赋值任务时，其实它也具有“将亡”的特点。一般，我们不必刻意区分一个右值到底是纯右值还是将亡值。</p><h1 id="左值引用-右值引用"><a href="#左值引用-右值引用" class="headerlink" title="左值引用 &amp; 右值引用"></a>左值引用 &amp; 右值引用</h1><p><code>c++98</code>中的引用很常见了，就是给变量取了个别名，在<code>c++11</code>中，因为增加了<strong>右值引用(</strong><code>rvalue reference</code><strong>)<strong>的概念，所以<code>c++98</code>中的引用都称为了</strong>左值引用(</strong><code>lvalue reference</code>**)**。 <code>c++11</code>中的右值引用使用的符号是<code>&amp;&amp;</code>                        </p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">A</span>&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="type">int</span> a;    </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function">A <span class="title">getTemp</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">A</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> &amp;refA = a;<span class="comment">//左值引用</span></span><br><span class="line">    <span class="comment">//int &amp;ref2 = 2; //编译错误</span></span><br><span class="line">    <span class="type">int</span> &amp;&amp;ref1=<span class="number">1</span>;<span class="comment">//右值引用</span></span><br><span class="line">    <span class="type">int</span> b =<span class="number">5</span>;</span><br><span class="line">    <span class="comment">//int &amp;&amp; refB =b;//编译错误，不能将一个左值赋值给一个右值引用</span></span><br><span class="line">    A&amp;&amp; refIns = <span class="built_in">getTemp</span>();<span class="comment">//函数返回值是 右值</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>getTemp()</code>返回的右值本来在表达式语句结束后，其生命也就该终结了（因为是临时变量），而通过右值引用，该右值又重获新生，其生命期将与右值引用类型变量<code>refIns</code>的生命期一样，只要<code>refIns</code>还活着，该右值临时变量将会一直存活下去。实际上就是给那个临时变量取了个名字。</p><p><strong>注意</strong>：这里<code>refIns</code>的<strong>类型</strong>是右值引用类型(<code>int &amp;&amp;</code>)，但是如果从左值和右值的角度区分它，它实际上是个<strong>左值</strong>。因为可以对它取地址，而且它还有名字，是一个已经命名的右值。</p><h2 id="常量左值引用"><a href="#常量左值引用" class="headerlink" title="常量左值引用"></a>常量左值引用</h2><p>左值引用只能绑定左值，右值引用只能绑定右值，如果绑定的不对，编译就会失败。但是，<strong>常量左值引用</strong>却是个奇葩，它可以算是一个“万能”的引用类型，它可以绑定非常量左值、常量左值、右值，而且在绑定右值的时候，常量左值引用还可以像右值引用一样将右值的生命期延长，缺点是，只能读不能改。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">const</span> A &amp;a =<span class="built_in">getTmp</span>();<span class="comment">//不会报错</span></span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">max</span><span class="params">(<span class="type">const</span> <span class="type">int</span> &amp;a,<span class="type">const</span> <span class="type">int</span> &amp;b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a+b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a=<span class="number">1</span>;</span><br><span class="line">    <span class="type">int</span> b=<span class="number">2</span>;</span><br><span class="line">    cout &lt;&lt; <span class="built_in">max</span>(<span class="number">1</span>,<span class="number">2</span>) &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p><code>T</code>是一个数据类型</p><ol><li>左值引用，使用<code>T&amp;</code>只能绑定左值</li><li>右值引用，使用<code>T&amp;&amp;</code>只能绑定右值</li><li>常量左值，使用<code>const T&amp;</code>，既可以绑定左值也可以绑定右值</li><li>已命名的<strong>右值引用</strong>，编译器会认为是个左值</li><li>编译器有返回值优化，但不要过于依赖(-fno-elide-constructors)</li></ol><h1 id="移动语义"><a href="#移动语义" class="headerlink" title="移动语义"></a>移动语义</h1><h2 id="移动构造函数-移动赋值函数"><a href="#移动构造函数-移动赋值函数" class="headerlink" title="移动构造函数 &amp; 移动赋值函数"></a>移动构造函数 &amp; 移动赋值函数</h2><p>用c++实现一个字符串类<code>MiniString</code>，<code>MiniString</code>内部管理一个C语言的<code>char *</code>数组，这个时候一般都需要实现拷贝构造函数和拷贝赋值函数，因为默认的拷贝是浅拷贝，而指针这种资源不能共享。代码如下：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MiniString</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">static</span> <span class="type">size_t</span> kbsize;</span><br><span class="line">    <span class="built_in">MiniString</span>(<span class="type">const</span> <span class="type">char</span> *str)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(str)</span><br><span class="line">        &#123;</span><br><span class="line">            m_data = <span class="keyword">new</span> <span class="type">char</span>[<span class="built_in">strlen</span>(str) + <span class="number">1</span>];</span><br><span class="line">            <span class="built_in">strcpy</span>(m_data, str);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            m_data = <span class="keyword">new</span> <span class="type">char</span>[<span class="number">1</span>];</span><br><span class="line">            *m_data = <span class="string">&#x27;\0&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">MiniString</span>(<span class="type">const</span> MiniString &amp;other)</span><br><span class="line">    &#123;</span><br><span class="line">        kbsize ++;</span><br><span class="line">        m_data=<span class="keyword">new</span> <span class="type">char</span>[<span class="built_in">strlen</span>(other.m_data) + <span class="number">1</span>];</span><br><span class="line">        <span class="built_in">strcpy</span>(m_data, other.m_data);</span><br><span class="line">        <span class="comment">//cout &lt;&lt; &quot;kb&quot; &lt;&lt; kbsize &lt;&lt; endl;</span></span><br><span class="line">    &#125;   </span><br><span class="line">    MiniString &amp;<span class="keyword">operator</span>=(<span class="type">const</span> MiniString &amp;other)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>==&amp;other)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">delete</span>[] m_data;</span><br><span class="line">        m_data = <span class="keyword">new</span> <span class="type">char</span>[<span class="built_in">strlen</span>(other.m_data) + <span class="number">1</span>];</span><br><span class="line">        <span class="built_in">strcpy</span>(m_data, other.m_data);</span><br><span class="line">        <span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">MiniString</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(m_data)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span>[] m_data;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">char</span> *m_data;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">size_t</span> MiniString::kbsize =<span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    vector&lt;MiniString&gt; v;</span><br><span class="line">    v.<span class="built_in">reserve</span>(<span class="number">1000</span>);</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>; i&lt;<span class="number">1000</span>; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        v.<span class="built_in">push_back</span>(<span class="built_in">MiniString</span>(<span class="string">&quot;hello world!&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">    cout &lt;&lt; MiniString::kbsize &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><blockquote><p>代码执行了<code>1000</code>次拷贝构造函数，如果<code>MiniString(&quot;hello&quot;)</code>构造出来的字符串本来就很长，构造一遍就很耗时了，最后却还要拷贝一遍，而<code>MiniString(&quot;hello&quot;)</code>只是临时对象，拷贝完就没什么用了，这就造成了没有意义的资源申请和释放操作，如果能够直接使用临时对象已经申请的资源，既能节省资源，又能节省资源申请和释放的时间。而<code>C++11</code>新增加的<strong>移动语义</strong>就能够做到这一点。</p></blockquote></blockquote><p>移动语义避免了移动原始数据，而只是修改了记录。要实现移动语义就必须增加两个函数：移动构造函数和移动赋值构造函数。必须让编译器知道什么时候需要复制，什么时候不需要复制。这就是右值引用发挥最大作用的地方。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;cstring&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;vector&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MiniString</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">static</span> <span class="type">size_t</span> kbsize;</span><br><span class="line">    <span class="type">static</span> <span class="type">size_t</span> movesize;</span><br><span class="line">    <span class="type">static</span> <span class="type">size_t</span> Fkbsize;</span><br><span class="line">    <span class="type">static</span> <span class="type">size_t</span> Fmovesize;</span><br><span class="line">    <span class="built_in">MiniString</span>(<span class="type">const</span> <span class="type">char</span> *str)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(str)</span><br><span class="line">        &#123;</span><br><span class="line">            m_data = <span class="keyword">new</span> <span class="type">char</span>[<span class="built_in">strlen</span>(str) + <span class="number">1</span>];</span><br><span class="line">            <span class="built_in">strcpy</span>(m_data, str);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            m_data = <span class="keyword">new</span> <span class="type">char</span>[<span class="number">1</span>];</span><br><span class="line">            *m_data = <span class="string">&#x27;\0&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">MiniString</span>(<span class="type">const</span> MiniString &amp;other)</span><br><span class="line">    &#123;</span><br><span class="line">        kbsize ++;</span><br><span class="line">        m_data=<span class="keyword">new</span> <span class="type">char</span>[<span class="built_in">strlen</span>(other.m_data) + <span class="number">1</span>];</span><br><span class="line">        <span class="built_in">strcpy</span>(m_data, other.m_data);</span><br><span class="line">        <span class="comment">// cout &lt;&lt; &quot;kb&quot; &lt;&lt; kbsize &lt;&lt; endl;</span></span><br><span class="line">    &#125; </span><br><span class="line">    <span class="built_in">MiniString</span>(MiniString &amp;&amp;other)</span><br><span class="line">    &#123;</span><br><span class="line">        m_data=other.m_data;</span><br><span class="line">        movesize ++;</span><br><span class="line">        other.m_data=<span class="literal">NULL</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    MiniString &amp;<span class="keyword">operator</span>=(<span class="type">const</span> MiniString &amp;other)</span><br><span class="line">    &#123;</span><br><span class="line">        Fkbsize ++;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>==&amp;other)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">delete</span>[] m_data;</span><br><span class="line">        m_data = <span class="keyword">new</span> <span class="type">char</span>[<span class="built_in">strlen</span>(other.m_data) + <span class="number">1</span>];</span><br><span class="line">        <span class="built_in">strcpy</span>(m_data, other.m_data);</span><br><span class="line">        <span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    MiniString &amp;<span class="keyword">operator</span>=(MiniString &amp;&amp; other)</span><br><span class="line">    &#123;</span><br><span class="line">        Fmovesize++;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>==&amp;other)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">delete</span>[] m_data;</span><br><span class="line">        m_data=other.m_data;</span><br><span class="line">        other.m_data=<span class="literal">NULL</span>;</span><br><span class="line">        <span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">MiniString</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">delete</span>[] m_data;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">char</span> *m_data;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">size_t</span> MiniString::kbsize =<span class="number">0</span>;</span><br><span class="line"><span class="type">size_t</span> MiniString::movesize=<span class="number">0</span>;</span><br><span class="line"><span class="type">size_t</span> MiniString::Fkbsize=<span class="number">0</span>;</span><br><span class="line"><span class="type">size_t</span> MiniString::Fmovesize;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    vector&lt;MiniString&gt; v;</span><br><span class="line">    v.<span class="built_in">reserve</span>(<span class="number">1000</span>);</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>; i&lt;<span class="number">1000</span>; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        v.<span class="built_in">push_back</span>(<span class="built_in">MiniString</span>(<span class="string">&quot;hello world!&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">    cout &lt;&lt;<span class="string">&quot;kbsize\t&quot;</span>&lt;&lt; MiniString::kbsize &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt;<span class="string">&quot;Fkbsize\t&quot;</span>&lt;&lt; MiniString::Fkbsize &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt;<span class="string">&quot;movesize\t&quot;</span>&lt;&lt; MiniString::movesize &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt;<span class="string">&quot;Fmovesize\t&quot;</span>&lt;&lt; MiniString::Fmovesize &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>移动构造函数与拷贝构造函数的区别是，拷贝构造的参数是<code>const MiniString&amp; str</code>，是<em><strong>常量左值引用</strong></em>，而移动构造的参数是<code>MiniString&amp;&amp; str</code>，是<em><strong>右值引用</strong></em>，而<code>MiniString(&quot;hello&quot;)</code>是个临时对象，是个右值，优先进入<strong>移动构造函数</strong>而不是拷贝构造函数。而移动构造函数与拷贝构造不同，它并不是重新分配一块新的空间，将要拷贝的对象复制过来，而是”偷”了过来，将自己的指针指向别人的资源，然后将别人的指针修改为<code>nullptr</code>，这一步很重要，如果不将别人的指针修改为空，那么临时对象析构的时候就会释放掉这个资源，”偷”也白偷了。</p><p>不用奇怪为什么可以抢别人的资源，临时对象的资源不好好利用也是浪费，因为生命周期本来就是很短，在你执行完这个表达式之后，它就毁灭了，充分利用资源，才能很高效。</p><p>当类中同时包含拷贝构造函数和移动构造函数时，如果使用临时对象初始化当前类的对象，编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时，编译器才会退而求其次，调用拷贝构造函数。</p><h2 id="std-move"><a href="#std-move" class="headerlink" title="std::move()"></a>std::move()</h2><p>对于一个左值，肯定是调用拷贝构造函数了，但是有些左值是局部变量，生命周期也很短，能不能也移动而不是拷贝呢？<code>C++11</code>为了解决这个问题，提供了<code>std::move()</code>方法来<strong>将左值转换为右值</strong>，从而方便应用移动语义。其实就是告诉编译器，虽然我是一个左值，但是不要对我用拷贝构造函数，而是用移动构造函数。<code>std::move</code> 的源码实现：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// FUNCTION TEMPLATE move</span></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">_Ty</span>&gt;</span><br><span class="line"><span class="function">_NODISCARD <span class="keyword">constexpr</span> <span class="type">remove_reference_t</span>&lt;_Ty&gt;&amp;&amp; <span class="title">move</span><span class="params">(_Ty&amp;&amp; _Arg)</span> <span class="keyword">noexcept</span> </span>&#123; <span class="comment">// forward _Arg as movable</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">static_cast</span>&lt;<span class="type">remove_reference_t</span>&lt;_Ty&gt;&amp;&amp; &gt;(_Arg);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//_NODISCARD 这是一种标记，用于指示编译器在忽略函数返回值时发出警告。</span></span><br><span class="line"><span class="comment">//constexpr:表示这个函数是在编译时计算的</span></span><br><span class="line"><span class="comment">//noexcept:表示这个函数不会抛出异常</span></span><br><span class="line"><span class="comment">//remove_reference_t 是 C++ 标准库 &lt;type_traits&gt; 中的一个模板元函数，用于移除类型的引用修饰符（&amp; 或 &amp;&amp;）。</span></span><br></pre></td></tr></table></figure><p><strong>static_cast:</strong></p><p>用于显示类型转换.在编译时进行类型检查，用于在不同但相关的类型之间检查.</p><p><strong>其他类型转换的函数</strong></p><ul><li><strong>dynamic_cast</strong>:<ul><li>用于在运行时进行安全的向下转型，主要用于处理继承关系中的多态类型</li><li>仅在具有虚函数的类层次结构中才有效</li><li>如果转型合法，则返回目标类型的指针或引用，否则返回nullptr</li></ul></li><li><strong>reinterpret_case</strong>：<ul><li>执行底层的二进制位级别的转换</li><li>非常强大，但潜在的不安全，因为它可以忽略类型之间的语义差异</li></ul></li></ul><blockquote><p>可以看到 <code>std::move</code> 是一个模板函数，通过<code>remove_reference_t</code>获得模板参数的原本类型，然后把值转换为该类型的右值。用C++大师 Scott Meyers 的在《Effective Modern C++》中的话说， std::move 是个cast ，not a move.</p></blockquote><p>注意： 使用 <code>move</code> 意味着，把一个左值转换为右值，原先的值不应该继续再使用（承诺即将废弃）。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">MiniString <span class="title">str1</span><span class="params">(<span class="string">&quot;hello&quot;</span>)</span></span>; <span class="comment">// 调用构造函数</span></span><br><span class="line"><span class="function">MiniString <span class="title">str2</span><span class="params">(<span class="string">&quot;world&quot;</span>)</span></span>; <span class="comment">// 调用构造函数</span></span><br><span class="line"><span class="function">MiniString <span class="title">str3</span><span class="params">(str1)</span></span>;    <span class="comment">// 调用拷贝构造函数</span></span><br><span class="line"><span class="function">MiniString <span class="title">str4</span><span class="params">(std::move(str1))</span></span>;    <span class="comment">// 调用移动构造函数</span></span><br><span class="line"><span class="comment">// cout &lt;&lt; str1.get_c_str() &lt;&lt; endl; // 此时str1的内部指针已经失效了！不要再使用</span></span><br><span class="line"><span class="comment">// 虽然str1中的m_dat已经称为了空，但是str1这个对象还活着，知道出了它的作用域才会析构，</span></span><br><span class="line"><span class="comment">// 而不是move完了立刻析构</span></span><br><span class="line">MiniString str5;</span><br><span class="line">str5 = str2;            <span class="comment">// 调用拷贝赋值函数</span></span><br><span class="line">MiniString str6;</span><br><span class="line">str6 = std::<span class="built_in">move</span>(str2); <span class="comment">// 调用移动赋值函数，str2的内容也失效了，不要再使用</span></span><br></pre></td></tr></table></figure><p>要注意一下几点：</p><ol><li><code>str6 = std::move(str2)</code>，虽然将<code>str2</code>的资源给了<code>str6</code>，但是<code>str2</code>并没有立刻析构，只有在<code>str2</code>离开了自己的作用域的时候才会析构，所以，如果继续使用<code>str2</code>的<code>m_data</code>变量，可能会发生意想不到的错误。</li><li>如果我们没有提供移动构造函数，只提供了拷贝构造函数，<code>std::move()</code>会失效但是不会发生错误，因为编译器找不到移动构造函数就去寻找拷贝构造函数，也这是拷贝构造函数的参数是<code>const T&amp;</code>常量左值引用的原因！</li><li><code>c++11中</code>的所有容器都实现了<code>move</code>语义，<code>move</code>只是转移了资源的控制权，本质上是将左值强制转化为右值使用，以用于移动拷贝或赋值，避免对<strong>含有资源的对象</strong>发生无谓的拷贝。<code>move</code>对于拥有如内存、文件句柄等资源的成员的对象有效，如果是一些基本类型，如<code>int</code>和<code>char[10]</code>数组等，如果使用<code>move</code>，仍会发生拷贝（因为没有对应的移动构造函数），所以说<code>move</code>对含有资源的对象说更有意义。</li></ol><h1 id="通用引用"><a href="#通用引用" class="headerlink" title="通用引用"></a>通用引用</h1><p>当右值引用和模板结合的时候，就复杂了。<code>T&amp;&amp;</code>并不一定表示右值引用，它可能是个左值引用又可能是个右值引用。例如：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T</span>&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">(T&amp;&amp;a,T&amp;&amp;b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; a+b &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b=<span class="number">20</span>;</span><br><span class="line">    <span class="built_in">func</span>(a,b);</span><br><span class="line">    <span class="built_in">func</span>(<span class="number">200</span>,<span class="number">300</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果上面的函数模板表示的是右值引用的话，肯定是不能传递左值的，但是事实却是可以。这里的<code>&amp;&amp;</code>是一个未定义的引用类型，称为<code>universal references</code>，它必须被初始化，它是左值引用还是右值引用却决于它的初始化，如果它被一个左值初始化，它就是一个左值引用；如果被一个右值初始化，它就是一个右值引用。</p><p><strong>注意</strong>：只有当<strong>发生自动类型推断</strong>时（如函数模板的类型自动推导，或auto关键字），<code>&amp;&amp;</code>才是一个<code>universal references</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">(T&amp;&amp;a)</span></span>;<span class="comment">//这里T需要推导，所以&amp;&amp;是universal references</span></span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>(T age)</span><br><span class="line">    &#123;</span><br><span class="line">        m_age = age;</span><br><span class="line">    &#125;</span><br><span class="line">    T m_age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Person&lt;<span class="type">int</span>&gt; <span class="title">p</span><span class="params">(<span class="number">1</span>)</span></span>;</span><br><span class="line">    cout &lt;&lt;p.m_age &lt;&lt; endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Test</span> &#123;</span><br><span class="line">  <span class="built_in">Test</span>( Test&amp;&amp; rhs );   <span class="comment">// Test是一个特定的类型，不需要类型推导，所以&amp;&amp;表示 右值引用  </span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">(std::vector&lt;T&gt;&amp;&amp; data)</span></span>;<span class="comment">//在往vector添加元素的时候已经将T推断出来，所以是右值引用</span></span><br></pre></td></tr></table></figure><p>所以最终还是要看<code>T</code>被推导成什么类型，如果<code>T</code>被推导成了<code>string</code>，那么<code>T&amp;&amp;</code>就是<code>string&amp;&amp;</code>，是个右值引用，如果<code>T</code>被推导为<code>string&amp;</code>，就会发生类似<code>string&amp; &amp;&amp;</code>的情况，对于这种情况，<code>c++11</code>增加了引用折叠的规则，总结如下：</p><ol><li>所有的右值引用叠加到右值引用上仍然使一个右值引用。</li><li>所有的其他引用类型之间的叠加都将变成左值引用。</li></ol><h1 id="完美转发"><a href="#完美转发" class="headerlink" title="完美转发"></a>完美转发</h1><p>所谓转发，就是通过一个函数将参数继续转交给另一个函数进行处理，原参数可能是右值，可能是左值，如果还能继续保持参数的原有特征，那么它就是完美的。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;iostream&gt;</span></span></span><br><span class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> std;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">process</span><span class="params">(<span class="type">int</span> &amp;i)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;process(int &amp;)&quot;</span> &lt;&lt; i &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">process</span><span class="params">(<span class="type">int</span> &amp;&amp;i)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;process(int &amp;&amp;)&quot;</span> &lt;&lt; i &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">myforward</span><span class="params">(<span class="type">int</span> &amp;&amp;i)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt;<span class="string">&quot;myforward(int &amp;&amp;)&quot;</span> &lt;&lt; i &lt;&lt; endl;</span><br><span class="line">    <span class="comment">//process(i);</span></span><br><span class="line">    <span class="built_in">process</span>(forward&lt;<span class="type">int</span>&gt;(i));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a =<span class="number">0</span>;</span><br><span class="line">    <span class="built_in">process</span>(a);</span><br><span class="line">    <span class="built_in">process</span>(<span class="number">1</span>);</span><br><span class="line">    <span class="built_in">process</span>(<span class="built_in">move</span>(a));</span><br><span class="line">    <span class="built_in">myforward</span>(<span class="number">1</span>);</span><br><span class="line">    <span class="built_in">myforward</span>(<span class="built_in">move</span>(a));</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面的例子就是不完美转发，而c++中提供了一个<code>std::forward()</code>模板函数解决这个问题。将上面的<code>myforward()</code>函数简单改写一下：</p><p>上面修改过后还是不完美转发，<code>myforward()</code>函数能够将右值转发过去，但是并不能够转发左值，解决办法就是借助<code>universal references</code>通用引用类型和<code>std::forward()</code>模板函数共同实现完美转发。例子如下：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">RunCode</span><span class="params">(<span class="type">int</span> &amp;&amp;m)</span> </span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;rvalue ref&quot;</span> &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">RunCode</span><span class="params">(<span class="type">int</span> &amp;m)</span> </span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;lvalue ref&quot;</span> &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">RunCode</span><span class="params">(<span class="type">const</span> <span class="type">int</span> &amp;&amp;m)</span> </span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;const rvalue ref&quot;</span> &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">RunCode</span><span class="params">(<span class="type">const</span> <span class="type">int</span> &amp;m)</span> </span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;const lvalue ref&quot;</span> &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 这里利用了universal references，如果写T&amp;，就不支持传入右值，而写T&amp;&amp;，既能支持左值，又能支持右值</span></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">perfectForward</span><span class="params">(T &amp;&amp; t)</span> </span>&#123;</span><br><span class="line">    <span class="built_in">RunCode</span>(forward&lt;T&gt; (t));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">notPerfectForward</span><span class="params">(T &amp;&amp; t)</span> </span>&#123;</span><br><span class="line">    <span class="built_in">RunCode</span>(t);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">0</span>;</span><br><span class="line">    <span class="type">int</span> b = <span class="number">0</span>;</span><br><span class="line">    <span class="type">const</span> <span class="type">int</span> c = <span class="number">0</span>;</span><br><span class="line">    <span class="type">const</span> <span class="type">int</span> d = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">notPerfectForward</span>(a);       <span class="comment">// lvalue ref</span></span><br><span class="line">    <span class="built_in">notPerfectForward</span>(<span class="built_in">move</span>(b)); <span class="comment">// lvalue ref</span></span><br><span class="line">    <span class="built_in">notPerfectForward</span>(c);       <span class="comment">// const lvalue ref</span></span><br><span class="line">    <span class="built_in">notPerfectForward</span>(<span class="built_in">move</span>(d)); <span class="comment">// const lvalue ref</span></span><br><span class="line"></span><br><span class="line">    cout &lt;&lt; endl;</span><br><span class="line">    <span class="built_in">perfectForward</span>(a);       <span class="comment">// lvalue ref</span></span><br><span class="line">    <span class="built_in">perfectForward</span>(<span class="built_in">move</span>(b)); <span class="comment">// rvalue ref</span></span><br><span class="line">    <span class="built_in">perfectForward</span>(c);       <span class="comment">// const lvalue ref</span></span><br><span class="line">    <span class="built_in">perfectForward</span>(<span class="built_in">move</span>(d)); <span class="comment">// const rvalue ref</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><a href="https://mqjyl2012.gitbook.io/algorithm/c-cpp/advanced-c++/mobile-semantic-perfect-forward">原文链接</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;h3 id=&quot;利用条件表达式完成下面的命题-学习成绩成绩-90分的同学用A表示，学习成绩在60～89分的同学用B表示哦-，学习成绩在60分以下的同学用C表示&quot;&gt;&lt;a href=&quot;#利用条件表达式完成下面的命题-学习成绩成绩-90分的同学用A表示，学习成</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    <category term="c++" scheme="https://future.thisis.host/categories/notes/c/"/>
    
    
    <category term="c++" scheme="https://future.thisis.host/tags/c/"/>
    
  </entry>
  
  <entry>
    <title>github主页放置贪吃蛇</title>
    <link href="https://future.thisis.host/2024/03/08/%E7%94%9F%E6%88%90%E4%B8%AA%E4%BA%BA%E8%AE%BF%E9%97%AE%E4%BB%A4%E7%89%8C/"/>
    <id>https://future.thisis.host/2024/03/08/%E7%94%9F%E6%88%90%E4%B8%AA%E4%BA%BA%E8%AE%BF%E9%97%AE%E4%BB%A4%E7%89%8C/</id>
    <published>2024-03-08T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.357Z</updated>
    
    <content type="html"><![CDATA[<h1 id="生成个人访问令牌"><a href="#生成个人访问令牌" class="headerlink" title="生成个人访问令牌"></a>生成个人访问令牌</h1><blockquote><p>生成secrets前首先要生成个人访问令牌</p></blockquote><p><strong>创建令牌</strong></p><ol><li>验证您的电子邮件地址(尚未验证)</li><li>在任何界面的右上角，点击个人资料照片，点击设置</li><li>在左边侧边栏中，点击<code>Developer settings</code>(在最下边)</li><li>然后在<code>Personal access tokens</code>的<code>Tokens</code>中选择Generate new tokens然后选择第二个</li></ol><p>选则您要授予此令牌的范围或权限。要使用令牌从命令行访问存储库，请选择<strong>repo</strong>。如果还需要其他权限请自行勾选。(workflow也进行选择)，然后确定即可</p><p><strong>最后</strong></p><p>将令牌复制到剪切板。出于安全的原因，在您离开该界面后，您将无法再次看到该令牌。</p><h1 id="配置github项目的secrets"><a href="#配置github项目的secrets" class="headerlink" title="配置github项目的secrets"></a>配置github项目的secrets</h1><p>在github的仓库中打开设置。</p><p>在侧边栏中点击<code>Secrets and variables</code>中的<code>Actions</code>。</p><p>点击<code>New repository secret</code>。</p><p>名称是随便起得。Secret就是刚才生成的令牌.</p><p><a href="https://blog.csdn.net/weixin_45178716/article/details/106416925">详细教程</a></p><h1 id="更改该仓库的写权限"><a href="#更改该仓库的写权限" class="headerlink" title="更改该仓库的写权限"></a>更改该仓库的写权限</h1><p>在该仓库侧边栏中选择<code>Actions</code>当中的<code>General</code>,在该页面下的<strong>Workflow</strong>当中选择第一个并前保存.</p><p><a href="https://stackoverflow.com/questions/72851548/permission-denied-to-github-actionsbot">详细教程</a> </p><h1 id="设置贪吃蛇"><a href="#设置贪吃蛇" class="headerlink" title="设置贪吃蛇"></a>设置贪吃蛇</h1><p>在仓库中的<strong>Actions</strong>中点击<code>newworkflow</code></p><p>然后点击<code>set up a workflow yourself</code></p><p>新建snake.yml.</p><p>复制以下内容.</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">name:</span> <span class="string">generate</span> <span class="string">animation</span></span><br><span class="line"></span><br><span class="line"><span class="attr">on:</span></span><br><span class="line">  <span class="comment"># run automatically every 24 hours</span></span><br><span class="line">  <span class="attr">schedule:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">cron:</span> <span class="string">&quot;0 */24 * * *&quot;</span> </span><br><span class="line">  </span><br><span class="line">  <span class="comment"># allows to manually run the job at any time</span></span><br><span class="line">  <span class="attr">workflow_dispatch:</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment"># run on every push on the master branch</span></span><br><span class="line">  <span class="attr">push:</span></span><br><span class="line">    <span class="attr">branches:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">main</span></span><br><span class="line">    </span><br><span class="line">  </span><br><span class="line"></span><br><span class="line"><span class="attr">jobs:</span></span><br><span class="line">  <span class="attr">generate:</span></span><br><span class="line">    <span class="attr">runs-on:</span> <span class="string">ubuntu-latest</span></span><br><span class="line">    <span class="attr">timeout-minutes:</span> <span class="number">10</span></span><br><span class="line">    </span><br><span class="line">    <span class="attr">steps:</span></span><br><span class="line">      <span class="comment"># generates a snake game from a github user (&lt;github_user_name&gt;) contributions graph, output a svg animation at &lt;svg_out_path&gt;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">generate</span> <span class="string">github-contribution-grid-snake.svg</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">Platane/snk/svg-only@v3</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">github_user_name:</span> <span class="string">$&#123;&#123;</span> <span class="string">github.repository_owner</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          <span class="attr">outputs:</span> <span class="string">|</span></span><br><span class="line"><span class="string">            dist/github-contribution-grid-snake.svg</span></span><br><span class="line"><span class="string">            dist/github-contribution-grid-snake-dark.svg?palette=github-dark</span></span><br><span class="line"><span class="string"></span>        <span class="attr">env:</span></span><br><span class="line">          <span class="attr">GITHUB_TOKEN:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.GITHUB_TOKEN</span> <span class="string">&#125;&#125;</span></span><br><span class="line">          </span><br><span class="line">          </span><br><span class="line">      <span class="comment"># push the content of &lt;build_dir&gt; to a branch</span></span><br><span class="line">      <span class="comment"># the content will be available at https://raw.githubusercontent.com/&lt;github_user&gt;/&lt;repository&gt;/&lt;target_branch&gt;/&lt;file&gt; , or as github page</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">name:</span> <span class="string">push</span> <span class="string">github-contribution-grid-snake.svg</span> <span class="string">to</span> <span class="string">the</span> <span class="string">output</span> <span class="string">branch</span></span><br><span class="line">        <span class="attr">uses:</span> <span class="string">crazy-max/ghaction-github-pages@v3.1.0</span></span><br><span class="line">        <span class="attr">with:</span></span><br><span class="line">          <span class="attr">target_branch:</span> <span class="string">output</span></span><br><span class="line">          <span class="attr">build_dir:</span> <span class="string">dist</span></span><br><span class="line">        <span class="attr">env:</span></span><br><span class="line">          <span class="attr">GITHUB_TOKEN:</span> <span class="string">$&#123;&#123;</span> <span class="string">secrets.GITHUB_TOKEN</span> <span class="string">&#125;&#125;</span></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>然后保存.</p><p>然后点击Run workflow即可</p><p>然后回到该仓库的主页，会生成output分支，里面会有对应提交记录的贪吃蛇的<strong>svg</strong>图片</p><p>然后点击生成的文件，在右上角有Raw，即可查看文件地址.</p><p><a href="https://www.cnblogs.com/javadog-net/p/17746748.html">贪吃蛇详细教程</a></p><p><a href="https://github.com/SIMple-lives/SIMple-lives/blob/main/README.md?plain=1">个人readme文件</a></p><p>将贪吃蛇部分代码部分代码的链接进行替换。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;生成个人访问令牌&quot;&gt;&lt;a href=&quot;#生成个人访问令牌&quot; class=&quot;headerlink&quot; title=&quot;生成个人访问令牌&quot;&gt;&lt;/a&gt;生成个人访问令牌&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;生成secrets前首先要生成个人访问令牌&lt;/p&gt;
&lt;/block</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    
    <category term="github" scheme="https://future.thisis.host/tags/github/"/>
    
    <category term="show" scheme="https://future.thisis.host/tags/show/"/>
    
  </entry>
  
  <entry>
    <title>ls的自我实现</title>
    <link href="https://future.thisis.host/2024/03/04/ls%20%E7%9A%84%E8%87%AA%E6%88%91%E5%AE%9E%E7%8E%B0/"/>
    <id>https://future.thisis.host/2024/03/04/ls%20%E7%9A%84%E8%87%AA%E6%88%91%E5%AE%9E%E7%8E%B0/</id>
    <published>2024-03-04T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.355Z</updated>
    
    <content type="html"><![CDATA[<h1 id="myls"><a href="#myls" class="headerlink" title="myls"></a>myls</h1><blockquote><p><code>ls</code> 是一个常用的命令行工具，用于列出指定目录中的文件和子目录。<code>ls</code> 的基本语法是:</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls [选项] [文件或目录]</span><br></pre></td></tr></table></figure><p>以下是一些常用的 <code>ls</code> 命令选项：</p><ol><li><p><strong>-l</strong>：以长格式显示文件信息，包括文件类型、权限、所有者、组、大小、修改时间等。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls -l</span><br></pre></td></tr></table></figure></li><li><p><strong>-a</strong>：显示所有文件，包括隐藏文件（以点开头的文件）。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls -a</span><br></pre></td></tr></table></figure></li><li><p><strong>-r</strong>：与 <code>-l</code> 逆序输出文件信息。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls -r</span><br></pre></td></tr></table></figure></li><li><p><strong>-R</strong>：递归显示子目录中的文件。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls -R</span><br></pre></td></tr></table></figure></li><li><p><strong>-t</strong>：按修改时间排序，最新修改的文件显示在前面。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls -lt</span><br></pre></td></tr></table></figure></li><li><p><strong>-S</strong>：按文件大小排序，最大的文件显示在前面。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls -lS</span><br></pre></td></tr></table></figure></li><li><p><strong>-i</strong>：显示文件的 inode 号码。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ls -i</span><br></pre></td></tr></table></figure></li></ol><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><p>1.-i -a -R -r -i -s -l为命令行参数，我们首先需要解析命令行参数。</p><p>2.我们需要对以上参数进行了解，并进行构思一个框架以便后续对代码的维护与可读性。</p><p>3.我觉得可以将以上参数分为三类:1.-a 为确定需要显示的文件多少，例如-a包含 . 隐藏文件。2.-s -t 排序参数，如果含有该参数，则就需要对文件显示进行排序。3.-i -l 为输出参数，即在输出的时候进行判断是否需要输出对应的信息.</p><p>4.ls 还可以指定文件进行查看，我们还需要对不同的文件或目录进行操作.</p><h2 id="相关函数"><a href="#相关函数" class="headerlink" title="相关函数"></a>相关函数</h2><ul><li><p><strong>getopt</strong>,<strong>getcwd</strong></p></li><li><p><strong>opendir</strong>,<strong>readdir</strong>,<strong>closedir</strong></p></li><li><p><strong>snprintf</strong></p></li><li><p><strong>stat</strong>,<strong>lstat</strong></p></li></ul><h2 id="主函数"><a href="#主函数" class="headerlink" title="主函数"></a>主函数</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">order</span> &#123;</span></span><br><span class="line">    a, s, t, r, I, l, R</span><br><span class="line">&#125;;<span class="comment">//枚举命令行参数。提高代码的可读性.</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> find = <span class="number">0</span>;<span class="comment">//用来接收getopt的返回值</span></span><br><span class="line">    <span class="type">int</span> orders[<span class="number">8</span>] = &#123;<span class="number">0</span>&#125;;<span class="comment">//存储对应参数的信息</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; argc; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (argv[i][<span class="number">0</span>] == <span class="string">&#x27;-&#x27;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">while</span> ((find = getopt(argc, argv, <span class="string">&quot;aIlrstR&quot;</span>)) != <span class="number">-1</span>)<span class="comment">//解析命令行参数</span></span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">switch</span> (find)<span class="comment">//将对应的参数信息残赋值为1.</span></span><br><span class="line">                &#123;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;a&#x27;</span>:</span><br><span class="line">                    orders[a] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;r&#x27;</span>:</span><br><span class="line">                    orders[r] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;s&#x27;</span>:</span><br><span class="line">                    orders[s] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;t&#x27;</span>:</span><br><span class="line">                    orders[t] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;l&#x27;</span>:</span><br><span class="line">                    orders[l] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;R&#x27;</span>:</span><br><span class="line">                    orders[R] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;I&#x27;</span>:</span><br><span class="line">                    orders[I] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">default</span>:</span><br><span class="line">                    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Invalid option\n&quot;</span>);</span><br><span class="line">                    <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> countfile = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; argc; i++)<span class="comment">//获取文件的数量.</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (argv[i][<span class="number">0</span>] != <span class="string">&#x27;-&#x27;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            countfile++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (countfile == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">char</span> current_path[MAX_PATH];<span class="comment">//存储当前的工作路径</span></span><br><span class="line">        <span class="keyword">if</span> ((getcwd(current_path, MAX_PATH)) != <span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (orders[R] == <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                do_open(current_path, orders);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                do_open_R(current_path, orders);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            perror(<span class="string">&quot;getcwd&quot;</span>);</span><br><span class="line">            <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; argc; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (argv[i][<span class="number">0</span>] != <span class="string">&#x27;-&#x27;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (countfile &gt; <span class="number">1</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%s\n&quot;</span>, argv[i]);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (orders[R] == <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                do_open(argv[i], orders);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                do_open_R(argv[i],orders);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>了解了ls的基本语法与功能后，我们就需要进行实现.</p><p>那么就首先需要解析命令行参数.获取我们本次操作需要进行的工作.</p><h3 id="getopt"><a href="#getopt" class="headerlink" title="getopt"></a>getopt</h3><p>该函数专门用来解析命令行参数.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">getopt</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> * <span class="type">const</span> argv[], <span class="type">const</span> <span class="type">char</span> *optstring)</span>;</span><br></pre></td></tr></table></figure><p><strong>参数说明</strong></p><ul><li><p>argc：通常由 main 函数直接传入，表示参数的数量</p></li><li><p>argv：通常也由 main 函数直接传入，表示参数的字符串变量数组</p></li><li><p>optstring：一个包含正确的参数选项字符串，用于参数的解析。例如 “abc:”，其中 -a，-b 就表示两</p><p>个普通选项，-c 表示一个必须有参数的选项，因为它后面有一个冒号.</p></li></ul><p>这里命令行参数已经解析，那么我们接下来就要进行对要查看的文件或目录数量进行统计.</p><p><strong>如果数量大于2,就需要在进行操作前输出本次查看的文件或目录路径.</strong></p><h3 id="getcwd"><a href="#getcwd" class="headerlink" title="getcwd"></a>getcwd</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">#include&lt;unistd.h&gt;</span><br><span class="line">char *getcwd(char *buf,size_t size);</span><br></pre></td></tr></table></figure><p>介绍：<br>参数说明：getcwd()会将当前工作目录的绝对路径复制到参数<a href="https://so.csdn.net/so/search?q=buffer&spm=1001.2101.3001.7020">buffer</a>所指的内存空间中,参数size为buf的空间大小。</p><p>如果未传入文件或目录，就需要对当前路径下的文件进行操作.所以需要用到该函数.</p><hr><p>现在已经获取到需要执行的参数和文件，接下来就需要进行参数操作.</p><p>所有参数中最难的就是递归部分，所以我们单独为-R封装一个函数来进行递归操作.</p><h2 id="do-open"><a href="#do-open" class="headerlink" title="do_open"></a>do_open</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fileinfo</span>//由于-<span class="title">l</span>需要输出文件的详细信息，所以需要结构体来存储信息</span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> i_node;</span><br><span class="line">    <span class="type">char</span> permission[<span class="number">16</span>];</span><br><span class="line">    <span class="type">short</span> owner;</span><br><span class="line">    <span class="type">short</span> group;</span><br><span class="line">    <span class="type">off_t</span> size;</span><br><span class="line">    <span class="type">time_t</span> c_ctime;</span><br><span class="line">    <span class="type">time_t</span> m_ctime;</span><br><span class="line">    <span class="type">nlink_t</span> link_num;</span><br><span class="line">    <span class="type">char</span> name[MAX_PATH];</span><br><span class="line">    <span class="type">mode_t</span> mode;</span><br><span class="line">    <span class="type">blkcnt_t</span> block;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">do_open</span><span class="params">(<span class="type">char</span> *path, <span class="type">int</span> orders[])</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">fileinfo</span> <span class="title">infos</span>[<span class="title">MAX_FILE</span>];</span><span class="comment">//我们的-s -t -r参数需要对文件进行排序，那么我们就需要数组来存储文件相关信息。</span></span><br><span class="line">    <span class="keyword">if</span> (orders[a])</span><br><span class="line">    &#123;</span><br><span class="line">        ls_a(path, infos, &amp;count);<span class="comment">//ls-用来打开文件以及存储文件名称</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (orders[a] == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        only_ls(path, infos, &amp;count);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (orders[t])</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo), cmp_time);<span class="comment">//对存储的信息进行相关的排序.t的优先级高于s</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ((orders[s] == <span class="number">1</span>) &amp;&amp; (orders[t] == <span class="number">0</span>))</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo), cmp_size);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ((orders[s] == <span class="number">0</span>) &amp;&amp; orders[t] == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo), cmp_name);<span class="comment">//按名称排序，使文字命名文件在前</span></span><br><span class="line">    &#125;</span><br><span class="line">    show_orders(infos, count, orders);<span class="comment">//最后进行输出.</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>既然获取到了参数与文件，所以我们的do_open就需要接受这两类参数.</p><p>我们在do_open中进行文件打开，排序参数，以及展示.</p><p>count参数用于计数文件个数，便于输出结果.</p><h2 id="do-open-R"><a href="#do-open-R" class="headerlink" title="do_open_R"></a>do_open_R</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line">void do_open_R(char *path, int orders[])</span><br><span class="line">&#123;</span><br><span class="line">    int count = 0;</span><br><span class="line">    struct fileinfo *infos = (struct fileinfo *)malloc(sizeof(struct fileinfo) * MAX_RFILE);</span><br><span class="line">    if (infos == NULL)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(&quot;malloc&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    if (orders[a])</span><br><span class="line">    &#123;</span><br><span class="line">        ls_a(path, infos, &amp;count);</span><br><span class="line">    &#125;</span><br><span class="line">    if (orders[a] == 0)</span><br><span class="line">    &#123;</span><br><span class="line">        only_ls(path, infos, &amp;count);</span><br><span class="line">    &#125;</span><br><span class="line">    if (orders[t])</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, sizeof(struct fileinfo), cmp_time);</span><br><span class="line">    &#125;</span><br><span class="line">    if ((orders[s] == 1) &amp;&amp; (orders[t] == 0))</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, sizeof(struct fileinfo), cmp_size);</span><br><span class="line">    &#125;</span><br><span class="line">    if ((orders[s] == 0) &amp;&amp; orders[t] == 0)</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, sizeof(struct fileinfo), cmp_name);</span><br><span class="line">    &#125;</span><br><span class="line">    show_orders(infos, count, orders);</span><br><span class="line">    for (int i = 0; i &lt; count; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        if (S_ISDIR(infos[i].mode) &amp;&amp; strcmp(infos[i].name, &quot;.&quot;) != 0 &amp;&amp; strcmp(infos[i].name, &quot;..&quot;) != 0)</span><br><span class="line">        &#123;</span><br><span class="line">            char sub_path[MAX_PATH];</span><br><span class="line">            snprintf(sub_path, sizeof(sub_path), &quot;%s/%s&quot;, path, infos[i].name);</span><br><span class="line">            struct stat flag;</span><br><span class="line">            if (lstat(sub_path, &amp;flag) == -1)</span><br><span class="line">            &#123;</span><br><span class="line">                fprintf(stderr, &quot;Permission denied or error reading: %s\n&quot;, sub_path);</span><br><span class="line">                continue;</span><br><span class="line">            &#125;</span><br><span class="line">            if(S_ISLNK(flag.st_mode))</span><br><span class="line">            &#123;</span><br><span class="line">                continue;</span><br><span class="line">            &#125;</span><br><span class="line">            do_open_R(sub_path,orders);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    free(infos);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>由于-R参数需要递归，所以采取堆上开辟空间进行存储</strong></p><p>这里多了一个判断，如果存储的路径对应的仍为目录，则需要继续进行简单的do_open操作。</p><p>所以S_ISDIR用来判断是否是目录，如果是则进行递归操作。</p><p>S_ISLNK用来判断文件是否为符号链接，如果不加该判断，会在对 &#x2F; 目录下&#x2F;dev&#x2F;fd中的符号链接进行叠加路径而出现错误.</p><h2 id="ls-a"><a href="#ls-a" class="headerlink" title="ls_a"></a>ls_a</h2><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">ls_a</span><span class="params">(<span class="type">char</span> *path, <span class="keyword">struct</span> fileinfo *infos, <span class="type">int</span> *count)</span></span><br><span class="line">&#123;</span><br><span class="line">    DIR *dir;<span class="comment">//接收opendir的返回值.</span></span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">dirent</span> *<span class="title">dirp</span>;</span><span class="comment">//readdir的返回值</span></span><br><span class="line">    <span class="keyword">if</span> ((dir = opendir(path)) == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%s\n&quot;</span>, path);</span><br><span class="line">        <span class="keyword">return</span> ;</span><br><span class="line">    &#125;</span><br><span class="line">    *count = <span class="number">0</span>;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">stat</span> <span class="title">st</span>;</span></span><br><span class="line">    <span class="keyword">while</span> ((dirp = readdir(dir)) != <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">char</span> current_path[MAX_PATH];</span><br><span class="line">        <span class="built_in">snprintf</span>(current_path, <span class="keyword">sizeof</span>(current_path), <span class="string">&quot;%s/%s&quot;</span>, path, dirp-&gt;d_name);</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> ((stat(current_path, &amp;st)) != <span class="number">-1</span>)<span class="comment">//存储文件的相关信息。</span></span><br><span class="line">        &#123;</span><br><span class="line">            </span><br><span class="line">            <span class="built_in">strncpy</span>(infos[*count].name, dirp-&gt;d_name, <span class="keyword">sizeof</span>(infos[*count].name) - <span class="number">1</span>);</span><br><span class="line">            infos[*count].name[<span class="keyword">sizeof</span>(infos[*count].name) - <span class="number">1</span>] = <span class="string">&#x27;\0&#x27;</span>;  <span class="comment">// Null-terminate the string</span></span><br><span class="line">            infos[*count].group = st.st_gid;</span><br><span class="line">            infos[*count].owner = st.st_uid;</span><br><span class="line">            infos[*count].mode = st.st_mode;</span><br><span class="line">            infos[*count].c_ctime = st.st_ctime;</span><br><span class="line">            infos[*count].size = st.st_size;</span><br><span class="line">            infos[*count].m_ctime = st.st_mtime;</span><br><span class="line">            infos[*count].i_node = st.st_ino;</span><br><span class="line">            mode_to_letters(st.st_mode, infos[*count].permission);</span><br><span class="line">            infos[*count].link_num = st.st_nlink;</span><br><span class="line">            infos[*count].block=st.st_blocks;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            perror(<span class="string">&quot;stat&quot;</span>);</span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        (*count)++;</span><br><span class="line">    &#125;</span><br><span class="line">    closedir(dir);<span class="comment">//一定要记得关闭文件</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>由于需要将信息进行存储，所以ls_a需要接收结构体数组，count 用于记录文件个数.</p><h3 id="opendir"><a href="#opendir" class="headerlink" title="opendir"></a>opendir</h3><p>opendir()函数用于打开一个目录，并返回指向该目录的句柄，供后续操作使用。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;dirent.h&gt;</span></span></span><br><span class="line">DIR * <span class="title function_">opendir</span><span class="params">(<span class="type">const</span> <span class="type">char</span> * dirpath)</span>;</span><br><span class="line">Returns directory stream handlc,or <span class="literal">NULL</span> on error</span><br></pre></td></tr></table></figure><h3 id="readdir"><a href="#readdir" class="headerlink" title="readdir"></a>readdir</h3><p>readdir()函数从一个目录流中读取连续的条目.</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;dirent.h&gt;</span></span></span><br><span class="line"><span class="keyword">struct</span> dirent *<span class="title function_">readdir</span><span class="params">(DIR * dirp)</span>;</span><br><span class="line">Returns pointer to a statically allocated structure describing next directory entry,or <span class="literal">NULL</span> on end-of-directory or error</span><br></pre></td></tr></table></figure><p>每调用 readdir()一次，就会从 dirp 所指代的目录流中读取下一目录条目，并返回一枚指针， 指向经静态分配而得的 dirent 类型结构，内含与该条目相关的如下信息： 每次调用 readdir()都会覆盖该结构。</p><h3 id="closedir"><a href="#closedir" class="headerlink" title="closedir"></a>closedir</h3><p>closedir()函数用于关闭处于打开状态的目录，同时释放它所使用的资源.(一定要记得关闭文件，否则就会造成内存泄漏).</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> <span class="title function_">closedir</span><span class="params">(DIR *dirp)</span>;</span><br></pre></td></tr></table></figure><h3 id="stat-获取文件信息"><a href="#stat-获取文件信息" class="headerlink" title="stat (获取文件信息)"></a>stat (获取文件信息)</h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span> </span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span> </span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span> </span></span><br><span class="line"> </span><br><span class="line"><span class="type">int</span> <span class="title function_">stat</span><span class="params">(<span class="type">const</span> <span class="type">char</span> *pathname, <span class="keyword">struct</span> stat *buf)</span>; </span><br></pre></td></tr></table></figure><p>函数参数及返回值含义如下：</p><blockquote><ul><li>pathname：用于指定一个需要查看属性的文件路径。</li><li>buf：struct stat 类型指针，用于指向一个 struct stat 结构体变量。调用 stat 函数的时候需要传入一个 struct stat 变量的指针，获取到的文件属性信息就记录在 struct stat 结构体中。</li><li>返回值：成功返回 0；失败返回-1，并设置 error。</li></ul></blockquote><h4 id="struct-stat"><a href="#struct-stat" class="headerlink" title="struct stat"></a>struct stat</h4><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">stat</span> </span></span><br><span class="line"><span class="class">&#123;</span> </span><br><span class="line"> <span class="type">dev_t</span> st_dev; <span class="comment">/* 文件所在设备的 ID */</span> </span><br><span class="line"> <span class="type">ino_t</span> st_ino; <span class="comment">/* 文件对应 inode 节点编号 */</span> </span><br><span class="line"> <span class="type">mode_t</span> st_mode; <span class="comment">/* 文件对应的模式 */</span> </span><br><span class="line"> <span class="type">nlink_t</span> st_nlink; <span class="comment">/* 文件的链接数 */</span> </span><br><span class="line"> <span class="type">uid_t</span> st_uid; <span class="comment">/* 文件所有者的用户 ID */</span> </span><br><span class="line"> <span class="type">gid_t</span> st_gid; <span class="comment">/* 文件所有者的组 ID */</span> </span><br><span class="line"> <span class="type">dev_t</span> st_rdev; <span class="comment">/* 设备号（指针对设备文件） */</span> </span><br><span class="line"> <span class="type">off_t</span> st_size; <span class="comment">/* 文件大小（以字节为单位） */</span> </span><br><span class="line"> <span class="type">blksize_t</span> st_blksize; <span class="comment">/* 文件内容存储的块大小 */</span> </span><br><span class="line"> <span class="type">blkcnt_t</span> st_blocks; <span class="comment">/* 文件内容所占块数 */</span> </span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">timespec</span> <span class="title">st_atim</span>;</span> <span class="comment">/* 文件最后被访问的时间 */</span> </span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">timespec</span> <span class="title">st_mtim</span>;</span> <span class="comment">/* 文件内容最后被修改的时间 */</span> </span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">timespec</span> <span class="title">st_ctim</span>;</span> <span class="comment">/* 文件状态最后被改变的时间 */</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h2 id="snprintf"><a href="#snprintf" class="headerlink" title="snprintf"></a>snprintf</h2><p><code>snprintf</code> 是一个 C 语言标准库函数，用于格式化字符串并将结果存储到一个字符数组中</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">snprintf</span><span class="params">(<span class="type">char</span> *str, <span class="type">size_t</span> size, <span class="type">const</span> <span class="type">char</span> *format, ...)</span></span>;</span><br></pre></td></tr></table></figure><ul><li><code>tr</code>: 指向存储结果的字符数组的指针。</li><li><code>size</code>: 最大允许写入的字符数（包括字符串终止符）。</li><li><code>format</code>: 格式化字符串，包含了要被写入到字符串中的文本和格式说明符。</li><li><code>...</code>: 可变数量的参数，用于替换格式字符串中的格式说明符。</li></ul><p><code>snprintf</code> 的行为类似于 <code>printf</code>，但是它会限制输出字符的数量，以防止溢出缓冲区。如果成功，<code>snprintf</code> 返回写入字符的总数（不包括字符串终止符），如果输出被截断，它会返回实际尝试写入的字符数。如果发生错误，返回负值。</p><h1 id="完整代码"><a href="#完整代码" class="headerlink" title="完整代码"></a>完整代码</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdlib.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;dirent.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/types.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/stat.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;string.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pwd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;grp.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;time.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;unistd.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;locale.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;ctype.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/ioctl.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdbool.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;getopt.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;error.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MAX_PATH 1024</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MAX_FILE 512</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MAX_RFILE 60000</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">order</span> &#123;</span></span><br><span class="line">    a, s, t, r, I, l, R</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">fileinfo</span></span></span><br><span class="line"><span class="class">&#123;</span></span><br><span class="line">    <span class="type">unsigned</span> <span class="type">int</span> i_node;</span><br><span class="line">    <span class="type">char</span> permission[<span class="number">16</span>];</span><br><span class="line">    <span class="type">short</span> owner;</span><br><span class="line">    <span class="type">short</span> group;</span><br><span class="line">    <span class="type">off_t</span> size;</span><br><span class="line">    <span class="type">time_t</span> c_ctime;</span><br><span class="line">    <span class="type">time_t</span> m_ctime;</span><br><span class="line">    <span class="type">nlink_t</span> link_num;</span><br><span class="line">    <span class="type">char</span> name[MAX_PATH];</span><br><span class="line">    <span class="type">mode_t</span> mode;</span><br><span class="line">    <span class="type">blkcnt_t</span> block;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">do_open</span><span class="params">(<span class="type">char</span> *path, <span class="type">int</span> orders[])</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">ls_a</span><span class="params">(<span class="type">char</span> *path, <span class="keyword">struct</span> fileinfo *infos, <span class="type">int</span> *count)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">only_ls</span><span class="params">(<span class="type">char</span> *path, <span class="keyword">struct</span> fileinfo *infos, <span class="type">int</span> *count)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">mode_to_letters</span><span class="params">(<span class="type">mode_t</span> mode, <span class="type">char</span> modestr[])</span>;</span><br><span class="line"><span class="type">int</span> <span class="title function_">cmp_name</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *a, <span class="type">const</span> <span class="type">void</span> *b)</span>;</span><br><span class="line"><span class="type">int</span> <span class="title function_">cmp_time</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *a, <span class="type">const</span> <span class="type">void</span> *b)</span>;</span><br><span class="line"><span class="type">int</span> <span class="title function_">cmp_size</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *a, <span class="type">const</span> <span class="type">void</span> *b)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">show_orders</span><span class="params">(<span class="keyword">struct</span> fileinfo *infos, <span class="type">int</span> count, <span class="type">int</span> orders[])</span>;</span><br><span class="line"><span class="type">char</span> *<span class="title function_">uid_to_name</span><span class="params">(<span class="type">uid_t</span> uid)</span>;</span><br><span class="line"><span class="type">char</span> *<span class="title function_">gid_to_name</span><span class="params">(<span class="type">gid_t</span> gid)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">do_open_R</span><span class="params">(<span class="type">char</span> *path, <span class="type">int</span> orders[])</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">print</span><span class="params">(<span class="keyword">struct</span> fileinfo infos)</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> find = <span class="number">0</span>;</span><br><span class="line">    <span class="type">int</span> orders[<span class="number">8</span>] = &#123;<span class="number">0</span>&#125;;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; argc; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (argv[i][<span class="number">0</span>] == <span class="string">&#x27;-&#x27;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">while</span> ((find = getopt(argc, argv, <span class="string">&quot;aIlrstR&quot;</span>)) != <span class="number">-1</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">switch</span> (find)</span><br><span class="line">                &#123;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;a&#x27;</span>:</span><br><span class="line">                    orders[a] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;r&#x27;</span>:</span><br><span class="line">                    orders[r] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;s&#x27;</span>:</span><br><span class="line">                    orders[s] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;t&#x27;</span>:</span><br><span class="line">                    orders[t] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;l&#x27;</span>:</span><br><span class="line">                    orders[l] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;R&#x27;</span>:</span><br><span class="line">                    orders[R] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;I&#x27;</span>:</span><br><span class="line">                    orders[I] = <span class="number">1</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                <span class="keyword">default</span>:</span><br><span class="line">                    <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Invalid option\n&quot;</span>);</span><br><span class="line">                    <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> countfile = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; argc; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (argv[i][<span class="number">0</span>] != <span class="string">&#x27;-&#x27;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            countfile++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (countfile == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">char</span> current_path[MAX_PATH];</span><br><span class="line">        <span class="keyword">if</span> ((getcwd(current_path, MAX_PATH)) != <span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (orders[R] == <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                do_open(current_path, orders);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                do_open_R(current_path, orders);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            perror(<span class="string">&quot;getcwd&quot;</span>);</span><br><span class="line">            <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">1</span>; i &lt; argc; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (argv[i][<span class="number">0</span>] != <span class="string">&#x27;-&#x27;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (countfile &gt; <span class="number">1</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%s\n&quot;</span>, argv[i]);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (orders[R] == <span class="number">0</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                do_open(argv[i], orders);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">else</span></span><br><span class="line">            &#123;</span><br><span class="line">                do_open_R(argv[i],orders);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">do_open</span><span class="params">(<span class="type">char</span> *path, <span class="type">int</span> orders[])</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">fileinfo</span> <span class="title">infos</span>[<span class="title">MAX_FILE</span>];</span></span><br><span class="line">    <span class="keyword">if</span> (orders[a])</span><br><span class="line">    &#123;</span><br><span class="line">        ls_a(path, infos, &amp;count);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (orders[a] == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        only_ls(path, infos, &amp;count);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (orders[t])</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo), cmp_time);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ((orders[s] == <span class="number">1</span>) &amp;&amp; (orders[t] == <span class="number">0</span>))</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo), cmp_size);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ((orders[s] == <span class="number">0</span>) &amp;&amp; orders[t] == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo), cmp_name);</span><br><span class="line">    &#125;</span><br><span class="line">    show_orders(infos, count, orders);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">do_open_R</span><span class="params">(<span class="type">char</span> *path, <span class="type">int</span> orders[])</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> count = <span class="number">0</span>;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">fileinfo</span> *<span class="title">infos</span> =</span> (<span class="keyword">struct</span> fileinfo *)<span class="built_in">malloc</span>(<span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo) * MAX_RFILE);</span><br><span class="line">    <span class="keyword">if</span> (infos == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        perror(<span class="string">&quot;malloc&quot;</span>);</span><br><span class="line">        <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (orders[a])</span><br><span class="line">    &#123;</span><br><span class="line">        ls_a(path, infos, &amp;count);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (orders[a] == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        only_ls(path, infos, &amp;count);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (orders[t])</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo), cmp_time);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ((orders[s] == <span class="number">1</span>) &amp;&amp; (orders[t] == <span class="number">0</span>))</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo), cmp_size);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ((orders[s] == <span class="number">0</span>) &amp;&amp; orders[t] == <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        qsort(infos, count, <span class="keyword">sizeof</span>(<span class="keyword">struct</span> fileinfo), cmp_name);</span><br><span class="line">    &#125;</span><br><span class="line">    show_orders(infos, count, orders);</span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; count; i++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (S_ISDIR(infos[i].mode) &amp;&amp; <span class="built_in">strcmp</span>(infos[i].name, <span class="string">&quot;.&quot;</span>) != <span class="number">0</span> &amp;&amp; <span class="built_in">strcmp</span>(infos[i].name, <span class="string">&quot;..&quot;</span>) != <span class="number">0</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="type">char</span> sub_path[MAX_PATH];</span><br><span class="line">            <span class="built_in">snprintf</span>(sub_path, <span class="keyword">sizeof</span>(sub_path), <span class="string">&quot;%s/%s&quot;</span>, path, infos[i].name);</span><br><span class="line">            <span class="class"><span class="keyword">struct</span> <span class="title">stat</span> <span class="title">flag</span>;</span></span><br><span class="line">            <span class="keyword">if</span> (lstat(sub_path, &amp;flag) == <span class="number">-1</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">&quot;Permission denied or error reading: %s\n&quot;</span>, sub_path);</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(S_ISLNK(flag.st_mode))</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            do_open_R(sub_path,orders);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">free</span>(infos);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">ls_a</span><span class="params">(<span class="type">char</span> *path, <span class="keyword">struct</span> fileinfo *infos, <span class="type">int</span> *count)</span></span><br><span class="line">&#123;</span><br><span class="line">    DIR *dir;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">dirent</span> *<span class="title">dirp</span>;</span></span><br><span class="line">    <span class="keyword">if</span> ((dir = opendir(path)) == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%s\n&quot;</span>, path);</span><br><span class="line">        <span class="keyword">return</span> ;</span><br><span class="line">    &#125;</span><br><span class="line">    *count = <span class="number">0</span>;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">stat</span> <span class="title">st</span>;</span></span><br><span class="line">    <span class="keyword">while</span> ((dirp = readdir(dir)) != <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">char</span> current_path[MAX_PATH];</span><br><span class="line">        <span class="built_in">snprintf</span>(current_path, <span class="keyword">sizeof</span>(current_path), <span class="string">&quot;%s/%s&quot;</span>, path, dirp-&gt;d_name);</span><br><span class="line">        </span><br><span class="line">        <span class="keyword">if</span> ((stat(current_path, &amp;st)) != <span class="number">-1</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            </span><br><span class="line">            <span class="built_in">strncpy</span>(infos[*count].name, dirp-&gt;d_name, <span class="keyword">sizeof</span>(infos[*count].name) - <span class="number">1</span>);</span><br><span class="line">            infos[*count].name[<span class="keyword">sizeof</span>(infos[*count].name) - <span class="number">1</span>] = <span class="string">&#x27;\0&#x27;</span>;  <span class="comment">// Null-terminate the string</span></span><br><span class="line">            infos[*count].group = st.st_gid;</span><br><span class="line">            infos[*count].owner = st.st_uid;</span><br><span class="line">            infos[*count].mode = st.st_mode;</span><br><span class="line">            infos[*count].c_ctime = st.st_ctime;</span><br><span class="line">            infos[*count].size = st.st_size;</span><br><span class="line">            infos[*count].m_ctime = st.st_mtime;</span><br><span class="line">            infos[*count].i_node = st.st_ino;</span><br><span class="line">            mode_to_letters(st.st_mode, infos[*count].permission);</span><br><span class="line">            infos[*count].link_num = st.st_nlink;</span><br><span class="line">            infos[*count].block=st.st_blocks;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            perror(<span class="string">&quot;stat&quot;</span>);</span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        (*count)++;</span><br><span class="line">    &#125;</span><br><span class="line">    closedir(dir);<span class="comment">//一定要记得关闭文件</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">only_ls</span><span class="params">(<span class="type">char</span> *path, <span class="keyword">struct</span> fileinfo *infos, <span class="type">int</span> *count)</span></span><br><span class="line">&#123;</span><br><span class="line">    DIR *dir;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">dirent</span> *<span class="title">dirp</span>;</span></span><br><span class="line">    <span class="keyword">if</span> ((dir = opendir(path)) == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%s\n&quot;</span>, path);</span><br><span class="line">        <span class="keyword">return</span> ;</span><br><span class="line">    &#125;</span><br><span class="line">    *count = <span class="number">0</span>;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">stat</span> <span class="title">st</span>;</span></span><br><span class="line">    <span class="keyword">while</span> ((dirp = readdir(dir)) != <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span> (dirp-&gt;d_name[<span class="number">0</span>] != <span class="string">&#x27;.&#x27;</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="type">char</span> current_path[MAX_PATH];</span><br><span class="line">            <span class="built_in">snprintf</span>(current_path, <span class="keyword">sizeof</span>(current_path), <span class="string">&quot;%s/%s&quot;</span>, path, dirp-&gt;d_name);</span><br><span class="line">            <span class="keyword">if</span> ((stat(current_path, &amp;st)) != <span class="number">-1</span>)</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">snprintf</span>(infos[*count].name, <span class="keyword">sizeof</span>(infos[*count].name), <span class="string">&quot;%s&quot;</span>, dirp-&gt;d_name);</span><br><span class="line">                infos[*count].group = st.st_gid;</span><br><span class="line">                infos[*count].owner = st.st_uid;</span><br><span class="line">                infos[*count].mode = st.st_mode;</span><br><span class="line">                infos[*count].c_ctime = st.st_ctime;</span><br><span class="line">                infos[*count].size = st.st_size;</span><br><span class="line">                infos[*count].m_ctime = st.st_mtime;</span><br><span class="line">                infos[*count].i_node = st.st_ino;</span><br><span class="line">                mode_to_letters(st.st_mode, infos[*count].permission);</span><br><span class="line">                infos[*count].link_num = st.st_nlink;</span><br><span class="line">                infos[*count].block = st.st_blocks;</span><br><span class="line">            &#125;</span><br><span class="line">            (*count)++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    closedir(dir);<span class="comment">//一定要记得及时释放</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">mode_to_letters</span><span class="params">(<span class="type">mode_t</span> mode, <span class="type">char</span> modestr[])</span> &#123;</span><br><span class="line">    <span class="built_in">strcpy</span>(modestr, <span class="string">&quot;----------&quot;</span>);</span><br><span class="line">    <span class="keyword">if</span> (S_ISDIR(mode)) modestr[<span class="number">0</span>] = <span class="string">&#x27;d&#x27;</span>;</span><br><span class="line">    <span class="keyword">if</span> (S_ISCHR(mode)) modestr[<span class="number">0</span>] = <span class="string">&#x27;c&#x27;</span>;</span><br><span class="line">    <span class="keyword">if</span> (S_ISBLK(mode)) modestr[<span class="number">0</span>] = <span class="string">&#x27;b&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (mode &amp; S_IRUSR) modestr[<span class="number">1</span>] = <span class="string">&#x27;r&#x27;</span>;</span><br><span class="line">    <span class="keyword">if</span> (mode &amp; S_IWUSR) modestr[<span class="number">2</span>] = <span class="string">&#x27;w&#x27;</span>;</span><br><span class="line">    <span class="keyword">if</span> (mode &amp; S_IXUSR) modestr[<span class="number">3</span>] = <span class="string">&#x27;x&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (mode &amp; S_IRGRP) modestr[<span class="number">4</span>] = <span class="string">&#x27;r&#x27;</span>;</span><br><span class="line">    <span class="keyword">if</span> (mode &amp; S_IWGRP) modestr[<span class="number">5</span>] = <span class="string">&#x27;w&#x27;</span>;</span><br><span class="line">    <span class="keyword">if</span> (mode &amp; S_IXGRP) modestr[<span class="number">6</span>] = <span class="string">&#x27;x&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (mode &amp; S_IROTH) modestr[<span class="number">7</span>] = <span class="string">&#x27;r&#x27;</span>;</span><br><span class="line">    <span class="keyword">if</span> (mode &amp; S_IWOTH) modestr[<span class="number">8</span>] = <span class="string">&#x27;w&#x27;</span>;</span><br><span class="line">    <span class="keyword">if</span> (mode &amp; S_IXOTH) modestr[<span class="number">9</span>] = <span class="string">&#x27;x&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">cmp_name</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *a, <span class="type">const</span> <span class="type">void</span> *b)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> *name_a = ((<span class="keyword">struct</span> fileinfo *)a)-&gt;name;</span><br><span class="line">    <span class="type">const</span> <span class="type">char</span> *name_b = ((<span class="keyword">struct</span> fileinfo *)b)-&gt;name;</span><br><span class="line">    setlocale(LC_COLLATE, <span class="string">&quot;&quot;</span>);</span><br><span class="line">    <span class="keyword">return</span> strcoll(name_a, name_b);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">cmp_size</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *a, <span class="type">const</span> <span class="type">void</span> *b)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">off_t</span> size_a = ((<span class="keyword">struct</span> fileinfo *)a)-&gt;size;</span><br><span class="line">    <span class="type">off_t</span> size_b = ((<span class="keyword">struct</span> fileinfo *)b)-&gt;size;</span><br><span class="line">    <span class="keyword">return</span> size_a &gt; size_b ? (size_a &lt; size_b ? <span class="number">-1</span> : <span class="number">0</span>) : <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">cmp_time</span><span class="params">(<span class="type">const</span> <span class="type">void</span> *a, <span class="type">const</span> <span class="type">void</span> *b)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">time_t</span> time_a = ((<span class="keyword">struct</span> fileinfo *)a)-&gt;m_ctime;</span><br><span class="line">    <span class="type">time_t</span> time_b = ((<span class="keyword">struct</span> fileinfo *)b)-&gt;m_ctime;</span><br><span class="line">    <span class="keyword">return</span> time_a &gt; time_b ? (time_a &lt; time_b ? <span class="number">-1</span> : <span class="number">0</span>) : <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">show_orders</span><span class="params">(<span class="keyword">struct</span> fileinfo *infos, <span class="type">int</span> count, <span class="type">int</span> orders[])</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">long</span> <span class="type">long</span> total = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span>(orders[l])</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; count; i++)</span><br><span class="line">        &#123;</span><br><span class="line">            total+=infos[i].block/<span class="number">2</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;总计 : %-11ld\n&quot;</span>, total);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (orders[r])</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = count - <span class="number">1</span>; i &gt;= <span class="number">0</span>; i--)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (orders[I])</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%-8d&quot;</span>, infos[i].i_node);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(orders[s])</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%-8d&quot;</span>, infos[i].block/<span class="number">2</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (orders[l])</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%s &quot;</span>, infos[i].permission);</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%4d &quot;</span>, (<span class="type">int</span>)infos[i].link_num);</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%-8s &quot;</span>, uid_to_name(infos[i].owner));</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%-8s &quot;</span>, gid_to_name(infos[i].group));</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%8ld &quot;</span>, infos[i].size);</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%.12s &quot;</span>, ctime(&amp;infos[i].c_ctime) + <span class="number">4</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            print(infos[i]);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> i = <span class="number">0</span>; i &lt; count; i++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">if</span> (orders[I])</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%-8d&quot;</span>, infos[i].i_node);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(orders[s])</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%-8d&quot;</span>, infos[i].block/<span class="number">2</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (orders[l])</span><br><span class="line">            &#123;</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%s &quot;</span>, infos[i].permission);</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%4d &quot;</span>, (<span class="type">int</span>)infos[i].link_num);</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%-8s &quot;</span>, uid_to_name(infos[i].owner));</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%-8s &quot;</span>, gid_to_name(infos[i].group));</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%8ld &quot;</span>, infos[i].size);</span><br><span class="line">                <span class="built_in">printf</span>(<span class="string">&quot;%.12s &quot;</span>, ctime(&amp;infos[i].c_ctime) + <span class="number">4</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            print(infos[i]);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">char</span> *<span class="title function_">uid_to_name</span><span class="params">(<span class="type">uid_t</span> uid)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="class"><span class="keyword">struct</span> <span class="title">passwd</span> *<span class="title">pw_ptr</span>;</span></span><br><span class="line">    pw_ptr = getpwuid(uid);</span><br><span class="line">    <span class="keyword">if</span> (pw_ptr == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">static</span> <span class="type">char</span> numstr[<span class="number">10</span>];</span><br><span class="line">        <span class="built_in">snprintf</span>(numstr, <span class="keyword">sizeof</span>(numstr), <span class="string">&quot;%d&quot;</span>, uid);</span><br><span class="line">        <span class="keyword">return</span> numstr;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> pw_ptr-&gt;pw_name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">char</span> *<span class="title function_">gid_to_name</span><span class="params">(<span class="type">gid_t</span> gid)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">struct</span> group *<span class="title function_">getgrgid</span><span class="params">()</span>, *grp_ptr;</span><br><span class="line">    <span class="type">static</span> <span class="type">char</span> numstr[<span class="number">10</span>];</span><br><span class="line">    <span class="keyword">if</span> ((grp_ptr = getgrgid(gid)) == <span class="literal">NULL</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="built_in">sprintf</span>(numstr, <span class="string">&quot;%d&quot;</span>, gid);</span><br><span class="line">        <span class="keyword">return</span> numstr;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> grp_ptr-&gt;gr_name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">print</span><span class="params">(<span class="keyword">struct</span> fileinfo infos)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">if</span> (S_ISREG(infos.mode))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// Regular file</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">strstr</span>(infos.name, <span class="string">&quot;.c&quot;</span>) != <span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// .c file, print in a different color</span></span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;\033[40;32m %s\033[0m\n&quot;</span>, infos.name);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strstr</span>(infos.name, <span class="string">&quot;.out&quot;</span>) != <span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// .out file, print in another color</span></span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;\033[40;33m %s\033[0m\n&quot;</span>, infos.name);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// Other regular file</span></span><br><span class="line">            <span class="built_in">printf</span>(<span class="string">&quot;%s\n&quot;</span>, infos.name);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span> <span class="keyword">if</span> (S_ISDIR(infos.mode))</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// Directory</span></span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;\033[40;34m %s\033[0m\n&quot;</span>, infos.name);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// Other file types</span></span><br><span class="line">        <span class="built_in">printf</span>(<span class="string">&quot;%s\n&quot;</span>, infos.name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;myls&quot;&gt;&lt;a href=&quot;#myls&quot; class=&quot;headerlink&quot; title=&quot;myls&quot;&gt;&lt;/a&gt;myls&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;ls&lt;/code&gt; 是一个常用的命令行工具，用于列出指定目录中的文件和子目录。&lt;cod</summary>
      
    
    
    
    <category term="plan" scheme="https://future.thisis.host/categories/plan/"/>
    
    
    <category term="linux" scheme="https://future.thisis.host/tags/linux/"/>
    
    <category term="plan" scheme="https://future.thisis.host/tags/plan/"/>
    
  </entry>
  
  <entry>
    <title>Learn Cpp</title>
    <link href="https://future.thisis.host/2024/03/04/%E5%88%9D%E8%AF%86C++/"/>
    <id>https://future.thisis.host/2024/03/04/%E5%88%9D%E8%AF%86C++/</id>
    <published>2024-03-04T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.356Z</updated>
    
    <content type="html"><![CDATA[<h1 id="C-初始"><a href="#C-初始" class="headerlink" title="C++初始"></a>C++初始</h1><h2 id="1-编写C-程序步骤"><a href="#1-编写C-程序步骤" class="headerlink" title="1.编写C++程序步骤"></a>1.编写C++程序步骤</h2><ul><li>创建项目</li><li>创建文件 </li><li>编写代码</li><li>运行程序</li></ul><h2 id="1-3变量"><a href="#1-3变量" class="headerlink" title="1.3变量"></a>1.3变量</h2><p><strong>作用</strong>：给一段指定的内存空间起名，方便操作这段内存</p><p><strong>语法</strong>：数据类型 变量名 &#x3D;初始值</p><h2 id="1-5关键字"><a href="#1-5关键字" class="headerlink" title="1.5关键字"></a>1.5关键字</h2><p>预先保留的单词</p><p>在定义变量或者常量的时候，不要用关键字</p><table><thead><tr><th>asm</th><th>do</th><th>if</th><th>return</th><th>typedef</th></tr></thead><tbody><tr><td>auto</td><td>dynamic_cast</td><td>inline</td><td>short</td><td>typeid</td></tr><tr><td>bool</td><td>else</td><td>int</td><td>signed</td><td>typename</td></tr><tr><td>break</td><td>enum</td><td>long</td><td>sizeof</td><td>union</td></tr><tr><td>case</td><td>explicit</td><td>mutable</td><td>static</td><td>unsigned</td></tr><tr><td>catch</td><td>export</td><td>namespace</td><td>static_cast</td><td>using</td></tr><tr><td>char</td><td>extern</td><td>new</td><td>struct</td><td>virtual</td></tr><tr><td>class</td><td>false</td><td>operator</td><td>switch</td><td>void</td></tr><tr><td>const</td><td>float</td><td>private</td><td>template</td><td>volatile</td></tr><tr><td>const_cast</td><td>for</td><td>protected</td><td>this</td><td>wchar_t</td></tr><tr><td>continue</td><td>friend</td><td>public</td><td>throw</td><td>while</td></tr><tr><td>default</td><td>goto</td><td>register</td><td>true</td><td></td></tr><tr><td>delete</td><td>double</td><td>reinterpret_cast</td><td>try</td><td></td></tr></tbody></table><h2 id="标识符命名规则"><a href="#标识符命名规则" class="headerlink" title="标识符命名规则"></a>标识符命名规则</h2><ul><li><p>标识符不能是关键字</p></li><li><p>标识符只能由字母，数字，下划线组成</p></li><li><p>第一个字符必须为字母或者下划线</p></li><li><p>标识符中区分大小写</p><blockquote><p>给标识符命名时，争取做到见名知意的效果，方便阅读</p></blockquote></li></ul><h2 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h2><h3 id="实型"><a href="#实型" class="headerlink" title="实型"></a>实型</h3><p><strong>作用</strong>：用于表示小数</p><p>浮点型变量分为两种：</p><ol><li>单精度float</li><li>双精度double</li></ol><p>两者的区别在与表示的有效数字范围不同.</p><table><thead><tr><th>数据类型</th><th>占用空间</th><th>有效数字范围</th></tr></thead><tbody><tr><td>float</td><td>4字节</td><td>7位有效数字</td></tr><tr><td>double</td><td>8字节</td><td>15 ~ 16位有效数字</td></tr></tbody></table><p>也可以用科学计数法表示.</p><h3 id="字符型"><a href="#字符型" class="headerlink" title="字符型"></a>字符型</h3><p><strong>作用</strong>：字符型变量用于显示单个字符</p><p><strong>语法</strong>：<code>char ch = &#39;a&#39;;</code></p><blockquote><p>注意1：在显示字符型变量时，用单引导将字符括起来，不要用双引号</p></blockquote><blockquote><p>注意2：单引号内只能有一个字符，不可以是字符串</p></blockquote><h2 id="字符串型"><a href="#字符串型" class="headerlink" title="字符串型"></a>字符串型</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//c风格的字符串</span></span><br><span class="line"><span class="type">char</span> str[]=<span class="string">&quot;helloworld&quot;</span>;</span><br><span class="line"><span class="comment">//c++风格的字符串</span></span><br><span class="line"><span class="comment">//要包含头文件</span></span><br><span class="line">string str=<span class="string">&quot;helloworld&quot;</span>;</span><br></pre></td></tr></table></figure><h2 id="布尔类型"><a href="#布尔类型" class="headerlink" title="布尔类型"></a>布尔类型</h2><p>本质上1代表真，0代表假</p><p>占一个字节.</p><h2 id="数据的输入"><a href="#数据的输入" class="headerlink" title="数据的输入"></a>数据的输入</h2><h3 id="关键字cin"><a href="#关键字cin" class="headerlink" title="关键字cin"></a>关键字cin</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//整形</span></span><br><span class="line"><span class="type">int</span> a =<span class="number">0</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;请输入整形变量:&quot;</span> &lt;&lt; endl;</span><br><span class="line">cin &gt;&gt; a;</span><br><span class="line">cout &lt;&lt; a &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line"><span class="comment">//浮点型</span></span><br><span class="line"><span class="type">double</span> a =<span class="number">0</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;请输入浮点型变量:&quot;</span> &lt;&lt; endl;</span><br><span class="line">cin &gt;&gt; a;</span><br><span class="line">cout &lt;&lt; a &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line"><span class="comment">//字符型</span></span><br><span class="line"><span class="type">char</span> a =<span class="number">0</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;请输入字符型变量:&quot;</span> &lt;&lt; endl;</span><br><span class="line">cin &gt;&gt; a;</span><br><span class="line">cout &lt;&lt; a &lt;&lt; endl;</span><br><span class="line"></span><br><span class="line"><span class="comment">//字符串型</span></span><br><span class="line">string a =<span class="number">0</span>;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;请输入字符串型变量:&quot;</span> &lt;&lt; endl;</span><br><span class="line">cin &gt;&gt; a;</span><br><span class="line">cout &lt;&lt; a &lt;&lt; endl;</span><br></pre></td></tr></table></figure><hr><p><strong>小数间是不能做取模运算的</strong></p><h2 id="程序流程结构"><a href="#程序流程结构" class="headerlink" title="程序流程结构"></a>程序流程结构</h2><blockquote><p>c&#x2F;c++支持最基本的三种程序运行结构：顺序结构、选择结构、循环结构</p><ul><li>顺序结构：程序按顺序执行，不发生跳转</li><li>选择结构：依据条件是否满足，有选择的执行相应功能</li><li>循环结构：依据条件是否满足，循环多次执行某段代码</li></ul></blockquote><h2 id="跳转语句"><a href="#跳转语句" class="headerlink" title="跳转语句"></a>跳转语句</h2><h3 id="break语句"><a href="#break语句" class="headerlink" title="break语句"></a>break语句</h3><p><strong>作用</strong>：用于跳出<code>选择结构</code>或者<code>循环结构</code></p><p>break使用的时机：</p><ul><li>出现在switch条件语句中，作用是终止case并跳出switch</li><li>出现在循环语句中，作用是跳出当前的循环语句</li><li>出现在嵌套循环中，跳出最近的内存循环语句</li></ul><h3 id="continue-语句"><a href="#continue-语句" class="headerlink" title="continue 语句"></a>continue 语句</h3><p><strong>作用</strong>：在<code>循环语句</code>中，跳出本次循环中余下尚未执行的语句，继续执行下一次循环</p><h2 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h2><p><strong>作用</strong>：将一段经常使用的代码封装起来，减少重复的代码</p><p>函数的定义一般主要有5步骤：</p><ol><li>返回值类型</li><li>函数名</li><li>参数列表</li><li>函数体语句</li><li>return 表达式</li></ol><h2 id="指针"><a href="#指针" class="headerlink" title="指针"></a>指针</h2><p><strong>空指针</strong>：指针变量指向内存中编号为0的空间</p><p><strong>用途</strong>：初始化指针变量</p><p>注意：空指针指向的内存是不可以访问的</p><h2 id="结构体"><a href="#结构体" class="headerlink" title="结构体"></a>结构体</h2><h1 id="核心编程"><a href="#核心编程" class="headerlink" title="核心编程"></a>核心编程</h1><h2 id="内存分区模型"><a href="#内存分区模型" class="headerlink" title="内存分区模型"></a>内存分区模型</h2><ul><li><p>代码区  存放CPU执行的机器指令   <strong>共享</strong> <strong>只读</strong> </p></li><li><p>全局区  </p><table><thead><tr><th>局部变量、const修饰的局部变量(局部变量)</th><th>不在全局区中</th></tr></thead><tbody><tr><td>全局变量  静态变量 static关键字 常量</td><td>全局区</td></tr></tbody></table></li><li><p>栈区</p><blockquote><p>不要返回局部变量的地址</p></blockquote></li><li><p>堆区</p><blockquote><p>在c++中主要利用new在堆区开辟内存</p></blockquote></li></ul><p><strong>意义</strong>：不同区域存放的数据，赋予不同的生命周期，给我们更大的灵活编程</p><h3 id="堆区"><a href="#堆区" class="headerlink" title="堆区"></a>堆区</h3><p>​C++中利用<code>new</code>操作符在堆区开辟数据</p><p>堆区开辟的数据由程序员手动开辟、手动释放、释放利用操作符delete</p><p>语法：<code>new 数据类型</code></p><p>利用new创建的数据，会返回该数据对应的类型的指针</p><p>new的基本语法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> *a=<span class="keyword">new</span> <span class="built_in">int</span>(<span class="number">10</span>);</span><br></pre></td></tr></table></figure><h1 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h1><p><strong>作用</strong>：给变量起别名</p><p><strong>语法</strong>：数据类型  &amp;别名 &#x3D;原名</p><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ul><li>引用必须要初始化</li><li>引用一旦初始化后，就不可以更改</li></ul><p>引用可以简化指针的用法.</p><p><strong>引用做函数参数</strong></p><p><strong>作用</strong>：函数传参时，可以利用引用的技术让形参修饰实参</p><p><strong>优点</strong>：可以简化指针修改实参</p><p>通过引用参数产生的效果按地址传递是一样的。引用的语法更加的简单。</p><p>引用是可以作为函数的返回值存在的.</p><p>不返回局部变量的引用. </p><p>函数的调用可以作为<strong>左值.</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> &amp;ref2=<span class="built_in">test02</span>();</span><br><span class="line"></span><br><span class="line"><span class="built_in">test02</span>()=<span class="number">1000</span>;</span><br></pre></td></tr></table></figure><p><strong>本质</strong>：引用的本质在c++内部实现是一个指针常量.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">(<span class="type">int</span> &amp;ref)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ref=<span class="number">100</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="comment">//自动转换为int *const ref = &amp;a;指针常量是指针指向不可改，也说明为什么引用不可以改</span></span><br><span class="line">    <span class="type">int</span> &amp;ref=a;</span><br><span class="line">    ref=<span class="number">20</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="built_in">func</span>(a);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>引用必须引一块合法的内存空间。</p><p>const修饰的局部变量不再全局区.</p><h2 id="函数-1"><a href="#函数-1" class="headerlink" title="函数"></a>函数</h2><h2 id="函数默认参数"><a href="#函数默认参数" class="headerlink" title="函数默认参数"></a>函数默认参数</h2><p>在c++中，函数的形参列表中的形参是可以有默认值的</p><p><strong>语法</strong> ：返回值类型  函数名 （参数&#x3D; 默认值） {}</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">int</span> <span class="title">func</span><span class="params">(<span class="type">int</span> a,<span class="type">int</span> b=<span class="number">10</span>,<span class="type">int</span> c=<span class="number">10</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="keyword">return</span> a+b+c;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//1.如果某个位置参数有默认值，那么这个位置往后，从左向右，必须都要有默认值</span></span><br><span class="line"><span class="comment">//2.如果函数声明有默认值，函数实现的时候就不能有默认值</span></span><br></pre></td></tr></table></figure><p>函数的默认参数，如果我们传入了参数，值就使用我们传入的参数，如果我们没有传入参数，那么就使用函数的默认参数值</p><p><strong>注意事项：</strong></p><ul><li>如果某个位置已经有了默认参数，那么这个位置往后，从左到右都必须要有默认值</li><li>如果函数声明有默认参数，函数实现就不能有默认参数</li><li>声明和实现只能一个有默认参数</li></ul><h2 id="函数占位参数"><a href="#函数占位参数" class="headerlink" title="函数占位参数"></a>函数占位参数</h2><p>c++中的函数的形参列表可以有占位参数，用来做占位，调用函数时必须填补该位置</p><p>语法：返回值类型 函数名 （数据类型） { }</p><p>目前占位参数我们还用不到.</p><p>占位参数还可以有默认参数.</p><h2 id="函数重载"><a href="#函数重载" class="headerlink" title="函数重载"></a>函数重载</h2><p><strong>作用：</strong>函数名可以相同，提高复用性</p><h3 id="满足条件"><a href="#满足条件" class="headerlink" title="满足条件"></a>满足条件</h3><ul><li>同一个作用域下</li><li>函数名称相同</li><li>函数参数类型不同 或者 个数不同 或者顺序不同</li></ul><p><strong>注意事项：</strong></p><ul><li><p>函数的返回值不可以作为函数重载的条件</p></li><li><p>引用作为重载的条件</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">fun</span><span class="params">(<span class="type">int</span> &amp;a)</span><span class="comment">//这两个可以作为函数重载的条件，因为函数的参数类型不同</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;func(int &amp;a)调用&quot;</span> &lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">fun</span><span class="params">(<span class="type">const</span> <span class="type">int</span> &amp;a)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;func(const int &amp;a)调用&quot;</span>&lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"> <span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="built_in">func</span>(a);<span class="comment">//调用的是第一个，因为这是一个变量.</span></span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">func</span><span class="params">(<span class="number">10</span>)</span></span>;<span class="comment">//调用的是第二个。</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>函数重载碰到默认参数(会出现二义性，尽量避免使用)</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">func2</span><span class="params">(<span class="type">int</span> a)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;func2(int a)的调用&quot;</span> &lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func2</span><span class="params">(<span class="type">int</span> a,<span class="type">int</span> b=<span class="number">10</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;func2(int a,int b)的调用&quot;</span> &lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">   <span class="built_in">func2</span>(<span class="number">10</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h1 id="类和对象"><a href="#类和对象" class="headerlink" title="类和对象"></a>类和对象</h1><p>c++面向对象的三大特性为：封装、继承、多态</p><p>c++认为万事万物都皆为对象，对象上有其属性和行为</p><p>具有相同性质的对象，我们可以抽象称为类，人属于人类，车属于车类</p><h2 id="封装"><a href="#封装" class="headerlink" title="封装"></a>封装</h2><h3 id="意义"><a href="#意义" class="headerlink" title="意义"></a>意义</h3><p>封装是c++面向对象的三大特性之一</p><ul><li>将属性和行为作为一个整体，表现生活中的事物</li><li>将属性和行为加以权限控制</li></ul><p>封装意义1：</p><p>在设计类的时候，属性和行为写在一起，表示事物</p><p>语法：class 类名 {   访问权限 ：   属性 &#x2F;行为  }；</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">const</span> <span class="type">double</span> PI =<span class="number">3.14</span>;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Circle</span> </span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">//访问权限</span></span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//圆的属性</span></span><br><span class="line">    <span class="type">int</span> m_r;</span><br><span class="line">    <span class="comment">//行为</span></span><br><span class="line">    <span class="comment">//获取周长</span></span><br><span class="line">    <span class="function"><span class="type">double</span> <span class="title">calculateZC</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">2</span>*PI*m_r;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="comment">//通过圆类 创建具体的圆（对象）</span></span><br><span class="line">    <span class="comment">//实例化(通过一个类  创建一个对象的过程) </span></span><br><span class="line">    Circle c1;</span><br><span class="line">    <span class="comment">//给圆对像的属性进行赋值、</span></span><br><span class="line">    c<span class="number">1.</span>m_r=<span class="number">10</span> ;</span><br><span class="line">    cout &lt;&lt; c<span class="number">1.</span><span class="built_in">calculateZC</span>()&lt;&lt;endl;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Student</span><span class="comment">//设计学生类</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span> :<span class="comment">//公共权限</span></span><br><span class="line">    <span class="comment">//类中的属性和行为  我们统称为 成员</span></span><br><span class="line">    <span class="comment">//属性 也成为 成员属性 成员变量</span></span><br><span class="line">    <span class="comment">//行为 也称为 成员函数 成员方法</span></span><br><span class="line">    <span class="comment">//属性 </span></span><br><span class="line">    string m_Name;</span><br><span class="line">    <span class="type">int</span> m_Id;</span><br><span class="line">    <span class="comment">//行为</span></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">show</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout&lt;&lt;<span class="string">&quot;姓名：  &quot;</span> &lt;&lt; m_Name &lt;&lt; <span class="string">&quot;学号 :&quot;</span> &lt;&lt; m_Id&lt;&lt;endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">set_name</span><span class="params">(string name)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_Name=name;</span><br><span class="line">&#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">set_Id</span><span class="params">(<span class="type">int</span> id)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_Id=id;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Student s1;</span><br><span class="line">    cin&gt;&gt;s<span class="number">1.</span>m_Name&gt;&gt;m_Id;</span><br><span class="line">    s<span class="number">1.</span><span class="built_in">show</span>();</span><br><span class="line">    Student s1;</span><br><span class="line">    s<span class="number">2.</span><span class="built_in">set_name</span>(<span class="string">&quot;张三&quot;</span>);</span><br><span class="line">    s<span class="number">2.</span><span class="built_in">set_Id</span>(<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>封装意义二：</p><p>类在设计时，可以把属性和行为放在不同的权限下，加以控制</p><p>三种权限：</p><p>1.public 公共权限</p><p>2.protected  保护权限</p><p>3.private私有权限</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//访问权限 三种</span></span><br><span class="line"><span class="comment">//公共权限public成员 类内可以访问 类外也可以访问</span></span><br><span class="line"><span class="comment">//保护权限protected成员 类内可以访问 类外不可以访问</span></span><br><span class="line"><span class="comment">//私有权限private成员 类内可以访问 类外不可以访问</span></span><br><span class="line"><span class="comment">//私有权限与保护权限的区别 在继承的时候可以区分 儿子可以访问父亲中的保护内容</span></span><br><span class="line"><span class="comment">//儿子不可以访问父亲的私有内容</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">string m_Name;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    string m_Car;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_Password;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_Name=<span class="string">&quot;张三&quot;</span>;</span><br><span class="line">        m_Car=<span class="string">&quot;饿狼传说&quot;</span>；</span><br><span class="line">        m_Password=<span class="number">123145</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="class-和-struct-的区别"><a href="#class-和-struct-的区别" class="headerlink" title="class 和 struct 的区别"></a>class 和 struct 的区别</h2><p>在c++中struct 和 class  唯一的区别就在于默认的访问权限不同</p><p><strong>区别：</strong></p><ul><li>struct默认权限为<strong>公共</strong></li><li>class          默认权限为<strong>私有</strong></li></ul><h2 id="成员属性设置为私有"><a href="#成员属性设置为私有" class="headerlink" title="成员属性设置为私有"></a>成员属性设置为私有</h2><p><strong>优点</strong>：</p><ul><li>将所有成员属性设置为私有，可以自己控制读写权限</li><li>由于写权限，我们可以检测数据的有效性</li></ul><p><strong>在类中可以让另外一个类作为类中本来的成员</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Point</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//在此实现成员函数</span></span><br><span class="line">    <span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_X;</span><br><span class="line">    <span class="type">int</span> m_Y;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">circle</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//在此实现成员函数</span></span><br><span class="line">    <span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_R;</span><br><span class="line">    Point m_Center;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//在头文件中可以进行类的声明</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Point</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">setx</span><span class="params">(<span class="type">int</span> x)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">sety</span><span class="params">(<span class="type">int</span> y)</span></span>;</span><br><span class="line">    <span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_X;</span><br><span class="line">    <span class="type">int</span> m_Y;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Circle</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">setm_R</span><span class="params">(<span class="type">int</span> r)</span></span>;</span><br><span class="line">    <span class="function"><span class="type">int</span> <span class="title">getr</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_R;</span><br><span class="line">    Point Center;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//在其余的文件定义该函数的时候需要加作用域</span></span><br><span class="line"><span class="type">void</span> Point:: <span class="built_in">setx</span>(<span class="type">int</span> x)</span><br><span class="line">&#123;</span><br><span class="line">    m_X=x;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="对象的初始化清理"><a href="#对象的初始化清理" class="headerlink" title="对象的初始化清理"></a>对象的初始化清理</h2><p>c++中的面向对象来源于生活 ，每个对象也都会有初始设置 以及对象销毁前的清理数据的设置。</p><h3 id="构造函数和析构函数"><a href="#构造函数和析构函数" class="headerlink" title="构造函数和析构函数"></a>构造函数和析构函数</h3><p>对象的<strong>初始化和清理</strong>也是两个非常重要的安全问题</p><p>​一个对象或者变量没有初始状态，对其使用后果未知</p><p>​同样的使用完一个对象或变量，没有及时清理，也会造成一定的安全问题</p><blockquote><p>c++利用了<strong>构造函数</strong>和<strong>析构函数</strong>解决上述问题，这两个函数将会被编译器自动调用，完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我们做的事情，因此如果<strong>我们不提供构造和析构，编译器会给我们提供空实现</strong></p></blockquote><p><strong>构造函数语法：</strong> 类名(){}</p><ol><li>构造函数，没有返回值也不写void</li><li>函数名称与类名相同</li><li>构造函数可以有参数，因此可以发生重载</li><li>程序在调用对象时候会自动调用构造，无需手动调用，而且只会调用一次</li></ol><p><strong>析构函数语法：</strong> <code>~类名()&#123;&#125;</code></p><ol><li>析构函数，没有返回值也不写void</li><li>函数名称与类名相同，在名称前加上符号~</li><li>析构函数不可以有参数，因此不可以发生重载</li><li>程序在对象销毁前自动调用析构，无需手动调用，而且只会调用一次</li></ol><p><strong>构造函数的分类及调用：</strong></p><ul><li><p>按参数</p><ul><li>有参构造</li><li>无参构造</li></ul></li><li><p>按类型</p><ul><li>普通构造</li><li>拷贝构造</li></ul></li></ul><p>三种调用方法：  </p><ul><li><p>括号法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Person P;<span class="comment">//默认构造时后面不要加括号</span></span><br><span class="line"><span class="function">Person <span class="title">p1</span><span class="params">(<span class="number">10</span>)</span></span>;</span><br><span class="line"><span class="function">Person <span class="title">p2</span><span class="params">(p1)</span></span>;</span><br></pre></td></tr></table></figure></li><li><p>显示法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Person p;</span><br><span class="line">Person p1=<span class="built_in">Person</span>(<span class="number">10</span>);</span><br><span class="line">Person P2=<span class="built_in">Person</span>(p2);</span><br></pre></td></tr></table></figure></li><li><p>隐式转换法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Person p4=<span class="number">10</span>;</span><br><span class="line">Person p5=p4;</span><br></pre></td></tr></table></figure></li></ul><p><strong>构造函数的调用顺序</strong>:</p><blockquote><p>1.当普通构造一个对象时，程序先自动调用默认构造函数分配空间，在调用自定义构造函数(如果有的话)</p><p>2.当拷贝构造一个对象时，程序先自动调用默认构造函数分配空间，然后分两种情况，如果程序有自定义拷贝函数，则调用自定义拷贝构造函数；如果没有，就调用默认拷贝构造函数进行浅拷贝.</p></blockquote><h3 id="拷贝构造函数调用时机"><a href="#拷贝构造函数调用时机" class="headerlink" title="拷贝构造函数调用时机"></a>拷贝构造函数调用时机</h3><p>c++拷贝构造函数调用时机</p><ul><li>使用一个创建完毕的对象来初始化一个新对象</li><li>值传递的方式给函数参数传值(做参数)</li><li>以值的方式返回局部对象(做返回值)</li></ul><h3 id="构造函数调用规则"><a href="#构造函数调用规则" class="headerlink" title="构造函数调用规则"></a>构造函数调用规则</h3><p>默认情况下，c++编译器至少给一个类添加3个函数</p><p>1.默认构造参数（无参，函数体为空）</p><p>2.默认析构函数（无参，函数体为空）</p><p>3.默认拷贝构造函数，对属性值进行拷贝</p><p><strong>规则如下：</strong></p><ul><li>如果用户定义有参构造函数，c++不在提供默认无参构造，但是会提供默认拷贝构造</li><li>如果用户定义拷贝构造函数，c++不会在提供其他的构造函数</li></ul><h3 id="深拷贝与浅拷贝"><a href="#深拷贝与浅拷贝" class="headerlink" title="深拷贝与浅拷贝"></a>深拷贝与浅拷贝</h3><p>浅拷贝：简单的赋值操作</p><p>深拷贝：在堆区重新申请空间，进行拷贝操作</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Person&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">Person</span>(<span class="type">int</span> a,<span class="type">int</span> height)</span><br><span class="line">    &#123;</span><br><span class="line">        m_age =a;</span><br><span class="line">        m_height= <span class="keyword">new</span> <span class="built_in">int</span>(height);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">Person</span>(<span class="type">const</span> Person &amp;other)</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Personkb&quot;</span> &lt;&lt; endl;</span><br><span class="line">        m_age = other.m_age;</span><br><span class="line">        m_height =<span class="keyword">new</span> <span class="built_in">int</span>(*other.m_height);<span class="comment">//深拷贝</span></span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">Person</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//析构，将堆区开辟的空间做释放操作</span></span><br><span class="line">        <span class="keyword">if</span>(m_height !=<span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span> m_height;</span><br><span class="line">        &#125;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Personxg&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> m_age;</span><br><span class="line">    <span class="type">int</span> *m_height; </span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Person <span class="title">p1</span><span class="params">(<span class="number">18</span>,<span class="number">160</span>)</span></span>;</span><br><span class="line">    cout &lt;&lt; p<span class="number">1.</span>m_age &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; *p<span class="number">1.</span>m_height &lt;&lt; endl;</span><br><span class="line">    <span class="function">Person <span class="title">p2</span><span class="params">(p1)</span></span>;</span><br><span class="line">    cout &lt;&lt; p<span class="number">2.</span>m_age &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; *p<span class="number">2.</span>m_height &lt;&lt;endl;<span class="comment">//会发生错误，因为p2是浅拷贝，但析构函数内部对p2进行了释放</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">test01</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>  会出现:free():double free detected in tcache 2.</p></blockquote><p>编译起提供的拷贝构造函数，只是简单的赋值，将原先的地址在复制一份。</p><p>所以需要深拷贝来解决该问题，自己实现拷贝构造函数</p><h3 id="初始化列表"><a href="#初始化列表" class="headerlink" title="初始化列表"></a>初始化列表</h3><p><strong>作用</strong>：c++提供了初始化列表语法，用来初始化（类的）属性</p><p><strong>语法</strong>：<code>构造函数( ): 属性1(值1),属性2(值2) ... &#123;&#125;</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//Person(int a,int b,int c)</span></span><br><span class="line">    <span class="comment">//&#123;</span></span><br><span class="line">    <span class="comment">//m_A=a;m_B=b;m_C=c;</span></span><br><span class="line"><span class="comment">//&#125;</span></span><br><span class="line">    <span class="built_in">Person</span>(<span class="type">int</span> a,<span class="type">int</span> b,<span class="type">int</span> c):<span class="built_in">m_A</span>(a),<span class="built_in">m_B</span>(b),<span class="built_in">m_C</span>(c)</span><br><span class="line">    &#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line">    <span class="type">int</span> m_B;</span><br><span class="line">    <span class="type">int</span> m_C;</span><br><span class="line">&#125;</span><br><span class="line"><span class="type">void</span> test</span><br><span class="line">&#123;</span><br><span class="line">    Person p;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">test</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>初始化const成员变量的唯一方法就是使用初始化列表</strong></p><h3 id="类对象作为类成员"><a href="#类对象作为类成员" class="headerlink" title="类对象作为类成员"></a>类对象作为类成员</h3><p>c++类中的成员可以是另一个类的对象，我们称该成员为对象成员</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">A</span>&#123;&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">B</span></span><br><span class="line">&#123;</span><br><span class="line">    A a;</span><br><span class="line">&#125;<span class="comment">//B类中有对象A作为成员，A为对象成员</span></span><br></pre></td></tr></table></figure><p>那么当创建B对象时，A与B的构造和析构的顺序是谁先谁后？</p><p>先构造A对象.</p><p>当其他类的对象作为本类成员，构造时先构造<strong>类对象</strong>，在构造<strong>自身.</strong></p><p>先析构B对象</p><p>析构时先析构自身，在析构类对象.</p><h3 id="静态成员"><a href="#静态成员" class="headerlink" title="静态成员"></a>静态成员</h3><p>静态成员就是在成员变量和成员函数前加上关键字static，成为静态成员</p><ul><li><p>静态成员变量</p><ul><li>所有对象共享同一份数据</li><li>在编译阶段分配内存</li><li>类内声明，类外初始化</li></ul></li><li><p>静态成员函数</p><ul><li>所有对象共享一个函数</li><li>静态成员函数只能访问静态成员变量,不可以访问非静态成员变量<ul><li>无法区分到底是哪一个对象的属性</li><li>也是有访问权限的</li></ul></li></ul></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line">Public:</span><br><span class="line">    <span class="type">static</span> <span class="type">int</span> m_A;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> Person:: m_A=<span class="number">100</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">Person P;</span><br><span class="line">    cout &lt;&lt; P.m_A &lt;&lt;endl;<span class="comment">//100</span></span><br><span class="line">    Person p2;</span><br><span class="line">    p<span class="number">2.</span>m_A=<span class="number">200</span>;</span><br><span class="line">    cout &lt;&lt; P.m_A &lt;&lt;endl;<span class="comment">//200</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test02</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt;Person :: m_A &lt;&lt;endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">static</span> <span class="type">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;static&quot;</span> &lt;&lt; endl; </span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">   Person ::<span class="built_in">func</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">test</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="c-对象模型和this指针"><a href="#c-对象模型和this指针" class="headerlink" title="c++对象模型和this指针"></a>c++对象模型和this指针</h2><h3 id="成员变量和成员函数分开存储"><a href="#成员变量和成员函数分开存储" class="headerlink" title="成员变量和成员函数分开存储"></a>成员变量和成员函数分开存储</h3><p>类的成员变量和成员函数分开存储</p><p>只有非静态成员变量才属于类的对象上</p><p>空对象的大小为1</p><p>c++编译器会给每一个空对象分配一个字节空间，是为了空对象占内存的位置.</p><p>每个空对象有一个独一无二的内存地址</p><h3 id="this指针概念"><a href="#this指针概念" class="headerlink" title="this指针概念"></a>this指针概念</h3><p>每一个非静态成员函数只会诞生一份函数实例，也就是说多个同类型的对象会共用一块代码</p><p>那么问题是：这一块代码是如何区分那个对象调用自己的呢?</p><p>c++通过提供特殊的对象指针，this指针，解决上述问题.this指针指向被调用的成员函数所属的对象。</p><p>this指针是<strong>隐含</strong>每一个<strong>非静态</strong>的成员函数内的一种<strong>指针</strong></p><p>this指针不需要定义，直接使用即可</p><p><strong>用途</strong>：</p><ul><li>当形参和成员变量名同名时，可用this指针来区分</li><li>在类的非静态成员函数中返回对象本身，可使用return *this</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>(<span class="type">int</span> age)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//解决名称冲突</span></span><br><span class="line">        <span class="keyword">this</span>-&gt;age = age;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function">Person&amp; <span class="title">PersonAddage</span><span class="params">(Person &amp;P)</span><span class="comment">//要返回引用， 如果返回的是Person的值话，返回的是对p2的一份拷贝</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;age += P.age;</span><br><span class="line">        <span class="keyword">return</span> *<span class="keyword">this</span>;<span class="comment">//返回*this</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Person <span class="title">p1</span><span class="params">(<span class="number">18</span>)</span></span>;</span><br><span class="line">    cout &lt;&lt; p<span class="number">1.</span>age &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test02</span><span class="params">()</span><span class="comment">//链式编程思想</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Person <span class="title">p1</span><span class="params">(<span class="number">10</span>)</span></span>;</span><br><span class="line">    <span class="function">Person <span class="title">p2</span><span class="params">(<span class="number">10</span>)</span></span>;</span><br><span class="line">    p<span class="number">2.</span><span class="built_in">PersonAddage</span>(p1).<span class="built_in">PersonAddage</span>(p1).<span class="built_in">PersonAddage</span>(p1);</span><br><span class="line">    cout &lt;&lt; p<span class="number">2.</span>age &lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">test02</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="空指针访问成员函数"><a href="#空指针访问成员函数" class="headerlink" title="空指针访问成员函数"></a>空指针访问成员函数</h3><p>c++中空指针也是可以调用成员函数的，但是也要注意有没有用到this指针</p><p>对this判空有助于提高代码的健壮性</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">showClassName</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Person&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">showPersonAge</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="comment">//报错原因是因为传入的指针是为NULL空的</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>==<span class="literal">NULL</span>) <span class="keyword">return</span>;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;age=&quot;</span> &lt;&lt; m_Age &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> m_Age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Person *P=<span class="literal">NULL</span>; </span><br><span class="line">    P-&gt;<span class="built_in">showClassName</span>();</span><br><span class="line">    <span class="comment">// P-&gt;showPersonAge();</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">test01</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="const修饰成员函数"><a href="#const修饰成员函数" class="headerlink" title="const修饰成员函数"></a>const修饰成员函数</h3><p>常函数：</p><ul><li>成员函数后加const后我们称这个函数为常函数</li><li>常函数内不可以修改成员属性</li><li>成员属性声明时加关键字mutable后，在常函数中依然可以修改</li></ul><p>常对象：</p><ul><li>声明对象前加const称该对象为常对象</li><li>常对象只能调用常函数<ul><li>普通成员函数可以修改属性</li></ul></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//this指针的本质 是指针常量  指针的指向是不可以修改的</span></span><br><span class="line"><span class="comment">//const Person *const this</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">showPerson</span><span class="params">()</span><span class="type">const</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="keyword">this</span>-&gt;m_A =<span class="number">100</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在成员函数后面加const，修饰的是this指向，让指针指向的值也不可以修改.</p><h3 id="友元"><a href="#友元" class="headerlink" title="友元"></a>友元</h3><p>在程序里，有些私有属性，也想让类外特殊的一些函数或者类进行访问，就需要用到友元的技术</p><p>友元的目的就是一个函数或者类 访问另一个类中私有成员</p><p><strong>友元的关键字</strong>：friend</p><p>友元的三种实现 </p><ul><li><p>全局函数做友元</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Building</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">//goodGay全局函数是 BUilding好朋友 ，可以访问Building中私有成员</span></span><br><span class="line">    <span class="function"><span class="keyword">friend</span> <span class="type">void</span> <span class="title">goodGay</span><span class="params">(Building &amp;building)</span></span>;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Building</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        m_SittingRoom =<span class="string">&quot;客厅&quot;</span>;</span><br><span class="line">        m_BedRoom = <span class="string">&quot;卧室&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    string m_SittingRoom;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    string m_BedRoom;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">goodGay</span><span class="params">(Building &amp;building)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; building.m_SittingRoom &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; building.m_BedRoom &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Building building;</span><br><span class="line">    <span class="built_in">goodGay</span>(building);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>类做友元</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Building</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">//goodGay类是本类的好朋友，可以访问本类中的私有成员</span></span><br><span class="line">    <span class="keyword">friend</span> <span class="keyword">class</span> <span class="title class_">goodGay</span>;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Building</span>();</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    string m_SittingRoom;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    string m_BedRoom;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">goodGay</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">goodGay</span>();</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">visit</span><span class="params">()</span></span>;<span class="comment">//参观函数访问Building中的属性</span></span><br><span class="line">    Building *building;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">goodGay::<span class="built_in">goodGay</span>()</span><br><span class="line">&#123;</span><br><span class="line">    building = <span class="keyword">new</span> Building;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> goodGay:: <span class="built_in">visit</span>()</span><br><span class="line">&#123;</span><br><span class="line">    cout&lt;&lt;building-&gt;m_SittingRoom&lt;&lt;endl;</span><br><span class="line">    cout&lt;&lt;building-&gt;m_BedRoom&lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//类外去写成员函数</span></span><br><span class="line">Building::<span class="built_in">Building</span>()</span><br><span class="line">&#123;</span><br><span class="line">    m_SittingRoom = <span class="string">&quot;客厅&quot;</span>;</span><br><span class="line">    m_BedRoom = <span class="string">&quot;卧室&quot;</span>;</span><br><span class="line">&#125;  </span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    goodGay g;</span><br><span class="line">    g.<span class="built_in">visit</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>成员函数做友元</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Building</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">goodGay</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">goodGay</span>();</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">visit1</span><span class="params">()</span></span>;<span class="comment">//visit可以访问私有成员</span></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">visit2</span><span class="params">()</span></span>;<span class="comment">//不可以访问私有成员</span></span><br><span class="line">    Building *building;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Building</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">friend</span> <span class="type">void</span> <span class="title">goodGay::visit1</span><span class="params">()</span></span>;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Building</span>();</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    string m_SettingRoom;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    string m_BedRoom;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">Building :: <span class="built_in">Building</span>()</span><br><span class="line">&#123;</span><br><span class="line">    m_SettingRoom = <span class="string">&quot;客厅&quot;</span>;</span><br><span class="line">    m_BedRoom = <span class="string">&quot;卧室&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line">goodGay :: <span class="built_in">goodGay</span>()</span><br><span class="line">&#123;</span><br><span class="line">    building = <span class="keyword">new</span> Building;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> goodGay :: <span class="built_in">visit1</span>()</span><br><span class="line">&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Building &quot;</span> &lt;&lt; building-&gt;m_SettingRoom &lt;&lt;endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Building &quot;</span> &lt;&lt; building-&gt;m_BedRoom &lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> goodGay :: <span class="built_in">visit2</span>()</span><br><span class="line">&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Building &quot;</span> &lt;&lt; building-&gt;m_SettingRoom &lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    goodGay g;</span><br><span class="line">    g.<span class="built_in">visit1</span>();</span><br><span class="line">    g.<span class="built_in">visit2</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h2 id="运算符重载"><a href="#运算符重载" class="headerlink" title="运算符重载"></a>运算符重载</h2><p>元算符重载概念：对已有的运算符重新进行定义，赋予其另外一种功能，以适应不同的数据类型</p><h3 id="加号运算符重载"><a href="#加号运算符重载" class="headerlink" title="加号运算符重载"></a>加号运算符重载</h3><p>作用：实现两个自定义数据类型相加的运算</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line">Person p3=p<span class="number">1.</span><span class="keyword">operator</span>+(p2);</span><br><span class="line">简化为</span><br><span class="line">Person p3=p1+p2;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">// Person operator+(Person &amp;p)</span></span><br><span class="line">    <span class="comment">// &#123;</span></span><br><span class="line">    <span class="comment">//     Person temp;</span></span><br><span class="line">    <span class="comment">//     temp.m_A=this-&gt;m_A+p.m_A;</span></span><br><span class="line">    <span class="comment">//     temp.m_B=this-&gt;m_B+p.m_B;</span></span><br><span class="line">    <span class="comment">//     return temp;</span></span><br><span class="line">    <span class="comment">// &#125;</span></span><br><span class="line">    <span class="comment">//本质上的调用是 Person p3=p1.operator+(p2);</span></span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line">    <span class="type">int</span> m_B;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">Person <span class="keyword">operator</span>+(Person &amp;p1,Person &amp;p2)<span class="comment">//本质上调用是Person p3=operator+(p2,p1);</span></span><br><span class="line">&#123;</span><br><span class="line">    Person temp;</span><br><span class="line">    temp.m_A=p<span class="number">1.</span>m_A+p<span class="number">2.</span>m_A;</span><br><span class="line">    temp.m_B=p<span class="number">1.</span>m_B+p<span class="number">2.</span>m_B;</span><br><span class="line">    <span class="keyword">return</span> temp;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Person p1;</span><br><span class="line">    p<span class="number">1.</span>m_A = <span class="number">10</span>;</span><br><span class="line">    p<span class="number">1.</span>m_B = <span class="number">10</span>;</span><br><span class="line">    Person p2;</span><br><span class="line">    p<span class="number">2.</span>m_A = <span class="number">10</span>;</span><br><span class="line">    p<span class="number">2.</span>m_B = <span class="number">10</span>;</span><br><span class="line">    Person p3=p1+p2;</span><br><span class="line">    cout &lt;&lt; p<span class="number">3.</span>m_A &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; p<span class="number">3.</span>m_B &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>运算符重载也可以发生函数重载.</strong></p><p>总结：</p><ul><li>对于内置的数据类型的表达式的运算符是不可能改变的</li><li>不要滥用运算符重载</li></ul><h3 id="左移运算符重载"><a href="#左移运算符重载" class="headerlink" title="左移运算符重载"></a>左移运算符重载</h3><p>可以输出自定义的数据类型</p><p>通常不会利用成员函数重载&lt;&lt;运算符，因为无法实现cout在左侧</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">// 通常不会利用成员函数重载&lt;&lt;运算符，因为无法实现cout在左侧</span></span><br><span class="line">    <span class="comment">// void operator&lt;&lt;()</span></span><br><span class="line">    <span class="comment">// &#123;</span></span><br><span class="line">    <span class="comment">// &#125;</span></span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line">    <span class="type">int</span> m_B;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//只能全局函数来重载左移运算符</span></span><br><span class="line">ostream&amp; <span class="keyword">operator</span>&lt;&lt;(ostream &amp;cout,Person &amp;p)</span><br><span class="line">&#123;  </span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;m_A=&quot;</span> &lt;&lt; p.m_A &lt;&lt;endl;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;m_B=&quot;</span> &lt;&lt; p.m_B &lt;&lt;endl;</span><br><span class="line">    <span class="keyword">return</span> cout;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Person p;</span><br><span class="line">    p.m_A = <span class="number">10</span>;</span><br><span class="line">    p.m_B = <span class="number">10</span>;</span><br><span class="line">    cout &lt;&lt; p&lt;&lt;endl;</span><br><span class="line">    cout &lt;&lt; p.m_A &lt;&lt; <span class="string">&quot; &quot;</span> &lt;&lt; p.m_B &lt;&lt; endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>重载左移运算符可以配合友元实现输出自定义数据类型</p></blockquote><h3 id="递增运算符重载"><a href="#递增运算符重载" class="headerlink" title="递增运算符重载"></a>递增运算符重载</h3><p>作用：通过重载运算符，实现自己的整形数据</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">MyIntegar</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">friend</span> ostream&amp; <span class="keyword">operator</span>&lt;&lt;(ostream&amp; os,  MyIntegar s);</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">MyIntegar</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        m_Num = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//重载前置++运算符</span></span><br><span class="line">    MyIntegar&amp; <span class="keyword">operator</span>++()</span><br><span class="line">    &#123;</span><br><span class="line">        m_Num++;</span><br><span class="line">        <span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    MyIntegar <span class="keyword">operator</span>++(<span class="type">int</span>)<span class="comment">//int代表占位参数，可以用于区分前置和后置递增</span></span><br><span class="line">    &#123;</span><br><span class="line">        MyIntegar temp=*<span class="keyword">this</span>;</span><br><span class="line">        <span class="keyword">this</span>-&gt;m_Num++;</span><br><span class="line">        <span class="keyword">return</span> temp;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_Num;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">ostream&amp; <span class="keyword">operator</span>&lt;&lt;(ostream&amp; os,  MyIntegar s)</span><br><span class="line">&#123;</span><br><span class="line">    os &lt;&lt; s.m_Num ;</span><br><span class="line">    <span class="keyword">return</span> os;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    MyIntegar myint;</span><br><span class="line">    cout &lt;&lt; ++(++myint)&lt;&lt;endl; </span><br><span class="line">    cout &lt;&lt; myint &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test2</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    MyIntegar myint;</span><br><span class="line">    cout &lt;&lt; myint++&lt;&lt;endl; </span><br><span class="line">    cout &lt;&lt; myint &lt;&lt; endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="赋值运算符重载"><a href="#赋值运算符重载" class="headerlink" title="赋值运算符重载"></a>赋值运算符重载</h3><p>c++编译器至少给一个类添加4个函数</p><p>1.默认构造函数(无参，函数体为空)</p><p>2.默认析构函数(无参，函数体为空)</p><p>3.默认拷贝构造函数，对属性进行值拷贝</p><p>4.赋值运算符 operator&#x3D;,对属性进行值拷贝</p><p>如果类中有属性指向堆区，做赋值操作时也会出现深浅拷贝问题</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>(<span class="type">int</span> age)</span><br><span class="line">    &#123;</span><br><span class="line">        m_Age = <span class="keyword">new</span> <span class="built_in">int</span>(age);</span><br><span class="line">    &#125;</span><br><span class="line">    Person&amp; <span class="keyword">operator</span>=(Person &amp;p)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//应该先判断是否有属性在堆区，如果有先释放干净，然后在深拷贝</span></span><br><span class="line">        <span class="keyword">if</span>(m_Age !=<span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span> m_Age;</span><br><span class="line">        &#125;</span><br><span class="line">        m_Age= <span class="keyword">new</span> <span class="built_in">int</span>(*(p.m_Age));</span><br><span class="line">        <span class="keyword">return</span> *<span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">Person</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(m_Age!=<span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span> m_Age;</span><br><span class="line">            m_Age = <span class="literal">NULL</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> *m_Age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Person <span class="title">p1</span><span class="params">(<span class="number">18</span>)</span></span>;</span><br><span class="line">    <span class="function">Person <span class="title">p2</span><span class="params">(<span class="number">20</span>)</span></span>;</span><br><span class="line">    <span class="function">Person <span class="title">p3</span><span class="params">(<span class="number">30</span>)</span></span>;</span><br><span class="line">    p3=p2=p1;</span><br><span class="line">    cout &lt;&lt; *p<span class="number">1.</span>m_Age &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; *p<span class="number">2.</span>m_Age &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; *p<span class="number">3.</span>m_Age &lt;&lt; endl;</span><br><span class="line">&#125;   </span><br></pre></td></tr></table></figure><h3 id="关系运算符重载"><a href="#关系运算符重载" class="headerlink" title="关系运算符重载"></a>关系运算符重载</h3><p>作用：重载关系运算符，可以让两个自定义类型对象进行对比操作</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>(string name,<span class="type">int</span> age)</span><br><span class="line">    &#123;</span><br><span class="line">        m_Name=name;</span><br><span class="line">        m_Age=age;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">bool</span> <span class="keyword">operator</span>==(Person &amp;P)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>-&gt;m_Name==P.m_Name &amp;&amp; <span class="keyword">this</span>-&gt;m_Age==P.m_Age)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125; </span><br><span class="line">     <span class="type">bool</span> <span class="keyword">operator</span>!=(Person &amp;P)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>-&gt;m_Name==P.m_Name &amp;&amp; <span class="keyword">this</span>-&gt;m_Age==P.m_Age)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125; </span><br><span class="line">    string m_Name;</span><br><span class="line">    <span class="type">int</span> m_Age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Person <span class="title">p1</span><span class="params">(<span class="string">&quot;John&quot;</span>,<span class="number">18</span>)</span></span>;</span><br><span class="line">    <span class="function">Person <span class="title">p2</span><span class="params">(<span class="string">&quot;John&quot;</span>,<span class="number">18</span>)</span></span>;</span><br><span class="line">    <span class="keyword">if</span>(p1 == p2)</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;p1==p2&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;p1!=p2&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="函数调用运算符重载"><a href="#函数调用运算符重载" class="headerlink" title="函数调用运算符重载"></a>函数调用运算符重载</h3><ul><li>函数调用运算符()也可以重载</li><li>由于重载后使用的方式非常像函数的调用，因此称为仿函数</li><li>仿函数没有固定写法，非常灵活</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Myprint</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//重载函数调用运算符</span></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">operator</span><span class="params">()</span><span class="params">(string test)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; test &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Myprint Myprint;</span><br><span class="line">    <span class="built_in">Myprint</span>(<span class="string">&quot;helloworld&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">test02</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">MyAdd myadd;</span><br><span class="line">    <span class="type">int</span> ret=<span class="built_in">myadd</span>(<span class="number">100</span>,<span class="number">100</span>);</span><br><span class="line">    cout &lt;&lt; ret &lt;&lt; endl;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//匿名函数对象</span></span><br><span class="line">    cout &lt;&lt; <span class="built_in">MyAdd</span>()(<span class="number">100</span>,<span class="number">100</span>)&lt;&lt; endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h2><p>继承是面向对象的三大特性之一</p><p>我们发现，定义这些类的时候，下级别的成员除了拥有上一级的共性，还有自己的特性。</p><p>这个时候考虑利用继承技术，减少代码重复。</p><h3 id="基本语法"><a href="#基本语法" class="headerlink" title="基本语法"></a>基本语法</h3><blockquote><p>​class  子类 ： 继承方式  父类</p><p>​子类   也称为  派生类</p><p>​父类   也称为   基类</p></blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">BasePage</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">header</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;首页、公开课、登陆、注册（公共头部）&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">footer</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;帮助中心、交流合作、站内地图、（公共底部）&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">left</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">            cout &lt;&lt; <span class="string">&quot;公共分类列表&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Java</span>: <span class="keyword">public</span> BasePage</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">content</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;java&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Python</span> : <span class="keyword">public</span> BasePage</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">content</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;phthon&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>好处：减少重复代码。</strong></p><h3 id="继承方式"><a href="#继承方式" class="headerlink" title="继承方式"></a>继承方式</h3><p>一共有三种：</p><ul><li><p>公共继承</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Base1</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="type">int</span> m_B;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_C;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son1</span> : <span class="keyword">public</span> Base1</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_A = <span class="number">10</span>;</span><br><span class="line">        m_B = <span class="number">10</span>;</span><br><span class="line">        <span class="comment">//m_C = 10;父类中的私有权限成员 子类访问不到</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></li><li><p>保护继承</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//父类中的除私有权限下的成员之外的所有成员变为自己的保护权限下的成员</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Base2</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="type">int</span> m_B;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_C;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son2</span> :<span class="keyword">protected</span> Base2</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_A=<span class="number">10</span>;</span><br><span class="line">        m_B=<span class="number">10</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></li><li><p>私有继承</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//除私有成员之外的全部变为自己的私有成员</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Base3</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="type">int</span> m_B;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_C;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son3</span> :<span class="keyword">private</span> Base3</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>: </span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_A=<span class="number">10</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure></li></ul><h3 id="继承中的对象模型"><a href="#继承中的对象模型" class="headerlink" title="继承中的对象模型"></a>继承中的对象模型</h3><p><strong>问题：</strong>从父类继承过来的成员，那些属于子类对象中？</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> m_A;</span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="type">int</span> m_B;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    <span class="type">int</span> m_C;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> :<span class="keyword">public</span> Base</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> m_D;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="built_in">sizeof</span>(Son) &lt;&lt; endl; <span class="comment">//**16**</span></span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>父类中的所有非静态成员属性都会被子类继承下去</p><p>父类中私有成员属性  是被编译器隐藏了，因此访问不到  但是确实是被继承下去了</p><h3 id="继承中构造和析构顺序"><a href="#继承中构造和析构顺序" class="headerlink" title="继承中构造和析构顺序"></a>继承中构造和析构顺序</h3><p>子类继承父类后，当创建子类对象，也会调用父类的构造函数</p><p>问题：父类和子类的构造和析构顺序是谁先谁后</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Base</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Base&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">Base</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Basexg&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> :<span class="keyword">public</span> Base</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Son</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Son&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">Son</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Sonxg&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Son s;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">test</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>Base</p><p>Son</p><p>Sonxg</p><p>Basexg</p></blockquote><p>继承中的构造和析构顺序：</p><ul><li>构造先构造父类，在构造子类</li><li>析构先析构子类，在构造父类</li></ul><h3 id="继承中同名处理方式"><a href="#继承中同名处理方式" class="headerlink" title="继承中同名处理方式"></a>继承中同名处理方式</h3><p>问题：当子类与父类出现同名的成员，如何通过子类对象，访问到子类或父类中同名的数据？</p><ul><li>访问子类同名成员直接访问即可</li><li>访问父类同名成员                需要加作用域</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Son s;</span><br><span class="line">    cout &lt;&lt; s.m_A &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; s.Base::m_A &lt;&lt; endl;<span class="comment">//如果通过子类对象  访问到父类中同名成员，需要加作用域</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//同名函数的处理方式</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Son s;</span><br><span class="line">    s.<span class="built_in">func</span>();</span><br><span class="line">    s.Base::<span class="built_in">func</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果子类中出现和父类同名的成员函数，子类的同名成员函数会隐藏掉父类中的所有同名成员函数。</p><p>如果想访问到父类中被隐藏的同名成员函数，需要加作用域。</p><p>总结：</p><ul><li>子类对象可以直接访问到子类中同名成员</li><li>子类对象加作用域可以访问到父类同名成员</li><li>当子类与父类拥有同名的成员函数，子类会隐藏父类中的所有同名的成员函数，加作用域可以访问到父类中同名函数</li></ul><h3 id="继承同名静态成员处理方式"><a href="#继承同名静态成员处理方式" class="headerlink" title="继承同名静态成员处理方式"></a>继承同名静态成员处理方式</h3><p>问题：继承中同名的静态成员在子类对象上如何进行访问?</p><p>静态成员和非静态成员出现同名，处理方式一致</p><ul><li>访问子类同名成员         直接访问即可</li><li>访问父类同名成员         需要加作用域</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//同名静态成员属性</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">//通过对象访问</span></span><br><span class="line">   Son s;</span><br><span class="line">    cout &lt;&lt; s.m_A &lt;&lt; endl; </span><br><span class="line">    cout &lt;&lt; Son:: m_A &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; Base ::m_A &lt;&lt; endl;</span><br><span class="line">    <span class="comment">//通过对象访问</span></span><br><span class="line">    cout &lt;&lt; s.Base::m_A &lt;&lt; endl;</span><br><span class="line">    <span class="comment">//第一个冒号 代表通过类名方式访问  第二个冒号代表父类作用域下</span></span><br><span class="line">    cout &lt;&lt; Son::Base::m_A &lt;&lt; endl; </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//同名静态成员函数</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">//通过对象访问</span></span><br><span class="line">    Son s;</span><br><span class="line">    s.<span class="built_in">func</span>();</span><br><span class="line">    s.Base::<span class="built_in">func</span>();</span><br><span class="line">    <span class="comment">//通过类名访问</span></span><br><span class="line">    Son ::<span class="built_in">func</span>();</span><br><span class="line">    Son::Base::<span class="built_in">func</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>子类出现和父类同名静态成员函数，也会隐藏父类中所有同名成员函数</p><p>如果想访问父类中被隐藏同名成员，需要加作用域</p><h3 id="多继承语法"><a href="#多继承语法" class="headerlink" title="多继承语法"></a>多继承语法</h3><p>C++允许一个类继承多个类</p><blockquote><p>语法：class  子类  ： 继承方式  父类1    ，继承方式   父类2 ……</p></blockquote><p>多继承可能会引发父类中有同名成员出现，需要加作用域区分</p><p>C++实际开发中不建议用多继承</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> :<span class="keyword">public</span> Base1,<span class="keyword">public</span> Base2</span><br></pre></td></tr></table></figure><blockquote><p>总结：多继承中如果父类中出现了同名情况，子类使用时候要加作用域.</p></blockquote><h3 id="菱形继承"><a href="#菱形继承" class="headerlink" title="菱形继承"></a>菱形继承</h3><p>菱形继承概念：</p><p>​两个派生类继承同一个基类</p><p>​又有某个同类同时继承两个派生类</p><p>​这种继承被称为菱形继承，或者钻石继承</p><p><strong>菱形继承典型案例</strong></p><blockquote><p>动物下有羊 与 驼继承了动物</p><p>底下又有草泥马(羊驼)同时继承了羊 与 驼</p></blockquote><p>菱形继承问题：</p><p>1.羊继承了动物的数据，驼同样继承了动物的数据，当草泥马使用数据时，就会产生二义性</p><p>2.草泥马继承自动物的数据继承了两份，其实我们应该清楚，这份数据我们只需要一份就可以.</p><p>利用虚继承  解决菱形继承问题</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">int</span> m_Age;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">//利用虚继承  解决菱形继承问题</span></span><br><span class="line"><span class="comment">//继承之前加上virtual 变为虚继承</span></span><br><span class="line"><span class="comment">//Animal类称为 虚基类</span></span><br><span class="line"><span class="comment">//羊类</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Sheep</span> : <span class="keyword">virtual</span> <span class="keyword">public</span> Animal&#123;&#125;;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Tuo</span> : <span class="keyword">virtual</span> <span class="keyword">public</span> Animal&#123;&#125;;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">SheepTuo</span> :<span class="keyword">public</span> Sheep,<span class="keyword">public</span> Tuo&#123;&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    SheepTuo st;</span><br><span class="line">    st.Sheep::m_Age = <span class="number">18</span>;</span><br><span class="line">    st.Tuo::m_Age = <span class="number">28</span>;</span><br><span class="line">    cout &lt;&lt; st.Sheep::m_Age &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; st.Tuo::m_Age &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; st.m_Age &lt;&lt; endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>总结：</p><ul><li>菱形继承带来的主要问题是子类继承两份相同的数据，导致资源浪费以及毫无意义</li><li>利用虚继承可以解决菱形继承问题</li></ul><h2 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h2><p>多态是C++面向对象三大特性之一</p><p>多态分为两类：</p><ul><li>静态多态 ：函数重载和运算符重载属于静态多态，复用函数名</li><li>动态多态 ：派生类和虚函数实现运行时多态</li></ul><p>区别：</p><ul><li>静态多态的函数地址早绑定 – 编译阶段确定函数地址</li><li>动态多态的函数地址晚绑定 – 运行阶段确定函数地址</li></ul><blockquote><p>动态多态满足条件：</p><ul><li><p>有继承关系</p></li><li><p>子类要重写父类中的虚函数（函数返回值类型  函数名  参数类表  完全相同）</p><p>使用</p><p>父类的指针或者引用 执行子类的对象</p></li></ul></blockquote><p>C++允许子类父类做类型转换.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//虚函数</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">spaek</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;speak Animal&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Cat</span> :<span class="keyword">public</span> Animal</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">speak</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;speak Cat&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">//如果想执行对应的子类函数，那么这个函数地址就不能提前绑定，需要在运行阶段进行绑定，晚绑定</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">dospeak</span><span class="params">(Animal &amp;A)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    A.<span class="built_in">spaek</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Cat cat;</span><br><span class="line">    <span class="built_in">dospeak</span>(cat);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="原理深度剖析"><a href="#原理深度剖析" class="headerlink" title="原理深度剖析"></a>原理深度剖析</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"><span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">speak</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">cout &lt;&lt; <span class="string">&quot;Animal Speak&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="built_in">sizeof</span>(Animal) &lt;&lt; endl;<span class="comment">//8   这是一个指针的大小，当使用虚函数的时候，内部生成</span></span><br><span class="line">       <span class="comment">//一个vfptr的指针，指向函数的所在位置</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="案例–计算器类"><a href="#案例–计算器类" class="headerlink" title="案例–计算器类"></a>案例–计算器类</h3><p>多态的优点：</p><ul><li>代码结构清晰</li><li>可读性强</li><li>立于前期和后期的拓展以及维护</li></ul><h3 id="纯虚函数和抽象类"><a href="#纯虚函数和抽象类" class="headerlink" title="纯虚函数和抽象类"></a>纯虚函数和抽象类</h3><p>在多态中，通常父类中函数的实现是毫无意义的，主要都是调用子类重写的内容</p><p>因此可以将虚函数改为纯虚函数</p><blockquote><p>语法：virtual   返回值类型 函数名 (参数列表) &#x3D; 0；</p></blockquote><p>当类中有了纯虚函数，这个类也称为抽象类</p><p>抽象类特点:</p><ul><li>无法实例化对象</li><li>子类必须重写抽象类中的纯虚函数，否则也属于抽象类型</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="comment">//纯虚函数</span></span><br><span class="line">    <span class="comment">//只要有一个纯虚函数，这个类称为抽象类</span></span><br><span class="line">    <span class="comment">//特点：无法实例化对象      抽象类的子类  必须要重写父类中的纯虚函数，否则也属于抽象类</span></span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">func</span><span class="params">()</span> </span>= <span class="number">0</span> ;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> : <span class="keyword">public</span> Base</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;实现函数&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">//Base b;</span></span><br><span class="line">    <span class="comment">//new Base;无法实例化对象</span></span><br><span class="line">    Son s;<span class="comment">//子类必须重写纯虚函数</span></span><br><span class="line">    s.<span class="built_in">func</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="案例-–-饮料制作"><a href="#案例-–-饮料制作" class="headerlink" title="案例  –  饮料制作"></a>案例  –  饮料制作</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">AbstractDrinking</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">Bool</span><span class="params">( )</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">Brew</span><span class="params">( )</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">PourInCup</span><span class="params">( )</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">PutSomething</span><span class="params">( )</span> </span>= <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">makeDrinking</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        <span class="built_in">Bool</span>( );</span><br><span class="line">        <span class="built_in">Brew</span>( );</span><br><span class="line">        <span class="built_in">PourInCup</span>();</span><br><span class="line">        <span class="built_in">PutSomething</span>( );</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">coffee</span> :<span class="keyword">public</span> AbstractDrinking</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">Bool</span><span class="params">( )</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Coffeewater&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">Brew</span><span class="params">( )</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;冲泡咖啡&quot;</span> &lt;&lt;endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">PourInCup</span><span class="params">( )</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;倒入杯中&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">PutSomething</span><span class="params">( )</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Put something&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Tea</span> :<span class="keyword">public</span> AbstractDrinking</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">Bool</span><span class="params">( )</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Teawater&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">Brew</span><span class="params">( )</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;茶叶咖啡&quot;</span> &lt;&lt;endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">PourInCup</span><span class="params">( )</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;倒入杯中&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">PutSomething</span><span class="params">( )</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Put something&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="虚析构和纯虚析构"><a href="#虚析构和纯虚析构" class="headerlink" title="虚析构和纯虚析构"></a>虚析构和纯虚析构</h3><p>多态使用时，如果子类中有属性开辟到堆区，那么父类指针在释放时无法调用到子类的析构代码</p><p>解决方式：将父类中的析构函数改为虚析构或者纯虚析构</p><p>虚构和纯虚析构共性：</p><ul><li>可以解决父类指针释放子类对象</li><li>都需要有具体的函数实现</li></ul><p>区别</p><ul><li>如果是纯虚析构，该类属于抽象类，无法实例化对象</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Animal</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Animal</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Animal的构造函数&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// virtual ~Animal() //利用虚析构可以解决 父类指针释放子类对象时的不干净的问题</span></span><br><span class="line">    <span class="comment">// &#123;</span></span><br><span class="line">    <span class="comment">//     cout &lt;&lt; &quot;Animal的析构函数&quot; &lt;&lt; endl;</span></span><br><span class="line">    <span class="comment">// &#125;</span></span><br><span class="line">    <span class="comment">//需要声明 ，也需要实现</span></span><br><span class="line">    <span class="keyword">virtual</span> ~<span class="built_in">Animal</span> () = <span class="number">0</span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">speak</span><span class="params">()</span></span>=<span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">Animal :: ~<span class="built_in">Animal</span>()</span><br><span class="line">&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;Animal的纯虚析构&quot;</span> &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Cat</span> : <span class="keyword">public</span> Animal</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Cat</span>(string name)</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;cat的构造函数&quot;</span> &lt;&lt; endl;</span><br><span class="line">        m_Name = <span class="keyword">new</span> <span class="built_in">string</span>(name);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">speak</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; *m_Name &lt;&lt; <span class="string">&quot;Cat Speaking&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">Cat</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>(m_Name!=<span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            cout &lt;&lt; <span class="string">&quot;cat的析构函数调用&quot;</span> &lt;&lt; endl;</span><br><span class="line">            <span class="keyword">delete</span> m_Name;</span><br><span class="line">            m_Name = <span class="literal">NULL</span>;</span><br><span class="line">        &#125; </span><br><span class="line">    &#125;</span><br><span class="line">    string *m_Name;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Animal *a = <span class="keyword">new</span> <span class="built_in">Cat</span>(<span class="string">&quot;Tom&quot;</span>);</span><br><span class="line">    a-&gt;<span class="built_in">speak</span>();</span><br><span class="line">    <span class="comment">//父类指针在析构的时候 ，不会调用子类中的析构函数 ，导致子类如果有属性在堆区的话 ，出现了内存泄漏</span></span><br><span class="line">    <span class="keyword">delete</span> a;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//虚析构语法：</span></span><br><span class="line"><span class="keyword">virtual</span> ~类名()&#123;&#125;</span><br><span class="line"><span class="comment">//纯虚析构语法：</span></span><br><span class="line"><span class="keyword">virtual</span> ~类名() = <span class="number">0</span>;</span><br><span class="line">类民::~类名()&#123;&#125;</span><br></pre></td></tr></table></figure><p>总结：</p><ul><li>虚析构或者纯虚析构就是用来解决通过父类指针释放子类对象</li><li>如果子类中没有堆区数据，可以不写</li><li>拥有纯虚析构函数的类也属于抽象类</li></ul><h3 id="案例3-–-组装电脑"><a href="#案例3-–-组装电脑" class="headerlink" title="案例3 – 组装电脑"></a>案例3 – 组装电脑</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">CPU</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">calculate</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">VideoCard</span> </span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">display</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Memory</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">storage</span><span class="params">()</span> </span>= <span class="number">0</span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Computer</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Computer</span>(CPU *cpu,VideoCard *vc ,Memory *mem)</span><br><span class="line">    &#123;</span><br><span class="line">        m_mem = mem;</span><br><span class="line">        m_vc = vc;</span><br><span class="line">        m_cpu=cpu;     </span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">work</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        m_cpu-&gt;<span class="built_in">calculate</span>();</span><br><span class="line">        m_vc-&gt;<span class="built_in">display</span>();</span><br><span class="line">        m_mem-&gt;<span class="built_in">storage</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    ~<span class="built_in">Computer</span>() </span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">if</span>( m_cpu!= <span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span> m_cpu;</span><br><span class="line">            m_cpu=<span class="literal">NULL</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(m_mem!=<span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span> m_mem;</span><br><span class="line">            m_mem=<span class="literal">NULL</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(m_vc!=<span class="literal">NULL</span>)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">delete</span> m_vc;</span><br><span class="line">            m_vc=<span class="literal">NULL</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    CPU * m_cpu;</span><br><span class="line">    VideoCard *m_vc;</span><br><span class="line">    Memory *m_mem;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Intelcpu</span>:<span class="keyword">public</span> CPU</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">calculate</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Intel CPU Start&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">IntelVideocard</span>:<span class="keyword">public</span> VideoCard</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">display</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Intel Videocard Start&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">IntelMemory</span>:<span class="keyword">public</span> Memory</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">storage</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Intel Memory Start&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Lenovocpu</span>:<span class="keyword">public</span> CPU</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">calculate</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Lenovo CPU Start&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">LenovoVideocard</span>:<span class="keyword">public</span> VideoCard</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">display</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Lenovo Videocard Start&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">LenovoMemory</span>:<span class="keyword">public</span> Memory</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">void</span> <span class="title">storage</span><span class="params">()</span> </span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Lenovo Memory Start&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    CPU * intelcpu=<span class="keyword">new</span> Intelcpu;</span><br><span class="line">    VideoCard * intelvideocard=<span class="keyword">new</span> IntelVideocard;</span><br><span class="line">    Memory * intelmemory=<span class="keyword">new</span> IntelMemory;</span><br><span class="line">    Computer * first= <span class="keyword">new</span> <span class="built_in">Computer</span>(intelcpu,intelvideocard,intelmemory);</span><br><span class="line">    first-&gt;<span class="built_in">work</span>();</span><br><span class="line">    <span class="keyword">delete</span> first;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;-----------------------&quot;</span> &lt;&lt; endl;</span><br><span class="line">    Computer * second= <span class="keyword">new</span> <span class="built_in">Computer</span>(<span class="keyword">new</span> Lenovocpu,<span class="keyword">new</span> LenovoVideocard,<span class="keyword">new</span> LenovoMemory);</span><br><span class="line">    second-&gt;<span class="built_in">work</span>();</span><br><span class="line">    <span class="keyword">delete</span> second;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">test</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="文件"><a href="#文件" class="headerlink" title="文件"></a>文件</h1><p>通过文件可以将数据持久化</p><p>头文件<fstream></p><p>文件类型：</p><ul><li>文本文件         -文件以文本的Ascll码形式存储在计算机中</li><li>二进制文件     -文件以文本的二进制形式存储在计算机中，用户一般不能直接读懂</li></ul><p>操作三大类：</p><ul><li>ofstream  写操作</li><li>ifstream   读操作</li><li>fstream    读写操作</li></ul><h2 id="文本文件"><a href="#文本文件" class="headerlink" title="文本文件"></a>文本文件</h2><table><thead><tr><th>打开方式</th><th>解释</th></tr></thead><tbody><tr><td>ios::in</td><td>为读文件而打开文件</td></tr><tr><td>ios::out</td><td>为写文件而打开文件</td></tr><tr><td>ios::app</td><td>追加方式写文件</td></tr><tr><td>ios::trunc</td><td>如果文件存在先删除，在创建</td></tr><tr><td>ios::binary</td><td>二进制方式</td></tr><tr><td>ios::ate</td><td>初始位置：文件尾</td></tr></tbody></table><p>文件打开方式可以配合使用， 利用|操作符</p><p>总结：</p><ul><li>文件操作必须包含头文件fstream</li><li>读文件可以利用ofstream 或者 fstream类</li><li>打开文件时需要指定操作文件的路径，以及打开的方式</li><li>利用 &lt;&lt; 可以向文件中写数据</li><li>操作完毕，关闭文件</li></ul><h2 id="读文件"><a href="#读文件" class="headerlink" title="读文件"></a>读文件</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ifstream ifs;</span><br><span class="line">    ifs.<span class="built_in">open</span>(<span class="string">&quot;test.txt&quot;</span>,ios::in);</span><br><span class="line">    <span class="keyword">if</span>(!ifs.<span class="built_in">is_open</span>())</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;文件打开失败&quot;</span> &lt;&lt; endl;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//接下来读取数据</span></span><br><span class="line">    <span class="comment">//1.first</span></span><br><span class="line">    <span class="comment">// char buf[1024]=&#123;0&#125;;</span></span><br><span class="line">    <span class="comment">// while(ifs &gt;&gt; buf)</span></span><br><span class="line">    <span class="comment">// &#123;</span></span><br><span class="line">    <span class="comment">//     cout &lt;&lt; buf &lt;&lt; endl;</span></span><br><span class="line">    <span class="comment">// &#125;</span></span><br><span class="line">    <span class="comment">//2.second</span></span><br><span class="line">    <span class="comment">// char buf[1024]=&#123;0&#125;;</span></span><br><span class="line">    <span class="comment">// while(ifs.getline(buf,1024))</span></span><br><span class="line">    <span class="comment">// &#123;</span></span><br><span class="line">    <span class="comment">//     cout &lt;&lt; buf &lt;&lt; endl;</span></span><br><span class="line">    <span class="comment">// &#125;</span></span><br><span class="line">    <span class="comment">//3.third</span></span><br><span class="line">    <span class="comment">// string buf;</span></span><br><span class="line">    <span class="comment">// while(getline(ifs,buf))</span></span><br><span class="line">    <span class="comment">// &#123;</span></span><br><span class="line">    <span class="comment">//     cout &lt;&lt; buf &lt;&lt; endl;</span></span><br><span class="line">    <span class="comment">// &#125;</span></span><br><span class="line">    <span class="comment">//4. fourth</span></span><br><span class="line">    <span class="type">char</span> c;</span><br><span class="line">    <span class="keyword">while</span>((c=ifs.<span class="built_in">get</span>())!=EOF)</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; c ;</span><br><span class="line">    &#125;</span><br><span class="line">    ifs.<span class="built_in">close</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>总结：</p><ul><li>读文件可以利用fstream ，或者fstream类</li><li>利用is_open函数可以判断文件是否可以打开成功</li><li>close关闭文件</li></ul><h2 id="二进制文件"><a href="#二进制文件" class="headerlink" title="二进制文件"></a>二进制文件</h2><p>以二进制的方式对文件进行读写操作</p><p>打开方式要指定为ios::binary</p><h3 id="写文件"><a href="#写文件" class="headerlink" title="写文件"></a>写文件</h3><p>二进制方式写文件主要利用流对象调用成员函数write</p><blockquote><p>函数原型 ： ofstream&amp; write(const char *buffer ,int len)</p></blockquote><p>参数解释:字符指针buffer指向内存中一段存储空间，len是读写的字节数</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">public</span>:</span><br><span class="line">    <span class="type">char</span> m_Name[<span class="number">64</span>];</span><br><span class="line">    <span class="type">int</span> m_Age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// ofstream ofs;</span></span><br><span class="line">    <span class="comment">// ofs.open(&quot;Person.txt&quot;,ios::out|ios::binary);</span></span><br><span class="line">    <span class="function">ofstream <span class="title">ofs</span><span class="params">(<span class="string">&quot;Person.txt&quot;</span>,ios::out|ios::binary)</span></span>;</span><br><span class="line">    Person p = &#123; <span class="string">&quot;张三&quot;</span> , <span class="number">18</span> &#125;;</span><br><span class="line">    ofs.<span class="built_in">write</span>((<span class="type">const</span> <span class="type">char</span> *)&amp;p,<span class="built_in">sizeof</span>(Person));</span><br><span class="line">    ofs.<span class="built_in">close</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="读文件-1"><a href="#读文件-1" class="headerlink" title="读文件"></a>读文件</h3><p>二进制方式读文件主要利用流对象调用成员函数read</p><blockquote><p>函数原型: istream&amp; read(char *buffer , int len);</p></blockquote><p>参数解释：字符指针buffer指向内存中的一段存储空间，len是读写的字节数</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="type">char</span> m_Name[<span class="number">64</span>];</span><br><span class="line">    <span class="type">int</span> m_Age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    ifstream ifs;</span><br><span class="line">    ifs.<span class="built_in">open</span>(<span class="string">&quot;Person.txt&quot;</span>,ios::in | ios::binary);</span><br><span class="line">    <span class="keyword">if</span>(!ifs.<span class="built_in">is_open</span>())</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;打开失败&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    Person p;</span><br><span class="line">    ifs.<span class="built_in">read</span>((<span class="type">char</span> *)&amp;p,<span class="built_in">sizeof</span>(Person));</span><br><span class="line">    cout &lt;&lt; p.m_Name &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; p.m_Age &lt;&lt; endl;</span><br><span class="line">    ifs.<span class="built_in">close</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="c-提高"><a href="#c-提高" class="headerlink" title="c++提高"></a>c++提高</h1><ul><li>本阶段主要针对C++泛型编程和STL技术详解</li></ul><h2 id="模板"><a href="#模板" class="headerlink" title="模板"></a>模板</h2><p>模板就是建立通用的模具，大大提高复用性</p><p>特点：</p><ul><li>模板不可以直接使用，他只是一个框架</li><li>模板的通用并不是万能的</li></ul><h3 id="函数模板"><a href="#函数模板" class="headerlink" title="函数模板"></a>函数模板</h3><ul><li>c++另一种编程思想为泛型编程，主要利用的技术就是模板</li><li>c++提供两种模板机制：函数模板和类模板</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line">函数声明或定义（这里写函数）</span><br></pre></td></tr></table></figure><p>解释：</p><ul><li>template   — 声明创建模板</li><li>typename  —表明其后面的符号是一种数据类型，可以用class代替</li><li>T  — 通用的数据类型 ， 名称可以替换 ， 通常为大写字母</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;<span class="comment">//声明一个模板，告诉编译器后面代码中紧跟着的T不要报错，T是一个通用的数据类型</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">myswap</span><span class="params">(T &amp;a, T &amp;b)</span> </span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    T temp=a;</span><br><span class="line">    a=b;</span><br><span class="line">    b=temp;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b=<span class="number">20</span>;</span><br><span class="line">    <span class="comment">//两种方式使用函数模板</span></span><br><span class="line">    <span class="comment">//1.自动类型推导</span></span><br><span class="line">    <span class="built_in">myswap</span>(a,b);</span><br><span class="line">    <span class="comment">//2.显示指定类型</span></span><br><span class="line">    <span class="built_in">myswap</span>&lt;<span class="type">int</span>&gt;(a,b);</span><br><span class="line">    <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>总结</strong>：</p><ul><li>函数模板利用关键字template</li><li>函数模板的两种使用方式：1.自动类型推导          2.显示指定类型</li><li>模板的目的是为了提高复用性，将数据类型参数化</li></ul><h4 id="注意事项-1"><a href="#注意事项-1" class="headerlink" title="注意事项"></a>注意事项</h4><ul><li>自动类型推导，必须要推导出一致的数据类型T，才可以使用</li><li>模板必须要确定出T的数据类型，才可以使用</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">mySwap</span><span class="params">(T &amp;a,T &amp;b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    T temp=a;</span><br><span class="line">    a=b;</span><br><span class="line">    b=temp;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b=<span class="number">20</span>;</span><br><span class="line">    <span class="type">char</span> c=<span class="string">&#x27;c&#x27;</span>;</span><br><span class="line">    <span class="comment">//正确的mySwap(a,b);</span></span><br><span class="line">    <span class="built_in">mySwap</span>(a,c);<span class="comment">//无法推导出一致的数据类型</span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T</span>&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">func</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;kjkasl&quot;</span>&lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="built_in">func</span>();<span class="comment">//没有指定T,函数内部都没有用到T  </span></span><br><span class="line"><span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h4><p>利用函数模板封装一个函数，使得函数可以对不同的数据类型排序</p><p>排序按照从小到达的顺序</p><p>可以用到不同的排序函数</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">partition</span><span class="params">(T *a,<span class="type">int</span> i,<span class="type">int</span> j)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    T x = a[i];</span><br><span class="line">    <span class="keyword">while</span>(i&lt;j)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">while</span>(i&lt;j &amp;&amp; a[j]&gt;=x)</span><br><span class="line">        &#123;</span><br><span class="line">            j--;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(i&lt;j)</span><br><span class="line">        &#123;</span><br><span class="line">            a[i]=a[j];</span><br><span class="line">            i++;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span>(i&lt;j &amp;&amp; a[i]&lt;x)</span><br><span class="line">        &#123;</span><br><span class="line">            i++;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(i&lt;j)</span><br><span class="line">        &#123;</span><br><span class="line">            a[j]=a[i];</span><br><span class="line">            j--;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    a[i] =x;</span><br><span class="line">    <span class="keyword">return</span> i;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">mySort</span><span class="params">(T *a,<span class="type">int</span> i,<span class="type">int</span> j)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(i&lt;j)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="type">int</span> x=<span class="built_in">partition</span>(a,i,j);</span><br><span class="line">        <span class="built_in">mySort</span>(a,i,x<span class="number">-1</span>);</span><br><span class="line">        <span class="built_in">mySort</span>(a,x<span class="number">+1</span>,j);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">char</span> chararr[]= <span class="string">&quot;bacdfe&quot;</span>;</span><br><span class="line">    <span class="built_in">mySort</span>(chararr,<span class="number">0</span>,<span class="number">5</span>);</span><br><span class="line">    cout &lt;&lt; chararr &lt;&lt; endl;</span><br><span class="line">    <span class="type">int</span> num[]=&#123;<span class="number">4</span>,<span class="number">5</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">9</span>,<span class="number">7</span>,<span class="number">0</span>,<span class="number">3</span>,<span class="number">6</span>,<span class="number">8</span>&#125;;</span><br><span class="line">    <span class="built_in">mySort</span>(num,<span class="number">0</span>,<span class="number">9</span>);</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i=<span class="number">0</span>;i&lt;(<span class="built_in">sizeof</span>(num)/<span class="built_in">sizeof</span>(<span class="type">int</span>));i++)</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; num[i] &lt;&lt; <span class="string">&quot;  &quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    cout &lt;&lt; endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="普通函数与函数模板的区别"><a href="#普通函数与函数模板的区别" class="headerlink" title="普通函数与函数模板的区别"></a>普通函数与函数模板的区别</h4><p>区别：</p><ul><li>普通函数调用时可以发生类型转换（隐式类型转换）</li><li>函数模板调用时，如果是自动类型推导的话，不会发生类型转换</li><li>如果显示指定类型的话，可以发生隐式类型转换</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function">T <span class="title">myadd</span><span class="params">(T a, T b)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">add</span><span class="params">(<span class="type">int</span> a,<span class="type">int</span> b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b=<span class="number">10</span>;</span><br><span class="line">    <span class="type">char</span> c=<span class="string">&#x27;a&#x27;</span>;</span><br><span class="line">    <span class="built_in">add</span>(a,c);</span><br><span class="line">    <span class="comment">//myadd(a,c);</span></span><br><span class="line">    <span class="comment">//显示指定类型</span></span><br><span class="line">    cout &lt;&lt; <span class="built_in">myadd</span>&lt;<span class="type">int</span>&gt;(a,c) &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><strong>总结：建议使用显示指定类型的方式，调用函数模板，因为可以自己确定通用类型T.</strong></p><h4 id="普通函数和函数模板的调用规则"><a href="#普通函数和函数模板的调用规则" class="headerlink" title="普通函数和函数模板的调用规则"></a>普通函数和函数模板的调用规则</h4><p>调用规则：</p><ul><li>如果函数模板和普通函数都可以实现，优先调用普通函数</li><li>可以通过空函数参数列表来强制调用函数模板</li><li>函数模板也可以发生重载</li><li>如果函数模板可以产生更好的匹配，优先调用函数模板</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> T&gt;</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">myprint</span><span class="params">(T a,T b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;函数模板&quot;</span> &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">myprint</span><span class="params">(<span class="type">int</span> a,<span class="type">int</span> b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;普通函数&quot;</span> &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a = <span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b = <span class="number">10</span>;</span><br><span class="line">    <span class="built_in">myprint</span>(a,b);<span class="comment">//调用的是普通函数，规则1 ，将普普通函数注释，只有声明，会发生报错，由于都可以实现，先调普通函数，但普通函数没有实现</span></span><br><span class="line">    myprint&lt;&gt;(a,b);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p> 总结：既然提供了函数模板，最好就不要提供普通函数，否则容易出现二义性</p><h4 id="模板的局限性"><a href="#模板的局限性" class="headerlink" title="模板的局限性"></a>模板的局限性</h4><ul><li>模板的局限性并不是万能的</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">f</span><span class="params">(T a,T b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">a=b;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//如果传入的的是一个数组，就无法实现了.</span></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">f</span><span class="params">(T a,T b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line"><span class="keyword">if</span>(a&gt;b)</span><br><span class="line">    &#123;</span><br><span class="line">......</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//传入的是Person ，无法确定比较的数值</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>因此C++为了解决这种问题，提供模板的重载，可以为这些特定的类型提供具体化的模板</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>(string name, <span class="type">int</span> age)</span><br><span class="line">    &#123;</span><br><span class="line">        m_name = name;</span><br><span class="line">        m_age = age;</span><br><span class="line">    &#125;</span><br><span class="line">    string m_name;</span><br><span class="line">    <span class="type">int</span> m_age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="function"><span class="type">bool</span> <span class="title">mycompare</span><span class="params">(T &amp;a, T &amp;b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(a==b)</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    <span class="keyword">else</span> </span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//利用具体化Person的版本实现代码，具体化优先调用</span></span><br><span class="line"><span class="keyword">template</span>&lt;&gt;<span class="function"><span class="type">bool</span> <span class="title">mycompare</span><span class="params">(Person &amp;a,Person &amp;b)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(a.m_name==b.m_name&amp;&amp;a.m_age==b.m_age)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="type">int</span> a=<span class="number">10</span>;</span><br><span class="line">    <span class="type">int</span> b=<span class="number">20</span>;</span><br><span class="line">    cout &lt;&lt; <span class="built_in">mycompare</span>(a,b) &lt;&lt; endl;<span class="comment">//发生错误，无法比较。1.比较运算符重载   2.</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="function">Person <span class="title">p1</span><span class="params">(<span class="string">&quot;Tom&quot;</span>,<span class="number">10</span>)</span></span>;</span><br><span class="line">    <span class="function">Person <span class="title">p2</span><span class="params">(<span class="string">&quot;Tom&quot;</span>,<span class="number">10</span>)</span></span>;</span><br><span class="line">    cout &lt;&lt; <span class="built_in">mycompare</span>(p1,p2)&lt;&lt;endl;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>总结：</p><ul><li>利用具体化的模板，可以解决自定义类型的通用化</li><li>学习模板并不是为了写模板，而是在STL能够运用系统提供的模板</li></ul><h3 id="类模板"><a href="#类模板" class="headerlink" title="类模板"></a>类模板</h3><p>作用：建立一个通用的类，类中的成员  数据类型可以不具体指定，用一个虚拟的类型来代表</p><blockquote><p>语法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line">类</span><br></pre></td></tr></table></figure><p>template    —声明创建模板</p><p>typename  —表明其后面是一种数据类型，可以用class代替</p><p>T                 —通用的数据类型，名称可以替换，通常为大写的数据类型</p></blockquote><p>类模板和函数模板的语法相似，在template后面加类，此类称为类模板.</p><h3 id="类模板与函数模板的区别"><a href="#类模板与函数模板的区别" class="headerlink" title="类模板与函数模板的区别"></a>类模板与函数模板的区别</h3><ul><li>类模板没有自动类型的推导的使用方式</li><li>类模板在模板参数列表中可以有默认参数(仅限于类模板)</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span>,<span class="keyword">class</span> <span class="title class_">T2</span>=<span class="type">int</span>&gt;<span class="comment">//模板参数列表</span></span><br><span class="line"><span class="keyword">class</span> Person</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>(T1 name ,T2 age)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;m_Name=name;</span><br><span class="line">        <span class="keyword">this</span>-&gt;m_Age=age;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">show</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="keyword">this</span>-&gt;m_Name &lt;&lt; endl;</span><br><span class="line">        cout &lt;&lt; <span class="keyword">this</span>-&gt;m_Age &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    T1 m_Name;</span><br><span class="line">    T2 m_Age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//类模板在模板列表中可以有默认参数</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Person&lt;string &gt;<span class="built_in">p1</span>(<span class="string">&quot;Tom&quot;</span>,<span class="number">17</span>);</span><br><span class="line">    p<span class="number">1.</span><span class="built_in">show</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">//Person p(&quot;John&quot;,18);,无类型推导的用法 </span></span><br><span class="line">    <span class="function">Person&lt;string ,<span class="type">int</span> &gt; <span class="title">p</span><span class="params">(<span class="string">&quot;John&quot;</span>,<span class="number">18</span>)</span></span>;</span><br><span class="line">    p.<span class="built_in">show</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>总结：</p><ul><li>类模板使用只能显示指定类型方式</li><li>类模板中的模板参数列表可以有默认参数</li></ul><h4 id="类模板中成员函数的创建时机"><a href="#类模板中成员函数的创建时机" class="headerlink" title="类模板中成员函数的创建时机"></a>类模板中成员函数的创建时机</h4><p>类模板中成员函数和普通类中成员函数创建时间是有区别的</p><ul><li>普通类中的成员函数一开始就可以创建</li><li>类模板中的成员函数在调用时才创建</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">typename</span> T&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">myClass</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    T obj;</span><br><span class="line">    <span class="comment">//类模板中的成员函数</span></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">func1</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        obj.<span class="built_in">showPerson1</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">func2</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        obj.<span class="built_in">showPerson2</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person12</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">showPerson2</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Person2&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person1</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">showPerson1</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="string">&quot;Person1&quot;</span> &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>总结：类模板中的成员函数并不是一开始就创建的，在调用时才去创建</p><h4 id="类模板对象做函数参数"><a href="#类模板对象做函数参数" class="headerlink" title="类模板对象做函数参数"></a>类模板对象做函数参数</h4><ul><li><p>类模板实例化的对象 ，向函数传参的方式</p></li><li><p>三种传参方式</p><ul><li><p>指定传入的类型   —直接显示对象的类型</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">print1</span><span class="params">(Person &lt;string,<span class="type">int</span>&gt;&amp;p)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">p.<span class="built_in">showPerson</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">Person&lt;string,<span class="type">int</span>&gt;<span class="built_in">p</span>(<span class="string">&quot;孙悟空&quot;</span>，<span class="number">100</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>参数模板化           —将对象中的参数变为模板进行传递</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span>,<span class="keyword">class</span> <span class="title class_">T2</span>&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">print2</span><span class="params">(Person &lt;T1,T2&gt;&amp;p)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    p.<span class="built_in">showPerson</span>();</span><br><span class="line">    cout &lt;&lt; <span class="string">&quot;T1的类型为: &quot;</span> &lt;&lt; <span class="built_in">typeid</span>(T1).name &lt;&lt; endl;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test02</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Person &lt;string,<span class="type">int</span> &gt;<span class="built_in">p</span>(<span class="string">&quot;tom&quot;</span>,<span class="number">200</span>);</span><br><span class="line">    <span class="built_in">print2</span>(p);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>整个类模板化       —将这个对象类型  模板化进行传递</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T</span>&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">print3</span><span class="params">(T &amp;p)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">     p.<span class="built_in">showPerson</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test03</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Person&lt;string ,<span class="type">int</span> &gt;<span class="built_in">p</span>(<span class="string">&quot;唐僧&quot;</span>,<span class="number">18</span>);</span><br><span class="line"> <span class="built_in">print3</span>(p);   </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span> ,<span class="keyword">class</span> <span class="title class_">T2</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>(T1 name ,T2 age)</span><br><span class="line">    &#123;</span><br><span class="line"><span class="keyword">this</span>-&gt;m_Name=name;</span><br><span class="line">        <span class="keyword">this</span>-&gt;m_Age=age;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">showPerson</span><span class="params">()</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; <span class="keyword">this</span>-&gt;m_Name &lt;&lt;endl;</span><br><span class="line">        cout &lt;&lt; <span class="keyword">this</span>-&gt;m_Age &lt;&lt;endl;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    T1 m_Name;</span><br><span class="line">    T2 m_Age;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>总结：</p><ul><li>通过类模板创建的对象，可以有三种方式向函数中进行传参</li><li>使用比较广泛的是第一种：指定传入类型</li></ul><h4 id="类模板与继承"><a href="#类模板与继承" class="headerlink" title="类模板与继承"></a>类模板与继承</h4><p>注意：</p><ul><li>当子类继承的父类是一个类模板时，子类在声明的时候，要指定出父类中T的类型</li><li>如果不指定，编译器无法给子类分配内存</li><li>如果想灵活指定出父类中T的类型，子类也需要变为类模板</li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Base</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    T m;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//class Son : public Base //错误的，必须要知道父类中T的数据类型，才能继承给子类</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son</span> : <span class="keyword">public</span> Base &lt;<span class="type">int</span>&gt;</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">//想灵活指定类模板中的类型，子类也需要变为模板</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span>,<span class="keyword">class</span> <span class="title class_">T2</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Son1</span> : <span class="keyword">public</span> Base&lt;T2&gt;</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Son1</span>()</span><br><span class="line">    &#123;</span><br><span class="line">        cout &lt;&lt; <span class="built_in">typeid</span>(T1).name &lt;&lt; endl;</span><br><span class="line">        cout &lt;&lt; <span class="built_in">typeid</span>(T2).name &lt;&lt; endl;</span><br><span class="line">    &#125;</span><br><span class="line">    T1 obj;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Son s1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Son1 &lt;<span class="type">int</span> ,string&gt; s;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>如果父类是一个类模板，子类在继承的时候必须要指定出父类中T的数据类型。</strong></p><h4 id="类模板成员函数在类外实现"><a href="#类模板成员函数在类外实现" class="headerlink" title="类模板成员函数在类外实现"></a>类模板成员函数在类外实现</h4><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span>,<span class="keyword">class</span> <span class="title class_">T2</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>(T1 name ,T2 age);</span><br><span class="line">    <span class="comment">// &#123;</span></span><br><span class="line">    <span class="comment">//     this-&gt;m_Age=age;</span></span><br><span class="line">    <span class="comment">//     this-&gt;m_Name=name;</span></span><br><span class="line">    <span class="comment">// &#125;</span></span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="title">showName</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="comment">// &#123;</span></span><br><span class="line">    <span class="comment">//     cout &lt;&lt; this-&gt;m_Age &lt;&lt; endl;</span></span><br><span class="line">    <span class="comment">//     cout &lt;&lt; this-&gt;m_Name &lt;&lt; endl;</span></span><br><span class="line">    <span class="comment">// &#125;</span></span><br><span class="line">    T1 m_Name;</span><br><span class="line">    T2 m_Age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span>,<span class="keyword">class</span> <span class="title class_">T2</span>&gt; </span><br><span class="line">Person&lt;T1,T2&gt; :: <span class="built_in">Person</span>(T1 name ,T2 age)</span><br><span class="line">&#123;</span><br><span class="line">    <span class="keyword">this</span>-&gt;m_Age=age;</span><br><span class="line">    <span class="keyword">this</span>-&gt;m_Name=name;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span>,<span class="keyword">class</span> <span class="title class_">T2</span>&gt;</span><br><span class="line"><span class="type">void</span> Person&lt;T1,T2&gt; :: <span class="built_in">showName</span>()</span><br><span class="line">&#123;</span><br><span class="line">    cout &lt;&lt; <span class="keyword">this</span>-&gt;m_Name &lt;&lt; endl;</span><br><span class="line">    cout &lt;&lt; <span class="keyword">this</span>-&gt;m_Age &lt;&lt; endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Person&lt;string,<span class="type">int</span>&gt;<span class="built_in">p</span>(<span class="string">&quot;John&quot;</span>,<span class="number">18</span>);</span><br><span class="line">    p.<span class="built_in">showName</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>总结：类模板中的成员函数类外实现时，要加上模板参数列表.</p><h4 id="类模板分文件编写"><a href="#类模板分文件编写" class="headerlink" title="类模板分文件编写"></a>类模板分文件编写</h4><p>类模板成员函数创建实际是在调用阶段 ，导致分文件编写时链接不到</p><ul><li>直接包含.cpp源文件</li><li>将声明和实现写到同一个文件当中，并更改后缀名为.hpp.  .hpp是约定的名称，并不是强制的</li></ul><p>​普通类中的成员函数一开始就可以创建</p><p>​类模板中的成员函数在调用时才创建</p><p>总结：主流的解决方式是第二种，将类模板和成员函数写到一起，并将后缀名改为.hpp</p><h4 id="类模板与友元"><a href="#类模板与友元" class="headerlink" title="类模板与友元"></a>类模板与友元</h4><p>全局函数实现 – 直接在类内声明友元即可</p><p>全局函数类外实现 – 提前让编译器知道全局函数的存在</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span>,<span class="keyword">class</span> <span class="title class_">T2</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//类外实现</span></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span> ,<span class="keyword">class</span> <span class="title class_">T2</span>&gt;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">printPerson2</span><span class="params">(Person&lt;T1,T2&gt; p)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    cout &lt;&lt; p.m_Name&lt;&lt;endl;</span><br><span class="line">    cout &lt;&lt; p.m_Age&lt;&lt;endl;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//通过全局函数打印Person的信息</span></span><br><span class="line"><span class="keyword">template</span> &lt;<span class="keyword">class</span> <span class="title class_">T1</span> ,<span class="keyword">class</span> <span class="title class_">T2</span>&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">//全局函数类内实现</span></span><br><span class="line">    <span class="function"><span class="keyword">friend</span> <span class="type">void</span> <span class="title">printPerson</span><span class="params">(Person&lt;T1,T2&gt; p)</span></span></span><br><span class="line"><span class="function">    </span>&#123;</span><br><span class="line">        cout &lt;&lt; p.m_Name&lt;&lt;endl;</span><br><span class="line">        cout &lt;&lt; p.m_Age&lt;&lt;endl;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//全局函数类外实现</span></span><br><span class="line">    <span class="comment">//加空模板的参数列表</span></span><br><span class="line">    <span class="keyword">friend</span> <span class="type">void</span> printPerson2&lt;&gt;(Person&lt;T1,T2&gt; p);</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="built_in">Person</span>(T1 name ,T2 age)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">this</span>-&gt;m_Name=name;</span><br><span class="line">        <span class="keyword">this</span>-&gt;m_Age=age;</span><br><span class="line">    &#125;</span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line">    T1 m_Name;</span><br><span class="line">    T2 m_Age;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Person &lt;string ,<span class="type">int</span>&gt; <span class="built_in">p</span> (<span class="string">&quot;Hello&quot;</span>,<span class="number">18</span>);</span><br><span class="line">    <span class="built_in">printPerson</span>(p);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">test01</span><span class="params">()</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    Person &lt;string ,<span class="type">int</span>&gt;   <span class="built_in">p</span>(<span class="string">&quot;ahjsd&quot;</span>,<span class="number">19</span>);</span><br><span class="line">    <span class="built_in">printPerson2</span>(p);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>总结：建议全局函数做类内实现，用法简单，而且编译器可以直接识别</p><p>总结： 字符串拼接的重载版本很多，记住几种即可.</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;C-初始&quot;&gt;&lt;a href=&quot;#C-初始&quot; class=&quot;headerlink&quot; title=&quot;C++初始&quot;&gt;&lt;/a&gt;C++初始&lt;/h1&gt;&lt;h2 id=&quot;1-编写C-程序步骤&quot;&gt;&lt;a href=&quot;#1-编写C-程序步骤&quot; class=&quot;headerlink&quot; ti</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    
    <category term="c++" scheme="https://future.thisis.host/tags/c/"/>
    
    <category term="grammar" scheme="https://future.thisis.host/tags/grammar/"/>
    
  </entry>
  
  <entry>
    <title>内存申请和释放</title>
    <link href="https://future.thisis.host/2024/03/04/%E5%86%85%E5%AD%98%E7%94%B3%E8%AF%B7%E5%92%8C%E9%87%8A%E6%94%BE/"/>
    <id>https://future.thisis.host/2024/03/04/%E5%86%85%E5%AD%98%E7%94%B3%E8%AF%B7%E5%92%8C%E9%87%8A%E6%94%BE/</id>
    <published>2024-03-04T00:00:00.000Z</published>
    <updated>2025-08-22T10:57:47.356Z</updated>
    
    <content type="html"><![CDATA[<h2 id="malloc-free"><a href="#malloc-free" class="headerlink" title="malloc&amp;free"></a>malloc&amp;free</h2><p>malloc(0)返回一个有效的空间长度为0的内存首地址，但是没法用(只能进行申请和释放).</p><p><strong>动态申请数组指针</strong>：</p><blockquote><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">int</span> (*P)[<span class="number">3</span>]=(<span class="built_in">int</span>(*)[<span class="number">3</span>])=<span class="built_in">malloc</span>(<span class="built_in">sizeof</span>(<span class="type">int</span>)*<span class="number">3</span>);</span><br><span class="line"><span class="built_in">int</span> (*q)[<span class="number">2</span>][<span class="number">3</span>]=(<span class="built_in">int</span>(*)[<span class="number">2</span>][<span class="number">3</span>])<span class="built_in">malloc</span>(<span class="built_in">sizeof</span>(<span class="type">int</span>)*<span class="number">6</span>);</span><br></pre></td></tr></table></figure></blockquote><p><strong>初始化</strong>：</p><p><code>malloc</code>函数分配得到的内存是未初始化的.一般在使用该内存空间时，要调用<code>memset</code>来初始化为0.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span>* <span class="title">memset</span><span class="params">(<span class="type">void</span> *dest,<span class="type">int</span> c,<span class="type">size_t</span> count)</span></span>;</span><br></pre></td></tr></table></figure><p>该函数可以将指定的内存空间按字节单位置为指定的字符c。其中，<code>dest</code>为要清零的内存空间的首地址，c为要设定的值，count为被操作的内存空间的字节长度。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">void* memcpy(void* dest, void* src, size_t count);</span><br></pre></td></tr></table></figure><p>此函数也是按照字节进行拷贝的，<code>dest</code>指向目标地址的指针，也就是要被赋值的空间首地址；<code>src</code>指向源地址的指针，也就是要被复制的空间的首地址；count跟<code>memset()</code>一样表示被拷贝的字节数；返回值也是被赋值的目标地址的指针。</p><p><strong>其他申请方式</strong>：</p><p><code>calloc</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span>* <span class="title">calloc</span><span class="params">(<span class="type">size_t</span> num, <span class="type">size_t</span> size)</span></span>; </span><br></pre></td></tr></table></figure><p><code>realloc</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span>* <span class="title">realloc</span><span class="params">(<span class="type">void</span>* memblock, <span class="type">size_t</span> size)</span></span>;  <span class="comment">// 为已分配的内存空间重新申请内存块</span></span><br></pre></td></tr></table></figure><p><code>_msize</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">size_t</span> _msize(<span class="type">void</span>* memblock);  <span class="comment">// Windows平台下专用函数，非C语言标准函数</span></span><br></pre></td></tr></table></figure><p>返回<code>malloc() &amp; calloc() &amp; realloc()</code>等申请内存块的大小，参数是分配内存块的首地址，也就是<code>malloc() &amp; calloc() &amp; realloc()</code>等的返回值。</p><p><strong>free</strong></p><p>用<code>malloc()</code>申请一块内存空间，OS会有一张表记录所申请空间的首地址和这块地址的长度，free(空间首地址)，free会从表中查找到这块首地址对应的内存大小，一并释放掉。</p><ol><li>free()不能去释放栈区的空间，栈区空间是由OS管理的，由OS进行申请和释放。</li><li>释放空间后，指针需要置空，避免成为野指针。</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span>* q = (<span class="type">int</span>*)<span class="built_in">malloc</span>(<span class="number">3</span>);</span><br><span class="line"><span class="built_in">free</span>(q);  <span class="comment">// 会报错，int型指针一次操作 4Byte，这里只申请了 3Byte 相当去别人的地盘上拆东西，那肯定是不允许的</span></span><br><span class="line"><span class="type">int</span>* n = (<span class="type">int</span>*)<span class="built_in">malloc</span>(<span class="number">7</span>);  <span class="comment">// 允许多申请，但是 int型指针一次只能操作 4Byte 多余的空间浪费了</span></span><br><span class="line"><span class="built_in">free</span>(n);  <span class="comment">// 释放时，从OS维护的表中查找到空间长度，会一并释放掉</span></span><br></pre></td></tr></table></figure><h2 id="new-delete"><a href="#new-delete" class="headerlink" title="new &amp; delete"></a>new &amp; delete</h2><h3 id="new"><a href="#new" class="headerlink" title="new"></a>new</h3><p>new 在申请基本类型空间时，主要会经历两个过程：</p><ol><li>调用 <code>operator new(size_t)</code> 或 <code>operator new[] (size_t)</code> 申请空间</li><li>进行强制类型转换</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ====== 申请单个空间 ======</span></span><br><span class="line">type* p = <span class="keyword">new</span> type;</span><br><span class="line"><span class="comment">// 执行上面这条语句实际的过程是下面的语句</span></span><br><span class="line"><span class="type">void</span>* tmp = <span class="keyword">operator</span> <span class="built_in">new</span>(<span class="built_in">sizeof</span>(type));       <span class="comment">// 调用 operator new(size_t) 申请空间</span></span><br><span class="line">type* p = <span class="built_in">static_cast</span>&lt;type*&gt;(tmp); <span class="comment">// 进行强制类型转换</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// ====== 申请数组空间 ======</span></span><br><span class="line">type* q = <span class="keyword">new</span> type[N];</span><br><span class="line"><span class="comment">// 执行上面这条语句实际的过程是下面的语句</span></span><br><span class="line"><span class="type">void</span>* tmp = <span class="keyword">operator</span> <span class="keyword">new</span>[](<span class="built_in">sizeof</span>(type) * N); <span class="comment">// 调用 operator new[](size_t) 申请空间</span></span><br><span class="line">type* p = <span class="built_in">static_cast</span>&lt;type*&gt;(tmp); <span class="comment">// 进行强制类型转换</span></span><br></pre></td></tr></table></figure><p><code>static_cast</code></p><p>是一种用于显示类型转换的强制转换运算符。是一个编译时运算符，用于在兼容类型之间执行转换.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">static_cast</span>&lt;new_type&gt;(expression)</span><br><span class="line"><span class="type">int</span> integerNumber = <span class="number">42</span>;</span><br><span class="line"><span class="type">double</span> doubleNumber = <span class="built_in">static_cast</span>&lt;<span class="type">double</span>&gt;(integerNumber);</span><br></pre></td></tr></table></figure><p>new 在申请 object 空间时，主要会经历三个过程：</p><p>​1.调用 <code>operator new(size_t)</code> 或 <code>operator new[] (size_t)</code> 申请空间</p><p>​2.进行强制类型转换</p><p>​3.调用类的构造函数</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ====== 申请单个object ======</span></span><br><span class="line">classname* p = <span class="keyword">new</span> classname;</span><br><span class="line"><span class="comment">// 执行上面的语句实际的过程是下面的条语句</span></span><br><span class="line"><span class="type">void</span>* tmp = <span class="keyword">operator</span> <span class="built_in">new</span>(<span class="built_in">sizeof</span>(classname)); <span class="comment">// 调用 operator new(size_t) 申请空间</span></span><br><span class="line">classname* p = <span class="built_in">static_cast</span>&lt;classname*&gt;(tmp);  <span class="comment">// 进行强制类型转换</span></span><br><span class="line">p-&gt;classname::<span class="built_in">classname</span>(); <span class="comment">// 调用类的构造函数，用户不允许这样调用构造函数，如果用户想调用可以通过 定位(placement)new 运算符 的方式调用</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// ====== 申请object数组空间 ======</span></span><br><span class="line">classname* q = <span class="keyword">new</span> classname[N];</span><br><span class="line"><span class="comment">// 执行上面的语句实际的过程是下面的条语句</span></span><br><span class="line"><span class="type">void</span>* tmp = <span class="keyword">operator</span> <span class="keyword">new</span>[](<span class="built_in">sizeof</span>(classname) * N + <span class="number">4</span>); <span class="comment">// 调用 operator new[](size_t) 申请空间</span></span><br><span class="line">classname* q = <span class="built_in">static_cast</span>&lt;classname*&gt;(tmp + <span class="number">4</span>); <span class="comment">// 进行强制类型转换</span></span><br><span class="line">q-&gt;classname::<span class="built_in">classname</span>(); <span class="comment">// 调用 N次 构造函数</span></span><br></pre></td></tr></table></figure><p><strong>注意</strong>：</p><p>申请的空间大小为</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">sizeof</span>(classname)*N<span class="number">+4</span>;</span><br></pre></td></tr></table></figure><p>前4个字节写入数组大小，最后调用N次构造函数。</p><p>这里为什么要写入数组大小呢？释放内存之前会调用每个对象的析构函数。但是编译器并不知道 q 实际所指对象的大小。如果没有储存数组大小，编译器如何知道该把p所指的内存分为几次来调用析构函数呢？</p><p>new[] 调用的是operator new[]，计算出数组总大小之后调用operator new。值得一提的是，可以通过()初始化数组为零值，实例：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">char</span>* p = <span class="keyword">new</span> <span class="type">char</span>[<span class="number">32</span>]();</span><br></pre></td></tr></table></figure><p>等同于：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">char</span> *p = <span class="keyword">new</span> <span class="type">char</span>[<span class="number">32</span>];</span><br><span class="line"><span class="built_in">memset</span>(p, <span class="number">32</span>, <span class="number">0</span>);</span><br></pre></td></tr></table></figure><p><strong>new的底层</strong></p><p><strong><code>operator new(size_t)</code></strong> 是系统提供的全局函数，其 <strong>底层是由</strong> <code>malloc</code> <strong>实现的：</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">operator new：该函数实际通过malloc来申请空间，当malloc申请空间成功时直接返回；申请空间失败，尝试</span></span><br><span class="line"><span class="comment">执行空 间不足应对措施，如果改应对措施用户设置了，则继续申请，否则抛异常。</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="type">void</span> *__CRTDECL <span class="keyword">operator</span> <span class="title">new</span><span class="params">(<span class="type">size_t</span> size)</span> _<span class="title">THROW1</span><span class="params">(_STD bad_alloc)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// try to allocate size bytes</span></span><br><span class="line">    <span class="type">void</span> *p;</span><br><span class="line">    <span class="keyword">while</span> ((p = <span class="built_in">malloc</span>(size)) == <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">if</span> (_callnewh(size) == <span class="number">0</span>)<span class="comment">//是否注册了新的处理程序，没有则继续循环试图分配空间.</span></span><br><span class="line">        &#123;</span><br><span class="line">            <span class="comment">// report no memory</span></span><br><span class="line">            <span class="comment">// 如果申请内存失败了，这里会抛出bad_alloc 类型异常</span></span><br><span class="line">            <span class="type">static</span> <span class="type">const</span> std::bad_alloc nomem;</span><br><span class="line">            _RAISE(nomem);</span><br><span class="line">        &#125;</span><br><span class="line">    <span class="keyword">return</span> (p);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="delete"><a href="#delete" class="headerlink" title="delete"></a>delete</h3><p>delete 的过程与 new 很相似，会调用 <code>operator delete(void*)</code> 或 <code>operator delete[] (void*)</code> 释放内存。</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">delete</span> p;</span><br><span class="line"><span class="comment">// 执行上面的代码实际过程是下面的语句</span></span><br><span class="line"><span class="function"><span class="keyword">operator</span> <span class="title">delete</span><span class="params">(p)</span></span>; <span class="comment">// 调用 operator delete(void*); 释放空间</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">delete</span>[] q;</span><br><span class="line"><span class="comment">// 执行上面的代码实际过程是下面的语句</span></span><br><span class="line"><span class="keyword">operator</span> <span class="keyword">delete</span>[](q); <span class="comment">// 调用 operator delete[](q); 释放空间</span></span><br></pre></td></tr></table></figure><p>delete 释放 object 空间</p><ol><li>调用类的析构函数</li><li>调用 <code>operator delete(void*)</code> 或 <code>operator delete[] (void*)</code> 释放内存</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">delete</span> obj;</span><br><span class="line"><span class="comment">// 执行上面的语句实际过程是下面的语句</span></span><br><span class="line">obj-&gt;~<span class="built_in">classname</span>(); <span class="comment">// 首先调用类的析构函数</span></span><br><span class="line"><span class="function"><span class="keyword">operator</span> <span class="title">delete</span><span class="params">(obj)</span></span>;   <span class="comment">// 调用 operator delete(void*); 释放 object 内存空间</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">delete</span>[] obj1;</span><br><span class="line"><span class="comment">// 执行上面的语句实际过程是下面的语句</span></span><br><span class="line">obj-&gt;~<span class="built_in">classname</span>(); <span class="comment">// 调用 N次 类的析构函数</span></span><br><span class="line"><span class="keyword">operator</span> <span class="keyword">delete</span>[](obj1); <span class="comment">// 调用 operator delete[](void*); 释放 object 内存空间</span></span><br></pre></td></tr></table></figure><p>new[]分配的内存只能由delete[]释放。如果由delete释放会崩溃，假设指针<code>obj1</code>指向new[]分配的内存，因为要4字节存储数组大小，实际分配的内存地址为<code>obj1-4</code>，系统记录的也是这个地址。<code>delete[]</code> 实际释放的就是<code>obj1-4</code>指向的内存。而<code>delete</code>会直接释放<code>obj1</code>指向的内存，这个内存根本没有被系统记录，所以会崩溃。</p><p><strong>delete底层</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">operator delete: 该函数最终是通过free来释放空间的</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *pUserData)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">_CrtMemBlockHeader * pHead;</span><br><span class="line"></span><br><span class="line"><span class="built_in">RTCCALLBACK</span>(_RTC_Free_hook, (pUserData, <span class="number">0</span>));</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (pUserData == <span class="literal">NULL</span>)</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">_mlock(_HEAP_LOCK); <span class="comment">/* block other threads */</span></span><br><span class="line">__TRY</span><br><span class="line"><span class="comment">/* get a pointer to memory block header */</span></span><br><span class="line">pHead = <span class="built_in">pHdr</span>(pUserData);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* verify block type */</span></span><br><span class="line">_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead-&gt;nBlockUse));</span><br><span class="line"></span><br><span class="line"> _free_dbg( pUserData, pHead-&gt;nBlockUse );</span><br><span class="line"></span><br><span class="line">__FINALLY</span><br><span class="line">_munlock(_HEAP_LOCK); <span class="comment">/* release other threads */</span></span><br><span class="line">__END_TRY_FINALLY</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">free的实现</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> free(p) _free_dbg(p, _NORMAL_BLOCK)</span></span><br></pre></td></tr></table></figure><p><strong>总结</strong>：</p><p>在<code>new</code>一个数组时，与malloc相似，os会维护一张记录数组头指针和数组长度的表.</p><p>释放基本数据类型的指针时，数组的头指针最终会被free（q）释放，所以调用delete q或者delete[] q,最终的结果都是调用free(q);</p><p>释放自定义类型的数组时，如果类中有需要在析构函数中释放，直接调用delete obj只会调用一次析构函数，后执行free()，就没有调用其他的析构函数，会造成内存泄漏.<strong>一定调用delete[] obj释放内存</strong>。</p><h2 id="new-和-delete的重写和重载"><a href="#new-和-delete的重写和重载" class="headerlink" title="new 和 delete的重写和重载"></a>new 和 delete的重写和重载</h2><p>这两个函数在使用时，其实执行的是全局的<code>::operator new</code>和<code>::operator delete</code>，如果我们在类中重载了这两个函数，那么就会调用我们实现的，没有则使用全局的. 对于基本数据类型则使用全局的.</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//全局运算符定义格式</span></span><br><span class="line"><span class="function"><span class="type">void</span>* <span class="keyword">operator</span> <span class="title">new</span><span class="params">(<span class="type">size_t</span> size [, param1, param2,....])</span></span>;</span><br><span class="line"><span class="function"><span class="type">void</span> <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *p [, param1, param2, ...])</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">//类内运算符定义格式</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">CA</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="type">void</span>* <span class="keyword">operator</span> <span class="title">new</span><span class="params">(<span class="type">size_t</span> size [, param1, param2,....])</span></span>;</span><br><span class="line">    <span class="function"><span class="type">void</span> <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *p [, param1, param2, ...])</span></span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p><strong>标准库提供的全局的 operator new( 函数 ) 有六种重载形式，operator delete也有六种重载形式：</strong></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// =======================new=========================//</span></span><br><span class="line"><span class="function"><span class="type">void</span> *<span class="keyword">operator</span> <span class="title">new</span><span class="params">(std::<span class="type">size_t</span> count)</span></span></span><br><span class="line"><span class="function">    <span class="title">throw</span><span class="params">(std::bad_alloc)</span></span>;              <span class="comment">// 一般的版本</span></span><br><span class="line"><span class="type">void</span> *<span class="keyword">operator</span> <span class="keyword">new</span>[](std::<span class="type">size_t</span> count)  </span><br><span class="line">    <span class="built_in">throw</span>(std::bad_alloc);</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="type">void</span> *<span class="keyword">operator</span> <span class="title">new</span><span class="params">(std::<span class="type">size_t</span> count,   <span class="comment">// 兼容早版本的 new</span></span></span></span><br><span class="line"><span class="params"><span class="function">    <span class="type">const</span> std::<span class="type">nothrow_t</span> <span class="type">const</span>&amp;)</span> <span class="title">throw</span><span class="params">()</span></span>;     <span class="comment">// 内存分配失败不会抛出异常</span></span><br><span class="line"><span class="type">void</span> *<span class="keyword">operator</span> <span class="keyword">new</span>[](std::<span class="type">size_t</span> count,  </span><br><span class="line">    <span class="type">const</span> std::<span class="type">nothrow_t</span> <span class="type">const</span>&amp;) <span class="built_in">throw</span>();</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="type">void</span> *<span class="keyword">operator</span> <span class="title">new</span><span class="params">(std::<span class="type">size_t</span> count, <span class="type">void</span> *ptr)</span> <span class="title">throw</span><span class="params">()</span></span>;  <span class="comment">// placement 版本</span></span><br><span class="line"><span class="type">void</span> *<span class="keyword">operator</span> <span class="keyword">new</span>[](std::<span class="type">size_t</span> count, <span class="type">void</span> *ptr) <span class="built_in">throw</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// ======================delete========================//</span></span><br><span class="line"><span class="function"><span class="type">void</span> * <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *)</span> <span class="keyword">noexcept</span></span>;</span><br><span class="line"><span class="type">void</span> * <span class="keyword">operator</span> <span class="keyword">delete</span>[](<span class="type">void</span> *) <span class="keyword">noexcept</span>;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="type">void</span> * <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *, std::<span class="type">nothrow_t</span> <span class="type">const</span>&amp;)</span> <span class="keyword">noexcept</span></span>;</span><br><span class="line"><span class="type">void</span> * <span class="keyword">operator</span> <span class="keyword">delete</span>[](<span class="type">void</span> *, std::<span class="type">nothrow_t</span> <span class="type">const</span>&amp;) <span class="keyword">noexcept</span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> * <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *, <span class="type">void</span> *)</span> <span class="keyword">noexcept</span></span>;</span><br><span class="line"><span class="type">void</span> * <span class="keyword">operator</span> <span class="keyword">delete</span>[](<span class="type">void</span> *, <span class="type">void</span> *) <span class="keyword">noexcept</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// VS C++下还有两个，GCC下不确定</span></span><br><span class="line"><span class="function"><span class="type">void</span> * <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *, <span class="type">size_t</span>)</span> <span class="keyword">noexcept</span></span>;</span><br><span class="line"><span class="type">void</span> * <span class="keyword">operator</span> <span class="keyword">delete</span>[](<span class="type">void</span> *, <span class="type">size_t</span>) <span class="keyword">noexcept</span>;</span><br></pre></td></tr></table></figure><p><code>new/delete</code>运算符重载规则:</p><ol><li>new和delete运算符重载必须成对出现。</li><li><strong>new运算符的第一个参数必须是size_t类型的，也就是指定分配内存的size尺寸；delete运算符的第一个参数必须是要销毁释放的内存对象。其他参数可以任意定义。</strong></li><li>系统默认实现了new&#x2F;delete、new[]&#x2F;delete[]、 placement new 5个运算符（expression）。它们都有特定的意义。使用它们在底层调用对应的函数，可以是系统提供的，也可能是被重写或重载的。</li><li>你可以重写默认实现的全局运算符，比如你想对内存的分配策略进行自定义管理或者你想监测堆内存的分配情况或者你想做堆内存的内存泄露监控等。<strong>但是你重写的全局运算符一定要满足默认的规则定义。也可以重载全局运算符，但也必须符合默认的规则，即第一个参数不能变。</strong></li><li>如果你想对某个类的堆内存分配的对象做特殊处理，那么你可以重载这个类的new&#x2F;delete运算符。当重载这两个运算符时虽然没有带static属性，但是不管如何对类的new&#x2F;delete运算符的重载总是被认为是静态成员函数。</li><li><strong>当delete运算符的参数&gt;&#x3D;2个时，就需要自己负责对象析构函数的调用，并且以运算符函数的形式来调用delete运算符。</strong></li><li>这里的重载遵循作用域覆盖原则，即在里向外寻找operator new的重载时，只要找到operator new()函数就不再向外查找，如果参数符合则通过，如果参数不符合则报错，而不管全局是否还有相匹配的函数原型。比如如果这里只将Foo中<code>operator new(size_t, const std::nothrow_t&amp;)</code>删除掉，就会在61行报错：</li></ol><p><strong>对象的自动删除</strong></p><p>一般来说系统对new&#x2F;delete的默认实现就能满足我们的需求，我们不需要再去重载这两个运算符。那为什么C++还提供对这两个运算符的重载支持呢？答案还是在运算符本身具有的缺陷所致。我们知道用new关键字来创建堆内存对象是分为了2步：1.是堆内存分配，2.是对象构造函数的调用。而这两步中的任何一步都有可能会产生异常。如果说是在第一步出现了问题导致内存分配失败则不会调用构造函数，这是没有问题的。如果说是在第二步构造函数执行过程中出现了异常而导致无法正常构造完成，那么就应该要将第一步中所分配的堆内存进行销毁。<strong>C++中规定如果一个对象无法完全构造那么这个对象将是一个无效对象，也不会调用析构函数。为了保证对象的完整性，当通过new分配的堆内存对象在构造函数执行过程中出现异常时就会停止构造函数的执行并且自动调用对应的delete运算符来对已经分配的堆内存执行销毁处理，这就是所谓的对象的自动删除技术</strong>。正是因为有了对象的自动删除技术才能解决对象构造不完整时会造成内存泄露的问题。</p><p><strong>全局delete运算符函数所支持的对象的自动删除技术虽然能解决对象本身的内存泄露问题，但是却不能解决对象构造函数内部的数据成员的内存分配泄露问题，此时我们需要将析构函数中需要释放的数据成员的内存在重载的operator delete函数中进行释放。</strong></p><p><strong>operator new运用技巧</strong></p><ul><li>用于调试</li><li>内存池优化</li><li>STL中的new</li></ul><h2 id="new和malloc的区别"><a href="#new和malloc的区别" class="headerlink" title="new和malloc的区别"></a>new和malloc的区别</h2><h3 id="内存的申请所在位置"><a href="#内存的申请所在位置" class="headerlink" title="内存的申请所在位置"></a>内存的申请所在位置</h3><p>new操作符从自由存储区（free store）上为对象动态分配内存空间，而<code>malloc</code>函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念，凡是通过new操作符进行内存申请，该内存即为自由存储区。而堆是操作系统中的术语，是操作系统所维护的一块特殊内存，用于程序的内存动态分配，C语言使用<code>malloc</code>从堆上分配内存，使用free释放已分配的对应内存。</p><p>那么自由存储区是否能够是堆（问题等价于new是否能在堆上动态分配内存），这取决于operator new 的实现细节。自由存储区不仅可以是堆，还可以是静态存储区，这都看operator new在哪里为对象分配内存。</p><p>特别的，new甚至可以不为对象分配内存！定位new的功能可以办到这一点：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span>(place_address) type</span><br></pre></td></tr></table></figure><p>place_address为一个指针，代表一块内存的地址。</p><h3 id="返回类型安全性"><a href="#返回类型安全性" class="headerlink" title="返回类型安全性"></a>返回类型安全性</h3><p>new返回对象类型的指针，类型严格匹配</p><p>而malloc返回<code>void *</code>,需要通过强制类型转换将<code>void *</code>转换成我们需要的类型.</p><h3 id="内存失败时的返回值"><a href="#内存失败时的返回值" class="headerlink" title="内存失败时的返回值"></a>内存失败时的返回值</h3><p>new内存分配失败时，会抛出<code>bac_alloc</code>异常，它不会返回NULL；<code>malloc</code>分配内存失败时返回NULL。</p><h3 id="是否需要指定内存大小"><a href="#是否需要指定内存大小" class="headerlink" title="是否需要指定内存大小"></a>是否需要指定内存大小</h3><p>使用new操作符申请内存分配时无须指定内存块的大小，编译器会根据类型信息自行计算，而<code>malloc</code>则需要显式地指出所需内存的尺寸。</p><h3 id="是否调用构造函数-析构函数"><a href="#是否调用构造函数-析构函数" class="headerlink" title="是否调用构造函数&#x2F;析构函数"></a>是否调用构造函数&#x2F;析构函数</h3><p>使用new操作符来分配对象内存时会经历三个步骤：</p><ol><li>第一步：调用operator new 函数（对于数组是operator new[]）分配一块足够大的，原始的，未命名的内存空间以便存储特定类型的对象。</li><li>第二步：编译器运行相应的构造函数以构造对象，并为其传入初值。</li><li>第三部：对象构造完成后，返回一个指向该对象的指针。</li></ol><p>使用delete操作符来释放对象内存时会经历两个步骤：</p><ol><li>第一步：调用对象的析构函数。</li><li>第二步：编译器调用operator delete(或operator delete[])函数释放内存空间。</li></ol><h3 id="对数组的处理"><a href="#对数组的处理" class="headerlink" title="对数组的处理"></a>对数组的处理</h3><p>C++提供了new[]与delete[]来专门处理数组类型，new[]分配的内存必须使用delete[]进行释放。</p><p>new对数组的支持体现在它会分别调用构造函数函数初始化每一个数组元素，释放对象时为每个对象调用析构函数。注意delete[]要与new[]配套使用，不然会找出数组对象部分释放的现象，造成内存泄漏。</p><p>至于<code>malloc</code>，它并知道你在这块内存上要放的数组还是啥别的东西，反正它就给你一块原始的内存，在给你个内存的地址就完事。所以如果要动态分配一个数组的内存，还需要我们手动自定数组的大小：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> * ptr = (<span class="type">int</span> *) <span class="built_in">malloc</span>( <span class="built_in">sizeof</span>(<span class="type">int</span>)* <span class="number">10</span> ); <span class="comment">//分配一个10个int元素的数组</span></span><br></pre></td></tr></table></figure><h3 id="new与malloc是否可以相互调用"><a href="#new与malloc是否可以相互调用" class="headerlink" title="new与malloc是否可以相互调用"></a>new与<code>malloc</code>是否可以相互调用</h3><p>operator new 的实现可以基于<code>malloc</code>，而<code>malloc</code>的实现不可以去调用new。</p><h3 id="是否可以被重载"><a href="#是否可以被重载" class="headerlink" title="是否可以被重载"></a>是否可以被重载</h3><p><code>opeartor new /operator delete</code>可以被重载。标准库是定义了operator new函数和operator delete函数的8个重载版本：</p><p>&#x2F;&#x2F; 这些版本可能抛出异常</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> * <span class="keyword">operator</span> <span class="title">new</span><span class="params">(<span class="type">size_t</span>)</span></span>;</span><br><span class="line"><span class="type">void</span> * <span class="keyword">operator</span> <span class="keyword">new</span>[](<span class="type">size_t</span>);</span><br><span class="line"><span class="function"><span class="type">void</span> * <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *)</span> <span class="keyword">noexcept</span></span>;</span><br><span class="line"><span class="type">void</span> * <span class="keyword">operator</span> <span class="keyword">delete</span>[](<span class="type">void</span> *) <span class="keyword">noexcept</span>;</span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 这些版本承诺不抛出异常</span></span><br><span class="line"><span class="function"><span class="type">void</span> * <span class="keyword">operator</span> <span class="title">new</span><span class="params">(<span class="type">size_t</span>, <span class="type">nothrow_t</span> <span class="type">const</span>&amp;)</span> <span class="keyword">noexcept</span></span>;</span><br><span class="line"><span class="type">void</span> * <span class="keyword">operator</span> <span class="keyword">new</span>[](<span class="type">size_t</span>, <span class="type">nothrow_t</span> <span class="type">const</span>&amp;) <span class="keyword">noexcept</span>;</span><br><span class="line"><span class="function"><span class="type">void</span> * <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *, <span class="type">nothrow_t</span> <span class="type">const</span>&amp;)</span> <span class="keyword">noexcept</span></span>;</span><br><span class="line"><span class="type">void</span> * <span class="keyword">operator</span> <span class="keyword">delete</span>[](<span class="type">void</span> *, <span class="type">nothrow_t</span> <span class="type">const</span>&amp;) <span class="keyword">noexcept</span></span><br></pre></td></tr></table></figure><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// VS C++下还有两个，GCC下不确定</span></span><br><span class="line"><span class="function"><span class="type">void</span> * <span class="keyword">operator</span> <span class="title">delete</span><span class="params">(<span class="type">void</span> *, <span class="type">size_t</span>)</span> <span class="keyword">noexcept</span></span>;</span><br><span class="line"><span class="type">void</span> * <span class="keyword">operator</span> <span class="keyword">delete</span>[](<span class="type">void</span> *, <span class="type">size_t</span>) <span class="keyword">noexcept</span>;</span><br></pre></td></tr></table></figure><p>我们可以重载上面函数版本中的任意一个，前提是自定义版本必须位于全局作用域或者类作用域中。总之，我们有足够的自由去重载operator new &#x2F;operator delete ，以决定我们的new与delete如何为对象分配内存，如何回收对象。</p><p>而<code>malloc/free</code>并不允许重载。</p><h3 id="能够直观地重新分配内存"><a href="#能够直观地重新分配内存" class="headerlink" title="能够直观地重新分配内存"></a>能够直观地重新分配内存</h3><p>使用<code>malloc</code>分配的内存后，如果在使用过程中发现内存不足，可以使用<code>realloc</code>函数进行内存重新分配实现内存的扩充。<code>realloc</code>先判断当前的指针所指内存是否有足够的连续空间，如果有，原地扩大可分配的内存地址，并且返回原来的地址指针；如果空间不够，先按照新指定的大小分配空间，将原有数据从头到尾拷贝到新分配的内存区域，而后释放原来的内存区域。</p><p>new没有这样直观的配套设施来扩充内存。</p><h3 id="客户处理内存分配不足"><a href="#客户处理内存分配不足" class="headerlink" title="客户处理内存分配不足"></a>客户处理内存分配不足</h3><p>在operator new抛出异常以反映一个未获得满足的需求之前，它会先调用一个用户指定的错误处理函数，这就是new_handler。new_handler是一个指针类型：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">namespace</span> std</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function"><span class="keyword">typedef</span> <span class="title">void</span> <span class="params">(*new_handler)</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>指向了一个没有参数没有返回值的函数，即为错误处理函数。为了指定错误处理函数，客户需要调用set_new_handler，这是一个声明于的一个标准库函数:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">namespace</span> std</span><br><span class="line">&#123;</span><br><span class="line">    <span class="function">new_handler <span class="title">set_new_handler</span><span class="params">(new_handler p )</span> <span class="title">throw</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>set_new_handler的参数为new_handler指针，指向了operator new 无法分配足够内存时该调用的函数。其返回值也是个指针，指向set_new_handler被调用前正在执行（但马上就要发生替换）的那个new_handler函数。</p><p>对于<code>malloc</code>，客户并不能够去编程决定内存不足以分配时要干什么事，只能看着<code>malloc</code>返回NULL。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;malloc-free&quot;&gt;&lt;a href=&quot;#malloc-free&quot; class=&quot;headerlink&quot; title=&quot;malloc&amp;amp;free&quot;&gt;&lt;/a&gt;malloc&amp;amp;free&lt;/h2&gt;&lt;p&gt;malloc(0)返回一个有效的空间长度为0的内存首</summary>
      
    
    
    
    <category term="notes" scheme="https://future.thisis.host/categories/notes/"/>
    
    <category term="c++" scheme="https://future.thisis.host/categories/notes/c/"/>
    
    
    <category term="memory" scheme="https://future.thisis.host/tags/memory/"/>
    
  </entry>
  
</feed>
