<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>flowwalker之码艺Blog</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://flowwalker.github.io/coding-notes-blog/</id>
  <link href="https://flowwalker.github.io/coding-notes-blog/" rel="alternate"/>
  <link href="https://flowwalker.github.io/coding-notes-blog/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, flowwalker之码艺Blog</rights>
  <subtitle>fingers flutter like butterflies over keys</subtitle>
  <title>码艺Blog</title>
  <updated>2026-07-21T12:55:14.471Z</updated>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="站务" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%AB%99%E5%8A%A1/"/>
    <category term="开篇" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E5%BC%80%E7%AF%87/"/>
    <content>
      <![CDATA[<p>这里是我的编程学习与实践笔记博客。</p><p>公式用 MathJax 渲染：</p><p>$$X(f) = \int_{-\infty}^{\infty} x(t)\, e^{-j2\pi f t}\, dt$$</p><p>在这个时代的潮流中，虽然手搓已经失去了效率一说，权威也被解构，那么——</p><p>似乎一切的自我陶醉都是一种自作多情，但</p><p>又何妨呢？</p><p>心中拥有美好，荒岛也能耕种出繁花～</p><p>孤芳自赏者，毋为世事倾侧。</p><p>主博客请访问 <a href="https://flowwalker.github.io/">flowwalker.github.io</a>。</p>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/3b26/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/3b26/"/>
    <published>2026-07-19T15:30:00.000Z</published>
    <summary>曾经翻飞双手，键盘中流声声震。</summary>
    <title>编程博客开张</title>
    <updated>2026-07-21T12:55:14.471Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--Python" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-Python/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="Python" scheme="https://flowwalker.github.io/coding-notes-blog/tags/Python/"/>
    <content>
      <![CDATA[<h1 id="Python修养3"><a href="#Python修养3" class="headerlink" title="Python修养3"></a>Python修养3</h1><h2 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h2><h3 id="基本说明"><a href="#基本说明" class="headerlink" title="基本说明"></a>基本说明</h3><ul><li><strong>可以返回多个值</strong></li><li>可以无参, 可以无返回</li><li>形参只拿到<strong>引用的副本</strong></li><li><strong>形参重新赋值, 不影响实参</strong></li><li>形参和实参<strong>指向同一个对象</strong>, 修改本地同时生效( ⚠️不是赋值, 赋值改变地方)</li><li>若执行过程中改变了形参<strong>所指向地方的内容</strong>, 实参也相应改变 (⚠️地方不变)</li></ul><blockquote><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">modify</span>(<span class="hljs-params">lst</span>): lst.append(<span class="hljs-number">99</span>)      <span class="hljs-comment"># ✅ 原地修改，外面看得见</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">reassign</span>(<span class="hljs-params">lst</span>): lst = [<span class="hljs-number">99</span>]          <span class="hljs-comment"># ❌ 重新赋值，改变了指向的地方，外面看不见</span>a = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]modify(a)<span class="hljs-built_in">print</span>(a)      <span class="hljs-comment"># [1, 2, 3, 99]</span>b = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]reassign(b)<span class="hljs-built_in">print</span>(b)      <span class="hljs-comment"># [1, 2, 3]  ← 没变！</span></code></pre><p>更明显的范例:</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>: n = <span class="hljs-number">0</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>: n = <span class="hljs-number">100</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">Swap1</span>(<span class="hljs-params">x, y</span>): tmp = x.n x.n = y.n y.n = tmp<span class="hljs-keyword">def</span> <span class="hljs-title function_">Swap2</span>(<span class="hljs-params">x, y</span>): x, y = y, xa = A()a.n = <span class="hljs-number">100</span>    <span class="hljs-comment"># 给实例 a 添加属性 n = 100</span>b = B()b.n = <span class="hljs-number">200</span>    <span class="hljs-comment"># 给实例 b 添加属性 n = 200</span>Swap1(a, b)<span class="hljs-built_in">print</span>(a.n, b.n)  <span class="hljs-comment"># 200 100，确实交换了</span>a = <span class="hljs-number">6</span>b = <span class="hljs-number">7</span>Swap2(a, b)<span class="hljs-built_in">print</span>(a, b)      <span class="hljs-comment"># 6 7，没交换！</span></code></pre></blockquote><h3 id="范式"><a href="#范式" class="headerlink" title="范式"></a>范式</h3><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">函数名</span>(<span class="hljs-params">参数<span class="hljs-number">1</span>,参数<span class="hljs-number">2</span>,...</span>):    语句组(即<span class="hljs-string">&quot;函数体&quot;</span>)<span class="hljs-comment"># 也可无参数</span></code></pre><h3 id="参数传递"><a href="#参数传递" class="headerlink" title="参数传递"></a>参数传递</h3><ul><li><p>默认参数</p></li><li><p>实参可带名字</p><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">a,b=<span class="hljs-number">1</span>,c=<span class="hljs-number">2</span></span>):    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;a=&#x27;</span>,a,<span class="hljs-string">&#x27;b=&#x27;</span>,b,<span class="hljs-string">&#x27;c=&#x27;</span>,c) func(<span class="hljs-number">10</span>,<span class="hljs-number">20</span>)func(<span class="hljs-number">30</span>,c=<span class="hljs-number">40</span>)func(c=<span class="hljs-number">50</span>,a=<span class="hljs-number">60</span>)</code></pre></li><li><p><strong>参数个数可以不定</strong>, <code>*b</code>传入元组</p><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">a,*b</span>): <span class="hljs-comment">#此处b将成为元组</span>    <span class="hljs-built_in">print</span>(b)c=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>]func(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-string">&#x27;ok&#x27;</span>,c)</code></pre><p>传入参数可以带<code>*</code>来解”框”</p><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">*b</span>):    <span class="hljs-built_in">print</span>(b,end=<span class="hljs-string">&#x27; however: &#x27;</span>)    <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> b:        <span class="hljs-built_in">print</span>(x,end=<span class="hljs-string">&#x27; &#x27;</span>)func(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>)<span class="hljs-built_in">print</span>()func(*[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>])<span class="hljs-built_in">print</span>()func(*(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>))<span class="hljs-built_in">print</span>()func((<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>))<span class="hljs-comment"># (1, 2, 3) however: 1 2 3 </span><span class="hljs-comment"># (1, 2, 3) however: 1 2 3 </span><span class="hljs-comment"># (1, 2, 3) however: 1 2 3 </span><span class="hljs-comment"># ((1, 2, 3),) however: (1, 2, 3)</span></code></pre></li><li><p><strong>参数可以不定</strong>, <code>**b</code>传入字典</p><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">**b</span>):    <span class="hljs-built_in">print</span>(b)func(p1=<span class="hljs-number">2</span>,p2=<span class="hljs-number">3</span>,p3=<span class="hljs-number">4</span>)<span class="hljs-comment"># &#123;&#x27;p1&#x27;: 2, &#x27;p2&#x27;: 3, &#x27;p3&#x27;: 4&#125;</span>a=&#123;<span class="hljs-string">&#x27;take&#x27;</span>:<span class="hljs-number">1</span>,<span class="hljs-string">&#x27;back&#x27;</span>:<span class="hljs-string">&#x27;this&#x27;</span>&#125;func(**a)<span class="hljs-comment"># &#123;&#x27;take&#x27;: 1, &#x27;back&#x27;: &#x27;this&#x27;&#125;</span></code></pre></li><li><p>函数中的变量, <strong>不加声明均为局部变量</strong></p><p>全局声明: <code>global x,y</code></p></li></ul><h3 id="python内置函数"><a href="#python内置函数" class="headerlink" title="python内置函数"></a>python内置函数</h3><ul><li>int(x)</li><li>float(x)</li><li>str(x)</li><li><strong>ord(x)</strong>  <strong>返回单个字符的Unicode 编码（整数)</strong></li><li><strong>chr(x)</strong></li><li>abs(x)</li><li>len(x)</li><li>max(x) <strong>x是列表,下同</strong></li><li>min(x)</li><li>max(x1,x2,…) 此处先视为列表后比较</li><li>min(x1,x2,…)</li><li>exit() 退出程序</li></ul><h3 id="跨文件引用函数和变量"><a href="#跨文件引用函数和变量" class="headerlink" title="跨文件引用函数和变量"></a>跨文件引用函数和变量</h3><p>t.py</p><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">hello</span>():    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;hello from t&#x27;</span>)haha=<span class="hljs-string">&#x27;ok&#x27;</span></code></pre><p>a.py</p><pre><code class="hljs python"><span class="hljs-keyword">from</span> t <span class="hljs-keyword">import</span> hello,haha<span class="hljs-comment"># 或者from t import *</span>hello() <span class="hljs-comment"># hello from t</span><span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;haha=&#x27;</span>,haha) <span class="hljs-comment"># haha=ok</span></code></pre><h2 id="OOP"><a href="#OOP" class="headerlink" title="OOP"></a>OOP</h2><h3 id="object类"><a href="#object类" class="headerlink" title="object类"></a>object类</h3><p><strong>所有类均自动由object类派生</strong></p><p>成员函数</p><ul><li><code>__init__</code> 构造函数</li><li><code>__eq__</code> 等号</li><li><code>__lt__</code> &lt;  即less than</li><li><code>__gt__</code> &gt;</li><li><code>__le__</code> &lt;&#x3D;</li><li><code>__ge__</code> &gt;&#x3D;</li><li><code>__ne__</code> !&#x3D;</li><li><code>__str__</code> 强制转换成str</li><li><code>__repr__</code> 强制转换为python可执行字符串</li><li><code>__del__</code> 析构函数</li><li>…</li></ul><h3 id="范式-1"><a href="#范式-1" class="headerlink" title="范式"></a>范式</h3><ul><li>构造函数和析构函数都<strong>只能有一个</strong></li><li>对象的<strong>成员变量可以随时添加</strong></li></ul><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x,y</span>):        <span class="hljs-variable language_">self</span>.x=x        <span class="hljs-variable language_">self</span>.y=y    <span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):        <span class="hljs-variable language_">self</span>.xx=<span class="hljs-number">9</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__del__</span>(<span class="hljs-params">self</span>):        <span class="hljs-built_in">print</span>(<span class="hljs-variable language_">self</span>.x,<span class="hljs-string">&quot;destructed&quot;</span>)    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__eq__</span>(<span class="hljs-params">self,b</span>):        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.x==b.x <span class="hljs-keyword">and</span> <span class="hljs-variable language_">self</span>.y==b.y    <span class="hljs-comment">#缺省情况下, 退回is, 比较id是否一样</span>a=A(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>)b=A(<span class="hljs-number">2</span>,<span class="hljs-number">3</span>)a.n2=<span class="hljs-number">28</span><span class="hljs-built_in">print</span>(a.n2)a.func()<span class="hljs-built_in">print</span>(a.xx)<span class="hljs-comment">#print(b.n2) #error</span><span class="hljs-built_in">print</span>(a.__eq__(b))<span class="hljs-built_in">print</span>(a==b)<span class="hljs-comment"># 均为False</span>a=<span class="hljs-number">8</span> <span class="hljs-comment"># 1 destructed</span></code></pre><blockquote><p>所谓比较id指的是, “地址”</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name</span>):<span class="hljs-variable language_">self</span>.name=namea=A(<span class="hljs-string">&quot;hh&quot;</span>)b=A(<span class="hljs-string">&quot;hh&quot;</span>)<span class="hljs-built_in">print</span>(a==b) <span class="hljs-comment">#此处的==退化为is</span><span class="hljs-comment">#False</span></code></pre><p>重载了<code>__eq__</code>后, 自动将<code>__hash__</code>设置为<code>None</code>, 需要手动设置回来才可哈希, 并且确保<strong>相等的值哈希值相等</strong></p><blockquote><p>关于<code>format</code>的语法</p><pre><code class="hljs python"><span class="hljs-string">&quot;(&#123;0.x&#125;,&#123;0.y&#125;)&quot;</span>.<span class="hljs-built_in">format</span>(<span class="hljs-variable language_">self</span>)</code></pre><table><thead><tr><th align="left">符号</th><th align="left">含义</th></tr></thead><tbody><tr><td align="left"><code>{0}</code></td><td align="left"><code>format()</code> 的第 <strong>0</strong> 个参数，也就是 <code>self</code></td></tr><tr><td align="left"><code>{0.x}</code></td><td align="left">第 0 个参数的 <code>.x</code> 属性，即 <code>self.x</code></td></tr><tr><td align="left"><code>{0.y}</code></td><td align="left">第 0 个参数的 <code>.y</code> 属性，即 <code>self.y</code></td></tr></tbody></table></blockquote><p>关于字符串重载的写法</p><p>(重载目的是 <strong>方便print</strong>)</p><blockquote><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">__str__</span>(<span class="hljs-params">self</span>):    <span class="hljs-comment"># 写法1：对象属性访问（你的代码）</span>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;(&#123;0.x&#125;,&#123;0.y&#125;)&quot;</span>.<span class="hljs-built_in">format</span>(<span class="hljs-variable language_">self</span>)    <span class="hljs-comment"># 写法2：拆开传（等价）</span>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;(&#123;&#125;,&#123;&#125;)&quot;</span>.<span class="hljs-built_in">format</span>(<span class="hljs-variable language_">self</span>.x, <span class="hljs-variable language_">self</span>.y)    <span class="hljs-comment"># 写法3：命名参数（等价）</span>    <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;(&#123;x&#125;,&#123;y&#125;)&quot;</span>.<span class="hljs-built_in">format</span>(x=<span class="hljs-variable language_">self</span>.x, y=<span class="hljs-variable language_">self</span>.y)    <span class="hljs-comment"># 写法4：f-string（最推荐）</span>    <span class="hljs-keyword">return</span> <span class="hljs-string">f&quot;(<span class="hljs-subst">&#123;self.x&#125;</span>,<span class="hljs-subst">&#123;self.y&#125;</span>)&quot;</span></code></pre></blockquote><p>python字符串的三种主要表示</p><table><thead><tr><th align="left">写法</th><th align="left">出现时间</th><th align="left">示例</th><th align="left">推荐度</th></tr></thead><tbody><tr><td align="left"><code>%</code> 格式化</td><td align="left">古老</td><td align="left"><code>&quot;%s is %d&quot; % (name, age)</code></td><td align="left">⭐⭐ 能跑，但过时了</td></tr><tr><td align="left"><code>.format()</code></td><td align="left">Python 2.6+</td><td align="left"><code>&quot;{} is {}&quot;.format(name, age)</code></td><td align="left">⭐⭐⭐ 兼容性好</td></tr><tr><td align="left"><strong>f-string</strong></td><td align="left">Python 3.6+</td><td align="left"><code>f&quot;{name} is {age}&quot;</code></td><td align="left"></td></tr></tbody></table></blockquote><h3 id="静态方法和类方法"><a href="#静态方法和类方法" class="headerlink" title="静态方法和类方法"></a>静态方法和类方法</h3><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span>:    school = <span class="hljs-string">&quot;PKU&quot;</span>           <span class="hljs-comment"># 类属性（全校统一）</span>        <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, name</span>):        <span class="hljs-variable language_">self</span>.name = name     <span class="hljs-comment"># 实例属性（每个人不同）</span>        <span class="hljs-comment"># ========== 普通方法 ==========</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">introduce</span>(<span class="hljs-params">self</span>):              <span class="hljs-comment"># self = 具体的某个学生</span>        <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;我是<span class="hljs-subst">&#123;self.name&#125;</span>，来自<span class="hljs-subst">&#123;self.school&#125;</span>&quot;</span>)        <span class="hljs-comment"># ========== 类方法 ==========</span><span class="hljs-meta">    @classmethod</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">change_school</span>(<span class="hljs-params">cls, new_name</span>): <span class="hljs-comment"># cls = Student 这个类本身</span>        cls.school = new_name        <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;全校改名了，现在叫<span class="hljs-subst">&#123;new_name&#125;</span>&quot;</span>)        <span class="hljs-comment"># ========== 静态方法 ==========</span><span class="hljs-meta">    @staticmethod</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">calc_score</span>(<span class="hljs-params">a, b</span>):             <span class="hljs-comment"># 跟学生、学校都没关系，就是个工具</span>        <span class="hljs-keyword">return</span> (a + b) / <span class="hljs-number">2</span>s = Student(<span class="hljs-string">&quot;Alice&quot;</span>)<span class="hljs-comment"># 普通方法：必须有个具体的学生</span>s.introduce()           <span class="hljs-comment"># ✅ 我是Alice，来自PKU</span>Student.introduce(s)    <span class="hljs-comment"># ✅ 等价写法，手动传self</span><span class="hljs-comment"># 类方法：通过类或实例都能调，改的是全校</span>Student.change_school(<span class="hljs-string">&quot;THU&quot;</span>)   <span class="hljs-comment"># ✅ 全校改名了</span>s.change_school(<span class="hljs-string">&quot;THU&quot;</span>)         <span class="hljs-comment"># ✅ 也能调，但改的是类属性</span><span class="hljs-comment"># 静态方法：就是个普通函数，放类里只是为了归类</span>Student.calc_score(<span class="hljs-number">80</span>, <span class="hljs-number">90</span>)     <span class="hljs-comment"># ✅ 85.0</span>s.calc_score(<span class="hljs-number">80</span>, <span class="hljs-number">90</span>)           <span class="hljs-comment"># ✅ 也能调，但跟 s 没关系</span></code></pre><ul><li><p><strong>类方法用于修改全类数据</strong>, 静态方法用于定义工具(如格式转换等), 普通方法用于操作<strong>某个具体对象的数据</strong></p></li><li><p>参见表格</p></li><li><table><thead><tr><th align="left"></th><th align="left"><strong>普通方法</strong></th><th align="left"><strong>类方法</strong></th><th align="left"><strong>静态方法</strong></th></tr></thead><tbody><tr><td align="left"><strong>定义格式</strong></td><td align="left"><code>def func(self)</code></td><td align="left"><code>@classmethod</code><br><code>def func(cls)</code></td><td align="left"><code>@staticmethod</code><br><code>def func()</code></td></tr><tr><td align="left"><strong>第一个参数</strong></td><td align="left"><code>self</code>（实例）<br><strong>表示知道自己属于哪个对象</strong></td><td align="left"><code>cls</code>（类本身）<br><strong>表示知道自己属于哪个类</strong></td><td align="left">没有</td></tr><tr><td align="left"><strong>访问实例属性</strong><br><code>self.name</code></td><td align="left">✅ 能</td><td align="left">❌ 不能</td><td align="left">❌ 不能</td></tr><tr><td align="left"><strong>访问类属性</strong><br><code>school</code></td><td align="left">能（通过<code>self.n</code>或者类名<code>A.n</code>或者<code>self.__class__.n</code>）</td><td align="left">✅ 能（通过<code>cls</code>）</td><td align="left">❌ 不能直接访问<br>（硬写类名可以，但不推荐）</td></tr><tr><td align="left"><strong>调用方式</strong></td><td align="left"><code>a.func()</code></td><td align="left"><code>A.func()</code> 或 <code>a.func()</code></td><td align="left"><code>A.func()</code> 或 <code>a.func()</code></td></tr><tr><td align="left"><strong>用途</strong></td><td align="left">操作具体某个对象的数据</td><td align="left">操作类本身的数据、<br>创建替代构造函数</td><td align="left">放在类里的工具函数<br><strong>（跟类数据无关）</strong></td></tr></tbody></table><blockquote><p>注: 此处普通方法利用<code>self.n</code>访问类属性, 属于查询机制, 先找实例对象,若无则查找类对象</p></blockquote><blockquote><p>此外还可以用类方法创建实例</p><pre><code class="hljs python">...<span class="hljs-meta">    @classmethod</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">from_string</span>(<span class="hljs-params">cls,string</span>):        value=<span class="hljs-built_in">int</span>(string)        <span class="hljs-keyword">return</span> cls(value)...obj=MyClass.from_string(<span class="hljs-string">&quot;42&quot;</span>)<span class="hljs-built_in">print</span>(obj.instance_attr)</code></pre></blockquote></li></ul><h3 id="访问范围"><a href="#访问范围" class="headerlink" title="访问范围"></a>访问范围</h3><h4 id="私有属性"><a href="#私有属性" class="headerlink" title="私有属性"></a>私有属性</h4><p>以<code>__</code>开头的变量 (两个<code>_</code>)</p><blockquote><p>注意: <code>_p</code>表示<strong>开发者约定为私有变量</strong>,仍然可以直接使用;  <code>__p</code> python会将其<strong>改名</strong>为<code>_类名__p</code>以<strong>强化私有变量的意味</strong>, 我们仍然可以使用改名后的变量</p><blockquote><p>python奉行”成年人”的观念</p><ul><li>名称改写机制<strong>防止子类意外覆盖父类的属性</strong></li><li>私有属性的命名是<strong>一种提示</strong>, 表示<strong>不应该</strong></li><li>通过限制对私有属性的直接访问, 类的设计者可以更自由地修改内部实现, 而不影响外部代码</li></ul></blockquote></blockquote><h3 id="property函数"><a href="#property函数" class="headerlink" title="property函数"></a>property函数</h3><h4 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h4><p>接收至多四个参数</p><ul><li><code>fget</code> 获取属性值的方法</li><li><code>fset </code> 设置属性值的方法</li><li><code>fdel </code> 删除属性值的方法</li><li><code>doc</code> 属性的文档字符串</li></ul><p>property是python的一个内部函数, 用于将<strong>一个方法转化为属性</strong></p><p>(方法伪装成属性, 调用时无需括号, <strong>看起来像是数据一样,实际内部调用了函数</strong>)</p><blockquote><p>解决的是私有后, 总是写获取&#x2F;修改&#x2F;设置&#x2F;删除接口的麻烦</p><p>实现 属性封装 和 计算属性</p></blockquote><h4 id="使用方法"><a href="#使用方法" class="headerlink" title="使用方法"></a>使用方法</h4><h5 id="way1"><a href="#way1" class="headerlink" title="way1"></a>way1</h5><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">foo</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):        <span class="hljs-variable language_">self</span>.name=<span class="hljs-string">&#x27;yoda&#x27;</span>        <span class="hljs-variable language_">self</span>.work=<span class="hljs-string">&#x27;master&#x27;</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">get_person</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.name,<span class="hljs-variable language_">self</span>.work    <span class="hljs-keyword">def</span> <span class="hljs-title function_">set_person</span>(<span class="hljs-params">self,value</span>):        <span class="hljs-variable language_">self</span>.name,<span class="hljs-variable language_">self</span>.work=value    person=<span class="hljs-built_in">property</span>(get_person,set_person)A3=foo()<span class="hljs-built_in">print</span>(A3.person) <span class="hljs-comment"># (&#x27;yoda&#x27;,&#x27;master&#x27;)</span>A3.person=<span class="hljs-string">&#x27;skylaer&#x27;</span>,<span class="hljs-string">&#x27;programmer&#x27;</span><span class="hljs-built_in">print</span>(A3.person) <span class="hljs-comment"># (&#x27;skylaer&#x27;,&#x27;programmer&#x27;)</span></code></pre><h5 id="way2-更简化"><a href="#way2-更简化" class="headerlink" title="way2(更简化)"></a>way2(更简化)</h5><p>使用<code>@property</code>将方法转化为属性</p><p>以及<code>@属性名.setter</code>和<code>属性名.deleter</code>来定义</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">foo</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self</span>):        <span class="hljs-variable language_">self</span>.name=<span class="hljs-string">&#x27;yoda&#x27;</span>        <span class="hljs-variable language_">self</span>.work=<span class="hljs-string">&#x27;master&#x27;</span>    <span class="hljs-comment">#将方法转换为属性</span><span class="hljs-meta">@property</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">person</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.name,<span class="hljs-variable language_">self</span>.work<span class="hljs-meta">@person.setter </span><span class="hljs-comment">#若不设置, 则为只读操作</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">person</span>(<span class="hljs-params">self,value</span>):        <span class="hljs-variable language_">self</span>.name,<span class="hljs-variable language_">self</span>.work=valueA3=foo()<span class="hljs-built_in">print</span>(A3.person)A3.person=<span class="hljs-string">&#x27;skylaer&#x27;</span>,<span class="hljs-string">&#x27;programmar&#x27;</span><span class="hljs-built_in">print</span>(A3.person)</code></pre><h4 id="用途"><a href="#用途" class="headerlink" title="用途"></a>用途</h4><h5 id="控制访问方式"><a href="#控制访问方式" class="headerlink" title="控制访问方式"></a>控制访问方式</h5><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Person</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,name</span>):        <span class="hljs-variable language_">self</span>._name=name<span class="hljs-meta">@property</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">name</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>._name<span class="hljs-meta">    @name.setter</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">name</span>(<span class="hljs-params">self,value</span>):        <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-built_in">isinstance</span>(value,<span class="hljs-built_in">str</span>):            <span class="hljs-keyword">raise</span> VauleError(<span class="hljs-string">&quot;Name must be a string&quot;</span>)<span class="hljs-variable language_">self</span>._name=valuep=Person(<span class="hljs-string">&quot;Alice&quot;</span>)p.name=<span class="hljs-number">123</span></code></pre><h5 id="动态计算属性"><a href="#动态计算属性" class="headerlink" title="动态计算属性"></a>动态计算属性</h5><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Rectangle</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,width,height</span>):        <span class="hljs-variable language_">self</span>.width=width        <span class="hljs-variable language_">self</span>.height=height<span class="hljs-meta">@property</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">area</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.width*<span class="hljs-variable language_">self</span>.heightr=Rectangle(<span class="hljs-number">5</span>,<span class="hljs-number">10</span>)<span class="hljs-built_in">print</span>(r.area)</code></pre><h5 id="隐藏内部实现细节"><a href="#隐藏内部实现细节" class="headerlink" title="隐藏内部实现细节"></a>隐藏内部实现细节</h5><p>以前的成员属性现在内部修改完, 外面也可以继续用</p><h3 id="运算符重载"><a href="#运算符重载" class="headerlink" title="运算符重载"></a>运算符重载</h3><p>直接记忆!</p><hr><h4 id="一、算术运算符"><a href="#一、算术运算符" class="headerlink" title="一、算术运算符"></a>一、算术运算符</h4><table><thead><tr><th>运算符</th><th>普通</th><th>反向（对象在右）</th><th>增量赋值（原地改）</th></tr></thead><tbody><tr><td><code>+</code></td><td><code>__add__</code></td><td><code>__radd__</code></td><td><code>__iadd__</code></td></tr><tr><td><code>-</code></td><td><code>__sub__</code></td><td><code>__rsub__</code></td><td><code>__isub__</code></td></tr><tr><td><code>*</code></td><td><code>__mul__</code></td><td><code>__rmul__</code></td><td><code>__imul__</code></td></tr><tr><td><code>/</code></td><td><code>__truediv__</code></td><td><code>__rtruediv__</code></td><td><code>__itruediv__</code></td></tr><tr><td><code>//</code></td><td><code>__floordiv__</code></td><td><code>__rfloordiv__</code></td><td><code>__ifloordiv__</code></td></tr><tr><td><code>%</code></td><td><code>__mod__</code></td><td><code>__rmod__</code></td><td><code>__imod__</code></td></tr><tr><td><code>**</code></td><td><code>__pow__</code></td><td><code>__rpow__</code></td><td><code>__ipow__</code></td></tr><tr><td><code>@</code></td><td><code>__matmul__</code></td><td><code>__rmatmul__</code></td><td><code>__imatmul__</code></td></tr></tbody></table><hr><h4 id="二、一元运算符"><a href="#二、一元运算符" class="headerlink" title="二、一元运算符"></a>二、一元运算符</h4><table><thead><tr><th>表达式</th><th>方法</th><th>说明</th></tr></thead><tbody><tr><td><code>-x</code></td><td><code>__neg__</code></td><td>负号</td></tr><tr><td><code>+x</code></td><td><code>__pos__</code></td><td>正号（一般返回自身）</td></tr><tr><td><code>abs(x)</code></td><td><code>__abs__</code></td><td>绝对值</td></tr><tr><td><code>~x</code></td><td><code>__invert__</code></td><td>按位取反</td></tr></tbody></table><hr><h4 id="三、比较运算符"><a href="#三、比较运算符" class="headerlink" title="三、比较运算符"></a>三、比较运算符</h4><table><thead><tr><th>运算符</th><th>方法</th><th>说明</th></tr></thead><tbody><tr><td><code>==</code></td><td><code>__eq__</code></td><td>等于</td></tr><tr><td><code>!=</code></td><td><code>__ne__</code></td><td>不等于</td></tr><tr><td><code>&lt;</code></td><td><code>__lt__</code></td><td>小于</td></tr><tr><td><code>&lt;=</code></td><td><code>__le__</code></td><td>小于等于</td></tr><tr><td><code>&gt;</code></td><td><code>__gt__</code></td><td>大于</td></tr><tr><td><code>&gt;=</code></td><td><code>__ge__</code></td><td>大于等于</td></tr></tbody></table><hr><h4 id="四、位运算符"><a href="#四、位运算符" class="headerlink" title="四、位运算符"></a>四、位运算符</h4><table><thead><tr><th>运算符</th><th>普通</th><th>反向</th><th>增量</th></tr></thead><tbody><tr><td><code>&amp;</code></td><td><code>__and__</code></td><td><code>__rand__</code></td><td><code>__iand__</code></td></tr><tr><td><code>|</code></td><td><code>__or__</code></td><td><code>__ror__</code></td><td><code>__ior__</code></td></tr><tr><td><code>^</code></td><td><code>__xor__</code></td><td><code>__rxor__</code></td><td><code>__ixor__</code></td></tr><tr><td><code>&lt;&lt;</code></td><td><code>__lshift__</code></td><td><code>__rlshift__</code></td><td><code>__ilshift__</code></td></tr><tr><td><code>&gt;&gt;</code></td><td><code>__rshift__</code></td><td><code>__rrshift__</code></td><td><code>__irshift__</code></td></tr></tbody></table><hr><h4 id="五、容器-序列（最常用）"><a href="#五、容器-序列（最常用）" class="headerlink" title="五、容器&#x2F;序列（最常用）"></a>五、容器&#x2F;序列（最常用）</h4><table><thead><tr><th>表达式</th><th>方法</th><th>说明</th></tr></thead><tbody><tr><td><code>len(x)</code></td><td><code>__len__</code></td><td>长度</td></tr><tr><td><code>x[i]</code></td><td><code>__getitem__</code></td><td>取值</td></tr><tr><td><code>x[i] = v</code></td><td><code>__setitem__</code></td><td>赋值</td></tr><tr><td><code>del x[i]</code></td><td><code>__delitem__</code></td><td>删除</td></tr><tr><td><code>x in s</code></td><td><code>__contains__</code></td><td>成员判断</td></tr><tr><td><code>for i in x:</code></td><td><code>__iter__</code></td><td>迭代</td></tr><tr><td><code>next(x)</code></td><td><code>__next__</code></td><td>生成器&#x2F;迭代器下一项</td></tr><tr><td><code>x()</code></td><td><code>__call__</code></td><td>把对象当函数调用, 相当于c++的operator()</td></tr><tr><td><code>with x:</code></td><td><code>__enter__</code> &#x2F; <code>__exit__</code></td><td>上下文管理器</td></tr></tbody></table><blockquote><p>老式迭代:</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">stepper</span>: <span class="hljs-keyword">def</span> <span class="hljs-title function_">__getitem__</span>(<span class="hljs-params">self, i</span>): <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.data[i] X = stepper() X.data = <span class="hljs-string">&#x27;Spam&#x27;</span> <span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> X: <span class="hljs-comment">#call __getitem__ ,for 语句自带异常处理</span><span class="hljs-built_in">print</span> (item)</code></pre><blockquote><p> <code>stepper</code> 虽然没写 <code>__iter__</code>，<code>for</code> 会<strong>自动按 i&#x3D;0,1,2,3… 去调 <code>__getitem__</code></strong>，直到 <code>self.data[i]</code> 越界抛出 <code>IndexError</code>，<code>for</code> 内部捕获后结束循环。</p><blockquote><p> <code>__getitem__</code> 为什么能被 <code>for</code> 用</p><p>Python 的 <code>for</code> 循环内部有个<strong>备胎机制</strong>：</p><pre><code class="hljs python"><span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> X:    ...</code></pre><p>实际执行的大致逻辑：</p><pre><code class="hljs python"><span class="hljs-comment"># 第1步：找 __iter__</span><span class="hljs-keyword">try</span>:    iterator = <span class="hljs-built_in">iter</span>(X)   <span class="hljs-comment"># 调用 X.__iter__()</span><span class="hljs-keyword">except</span> TypeError:    <span class="hljs-comment"># 第2步：如果没有 __iter__，就用 __getitem__ 硬凑</span>    i = <span class="hljs-number">0</span>    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:        <span class="hljs-keyword">try</span>:            item = X[i]      <span class="hljs-comment"># 调用 X.__getitem__(i)</span>            i += <span class="hljs-number">1</span>        <span class="hljs-keyword">except</span> (IndexError, StopIteration):            <span class="hljs-keyword">break</span>            <span class="hljs-comment"># 越界就停</span></code></pre></blockquote></blockquote><p>现代迭代:</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">stepper</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, data</span>):        <span class="hljs-variable language_">self</span>.data = data        <span class="hljs-keyword">def</span> <span class="hljs-title function_">__iter__</span>(<span class="hljs-params">self</span>):           <span class="hljs-comment"># 现代迭代协议</span>        <span class="hljs-keyword">return</span> <span class="hljs-built_in">iter</span>(<span class="hljs-variable language_">self</span>.data)    <span class="hljs-comment"># 直接返回一个迭代器</span><span class="hljs-comment"># 或者更完整：</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">stepper</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, data</span>):        <span class="hljs-variable language_">self</span>.data = data        <span class="hljs-variable language_">self</span>.index = <span class="hljs-number">0</span>        <span class="hljs-keyword">def</span> <span class="hljs-title function_">__iter__</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>        <span class="hljs-keyword">def</span> <span class="hljs-title function_">__next__</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">if</span> <span class="hljs-variable language_">self</span>.index &gt;= <span class="hljs-built_in">len</span>(<span class="hljs-variable language_">self</span>.data):            <span class="hljs-keyword">raise</span> StopIteration        result = <span class="hljs-variable language_">self</span>.data[<span class="hljs-variable language_">self</span>.index]        <span class="hljs-variable language_">self</span>.index += <span class="hljs-number">1</span>        <span class="hljs-keyword">return</span> result</code></pre></blockquote><h4 id="六、类型转换"><a href="#六、类型转换" class="headerlink" title="六、类型转换"></a>六、类型转换</h4><table><thead><tr><th>函数</th><th>方法</th></tr></thead><tbody><tr><td><code>str(x)</code></td><td><code>__str__</code></td></tr><tr><td><code>repr(x)</code></td><td><code>__repr__</code></td></tr><tr><td><code>int(x)</code></td><td><code>__int__</code></td></tr><tr><td><code>float(x)</code></td><td><code>__float__</code></td></tr><tr><td><code>bool(x)</code></td><td><code>__bool__</code></td></tr><tr><td><code>hash(x)</code></td><td><code>__hash__</code></td></tr></tbody></table><h4 id="七、输出重载"><a href="#七、输出重载" class="headerlink" title="七、输出重载"></a>七、输出重载</h4><p>字符串即可</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__str__</span>(<span class="hljs-params">self</span>):      <span class="hljs-comment"># print() 调用</span>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;我是str&quot;</span>        <span class="hljs-keyword">def</span> <span class="hljs-title function_">__repr__</span>(<span class="hljs-params">self</span>):     <span class="hljs-comment"># 交互式命令行/repr()调用</span>        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;我是repr&quot;</span>a = A()<span class="hljs-built_in">print</span>(a)        <span class="hljs-comment"># 我是str</span><span class="hljs-comment">#常用,面向用户</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">repr</span>(a))  <span class="hljs-comment"># 我是repr</span><span class="hljs-comment">#开发者调试用</span></code></pre><h4 id="注-不重载lt也可以排序-用key"><a href="#注-不重载lt也可以排序-用key" class="headerlink" title="注:不重载lt也可以排序(用key&#x3D;)"></a>注:不重载lt也可以排序(用key&#x3D;)</h4><pre><code class="hljs python"><span class="hljs-keyword">from</span> operator <span class="hljs-keyword">import</span> *<span class="hljs-keyword">class</span> <span class="hljs-title class_">Point</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x=<span class="hljs-number">0</span>,y=<span class="hljs-number">0</span></span>):        <span class="hljs-variable language_">self</span>.x=x        <span class="hljs-variable language_">self</span>.y=y<span class="hljs-keyword">def</span> <span class="hljs-title function_">__str__</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">return</span> <span class="hljs-string">&quot;(&quot;</span>+<span class="hljs-built_in">str</span>(<span class="hljs-variable language_">self</span>.x)+<span class="hljs-string">&quot;,&quot;</span>+<span class="hljs-built_in">str</span>(<span class="hljs-variable language_">self</span>.y)+<span class="hljs-string">&quot;)&quot;</span>a=[Point(<span class="hljs-number">3</span>,<span class="hljs-number">5</span>),Point(<span class="hljs-number">2</span>,<span class="hljs-number">1</span>),Point(<span class="hljs-number">4</span>,<span class="hljs-number">6</span>),Point(<span class="hljs-number">9</span>,<span class="hljs-number">0</span>)]a.sort(key=attrgetter(<span class="hljs-string">&#x27;x&#x27;</span>,<span class="hljs-string">&#x27;y&#x27;</span>)) <span class="hljs-comment">#先按x,后按y</span><span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> a:    <span class="hljs-built_in">print</span>(x,end=<span class="hljs-string">&#x27;&#x27;</span>)<span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;&#x27;</span>)a.sort(key=<span class="hljs-keyword">lambda</span> p:p.y)<span class="hljs-comment">#按y排序</span><span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> a:    <span class="hljs-built_in">print</span>(x,end=<span class="hljs-string">&#x27;&#x27;</span>)</code></pre><blockquote><p>注: <code>itemgetter</code> 用 <code>[]</code> 取（列表&#x2F;字典索引），<code>attrgetter</code> 用 <code>.</code> 取（对象属性）。</p><table><thead><tr><th align="left">工具</th><th align="left">操作符</th><th align="left">用于</th><th align="left">等价 lambda</th></tr></thead><tbody><tr><td align="left"><code>itemgetter(0)</code></td><td align="left"><code>x[0]</code></td><td align="left">列表、元组、字典</td><td align="left"><code>lambda x: x[0]</code></td></tr><tr><td align="left"><code>itemgetter(&#39;name&#39;)</code></td><td align="left"><code>x[&#39;name&#39;]</code></td><td align="left">字典</td><td align="left"><code>lambda x: x[&#39;name&#39;]</code></td></tr><tr><td align="left"><code>attrgetter(&#39;x&#39;)</code></td><td align="left"><code>obj.x</code></td><td align="left">对象的属性</td><td align="left"><code>lambda obj: obj.x</code></td></tr><tr><td align="left"><code>attrgetter(&#39;x&#39;, &#39;y&#39;)</code></td><td align="left"><code>(obj.x, obj.y)</code></td><td align="left">多属性</td><td align="left"><code>lambda obj: (obj.x, obj.y)</code></td></tr></tbody></table></blockquote><h3 id="泛型"><a href="#泛型" class="headerlink" title="泛型"></a>泛型</h3><p>变量类型本就可变, <strong>任何函数都相当于模板</strong></p><h3 id="继承和多态"><a href="#继承和多态" class="headerlink" title="继承和多态"></a>继承和多态</h3><h4 id="基本内容"><a href="#基本内容" class="headerlink" title="基本内容"></a>基本内容</h4><p>本来对象的类型就是运行时确定, 没有明显的多态 </p><blockquote><p>多态过于自然, 以至于感受不到</p></blockquote><p><code>class B(A):</code>  派生类定义</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x,y</span>):        <span class="hljs-variable language_">self</span>.x=x        <span class="hljs-variable language_">self</span>.y=y<span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):        <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;A::func&quot;</span>,<span class="hljs-variable language_">self</span>.x,<span class="hljs-variable language_">self</span>.y)<span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>(<span class="hljs-title class_ inherited__">A</span>):    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x,y,z</span>):        A.__init__(<span class="hljs-variable language_">self</span>,x,y) <span class="hljs-comment">#调用基类的构造函数</span>        <span class="hljs-variable language_">self</span>.z=z<span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):        A.func(<span class="hljs-variable language_">self</span>)        <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;B::func&quot;</span>,<span class="hljs-variable language_">self</span>.x,<span class="hljs-variable language_">self</span>.y,<span class="hljs-variable language_">self</span>.z)a=A(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>)b=B(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>)a.func()b.func()</code></pre><h4 id="调用父类函数的方式"><a href="#调用父类函数的方式" class="headerlink" title="调用父类函数的方式"></a>调用父类函数的方式</h4><ul><li>类名</li><li>super(type,obj)</li><li>super()</li></ul><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x,y</span>):        <span class="hljs-variable language_">self</span>.x=x        <span class="hljs-variable language_">self</span>.y=y    <span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):        <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;A::func&quot;</span>,<span class="hljs-variable language_">self</span>.x,<span class="hljs-variable language_">self</span>.y)<span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>(<span class="hljs-title class_ inherited__">A</span>):    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x,y,z</span>):        <span class="hljs-comment"># ✨🌟</span>        <span class="hljs-comment">#A.__init__(self,x,y) #调用基类的构造函数</span>        <span class="hljs-comment">#super(B,self).__init__(x,y)</span>        <span class="hljs-built_in">super</span>().__init__(x,y)        <span class="hljs-variable language_">self</span>.z=z    <span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):        A.func(<span class="hljs-variable language_">self</span>)        <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;B::func&quot;</span>,<span class="hljs-variable language_">self</span>.x,<span class="hljs-variable language_">self</span>.y,<span class="hljs-variable language_">self</span>.z)a=A(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>)b=B(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>)a.func()b.func()<span class="hljs-built_in">super</span>(B,b).func()</code></pre><p>注:<strong>类外部使用super(type,obj)</strong></p><blockquote><p>注: <code>isinstance</code>的用法</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:    <span class="hljs-keyword">pass</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>(<span class="hljs-title class_ inherited__">A</span>):    <span class="hljs-keyword">pass</span>a=A()b=B()<span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(a,A)) <span class="hljs-comment">#True</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(b,A)) <span class="hljs-comment">#True⚠️⚠️</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(a,B)) <span class="hljs-comment">#False</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">isinstance</span>(b,B)) <span class="hljs-comment">#True</span></code></pre></blockquote><h2 id="可哈希-hashable"><a href="#可哈希-hashable" class="headerlink" title="可哈希(hashable)"></a>可哈希(hashable)</h2><h3 id="基本内容-1"><a href="#基本内容-1" class="headerlink" title="基本内容"></a>基本内容</h3><ul><li><p><strong>不可变的内置对象, 可哈希</strong> ( 能通过 hash映射为一个整数)</p></li><li><p><strong>字典, 列表, 集合不可哈希</strong></p></li><li><p>自定义对象<strong>默认可哈希</strong></p><ul><li>重载了<code>__eq__</code><strong>默认不可哈希</strong>( python自动将<code>__hash__</code>设为<code>None</code>)</li><li>重载了<code>__eq__</code>需要重载<code>__hash__</code>才又可哈希</li></ul><blockquote><p>问题如下:</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">BadMutable</span>: <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, value</span>):     <span class="hljs-variable language_">self</span>.value = value <span class="hljs-keyword">def</span> <span class="hljs-title function_">__eq__</span>(<span class="hljs-params">self, other</span>):     <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.value == other.value <span class="hljs-comment"># 如果没设置成None，等价于:</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__hash__</span>(<span class="hljs-params">self</span>):     <span class="hljs-keyword">return</span> <span class="hljs-built_in">id</span>(<span class="hljs-variable language_">self</span>)obj1 = BadMutable(<span class="hljs-number">10</span>)obj2 = BadMutable(<span class="hljs-number">20</span>)d = &#123;obj1: <span class="hljs-string">&quot;ten&quot;</span>, obj2: <span class="hljs-string">&quot;twenty&quot;</span>&#125;<span class="hljs-built_in">print</span>(<span class="hljs-built_in">len</span>(d))      <span class="hljs-comment"># 2</span>obj2.value = <span class="hljs-number">10</span>    <span class="hljs-comment"># 修改 obj2 的值让它等于 obj1</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">len</span>(d))      <span class="hljs-comment"># 集合中它们被认为是不同的元素!</span></code></pre></blockquote></li><li><p>关于哈希值&#x2F;本值</p><blockquote><p>字典和集合都是”哈希表”数据结构, 根据元素的哈希值为元素找存放的槽, 哈希值可视为槽编号</p><p>若<code>hash(a)!=hash(b)</code> 则a,b可处于同一个集合(同字典中不同元素的键)</p><p>若<code>hash(a)==hash(b)</code>, 但<code>a==b</code>不成立, <strong>也可以</strong></p><p>(python底层会自己处理)</p></blockquote></li></ul><h3 id="对象作为key"><a href="#对象作为key" class="headerlink" title="对象作为key"></a>对象作为key</h3><p>实际是以<strong>对象的地址</strong>作为key ,而非值</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">P</span>:<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x,y</span>):        <span class="hljs-variable language_">self</span>.x=x        <span class="hljs-variable language_">self</span>.y=y<span class="hljs-built_in">print</span>(P(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>) <span class="hljs-keyword">is</span> P(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>)) <span class="hljs-comment"># False</span>a=P(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>)b=P(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>)d=&#123;a:<span class="hljs-string">&#x27;1&#x27;</span>, b:<span class="hljs-string">&#x27;ok&#x27;</span>,P(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>):<span class="hljs-number">1.2</span>&#125;<span class="hljs-built_in">print</span>(d[a]) <span class="hljs-comment"># 1</span><span class="hljs-built_in">print</span>(d[b]) <span class="hljs-comment"># ok</span><span class="hljs-built_in">print</span>(d[P(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>)]) <span class="hljs-comment"># keyError 因为这是重新创建的地址, 找不到你存的那个地址了</span></code></pre><h3 id="对象的值作为key"><a href="#对象的值作为key" class="headerlink" title="对象的值作为key"></a>对象的值作为key</h3><p>重写<code>__eq__</code>和<code>__hash__</code></p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x</span>):        <span class="hljs-variable language_">self</span>.x=x    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__eq__</span>(<span class="hljs-params">self,other</span>):        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.x==other.x    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__hash__</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>a=A(<span class="hljs-number">3</span>)b=A(<span class="hljs-number">3</span>)d=&#123;A(<span class="hljs-number">5</span>):<span class="hljs-number">10</span>, A(<span class="hljs-number">3</span>):<span class="hljs-number">20</span>, a:<span class="hljs-number">30</span>, b:<span class="hljs-number">40</span>&#125;<span class="hljs-built_in">print</span>(d[a]) <span class="hljs-comment"># 40</span><span class="hljs-built_in">print</span>(d[A(<span class="hljs-number">5</span>)]) <span class="hljs-comment"># 10</span></code></pre>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/d98d/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/d98d/"/>
    <published>2026-05-22T16:00:00.000Z</published>
    <summary>函数定义、参数传递与返回值</summary>
    <title>Python修养3</title>
    <updated>2026-07-21T09:01:09.822Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--Python" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-Python/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="Python" scheme="https://flowwalker.github.io/coding-notes-blog/tags/Python/"/>
    <content>
      <![CDATA[<h1 id="Python修养4"><a href="#Python修养4" class="headerlink" title="Python修养4"></a>Python修养4</h1><h2 id="函数式程序设计"><a href="#函数式程序设计" class="headerlink" title="函数式程序设计"></a>函数式程序设计</h2><h3 id="思想"><a href="#思想" class="headerlink" title="思想"></a>思想</h3><ul><li><p>函数可以用来<strong>给变量赋值</strong></p><blockquote><p>python中的函数是<strong>对象</strong>, 可像普通变量一样赋值,传值,返回</p></blockquote></li><li><p>函数可作为<strong>函数的参数</strong></p><blockquote><p>python中的可调用对象( 即可以用<code>()</code>调用 ) 包括普通函数和<strong>实现了<code>__call__</code>方法的类实例</strong></p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>:<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,n</span>):<span class="hljs-variable language_">self</span>.n = n<span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self,x</span>):<span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.n + x<span class="hljs-keyword">def</span> <span class="hljs-title function_">add</span>(<span class="hljs-params">x, y, f</span>):<span class="hljs-keyword">return</span> f(x) + f(y)<span class="hljs-built_in">print</span>(add(<span class="hljs-number">1</span>,<span class="hljs-number">10</span>,<span class="hljs-built_in">abs</span>)) <span class="hljs-comment">#=&gt; 11</span><span class="hljs-built_in">print</span>(add(<span class="hljs-number">1</span>,<span class="hljs-number">10</span>,A(<span class="hljs-number">5</span>))) <span class="hljs-comment">#=&gt; 21</span></code></pre></blockquote></li><li><p>lambda表达式可以被赋值给变量, 也可作为函数的返回值和参数</p><blockquote><p>回顾<code>filter(function,iterable)</code> 挑选出可迭代对象**中每一个满足function的元素返回一个迭代器</p></blockquote><blockquote><p>trick:</p><pre><code class="hljs python">b=<span class="hljs-keyword">lambda</span> x:<span class="hljs-keyword">lambda</span> y:x+y<span class="hljs-comment">#b是一个lambda表达式, 返回值是一个lambda表达式</span>a=b(<span class="hljs-number">3</span>) <span class="hljs-comment">#暂时存放3</span><span class="hljs-built_in">print</span>(a(<span class="hljs-number">2</span>)) <span class="hljs-comment"># 5</span></code></pre></blockquote></li><li><p>⚠️函数<strong>内部声明</strong>的变量<strong>自动视为局部变量</strong></p></li><li><p>⚠️可以直接<strong>读取外部全局变量</strong>, 但是若要<strong>修改</strong>🌊需要<code>global x</code>的声明</p></li></ul><h3 id="闭包-closure"><a href="#闭包-closure" class="headerlink" title="闭包(closure)"></a>闭包(closure)</h3><ul><li><p>能够维持外部变量值的函数</p></li><li><p>⚠️修改维持的变量要使用<code>nonlocal x</code>声明</p><blockquote><p>告诉python不要创建局部变量, 要去外围func函数中查找x并修改</p></blockquote></li></ul><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">x</span>):    <span class="hljs-keyword">def</span> <span class="hljs-title function_">g</span>(<span class="hljs-params">y</span>):        <span class="hljs-keyword">nonlocal</span> x        x+=<span class="hljs-number">1</span>        <span class="hljs-keyword">return</span> x+y <span class="hljs-comment">#g是一个闭包,即能够维持外部变量值的函数</span>    <span class="hljs-keyword">return</span> gf=func(<span class="hljs-number">10</span>)<span class="hljs-built_in">print</span>(f(<span class="hljs-number">4</span>))f=func(<span class="hljs-number">20</span>)<span class="hljs-built_in">print</span>(f(<span class="hljs-number">4</span>))<span class="hljs-built_in">print</span>(f(<span class="hljs-number">5</span>))</code></pre><p><strong>闭包的作用</strong></p><p>调用&#x2F;补充别人的库函数而<strong>不修改别人的库</strong></p><blockquote><pre><code class="hljs python"><span class="hljs-comment"># ========== 原始库（dummy_network.py）==========</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">DummyNet</span>(): <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, weight, bias</span>):     <span class="hljs-variable language_">self</span>.weight = weight     <span class="hljs-variable language_">self</span>.bias = bias <span class="hljs-keyword">def</span> <span class="hljs-title function_">forward</span>(<span class="hljs-params">self, <span class="hljs-built_in">input</span></span>):     <span class="hljs-keyword">return</span> <span class="hljs-built_in">input</span> * <span class="hljs-variable language_">self</span>.weight + <span class="hljs-variable language_">self</span>.bias <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, <span class="hljs-built_in">input</span></span>):     <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.forward(<span class="hljs-built_in">input</span>)<span class="hljs-comment"># 使用方式</span><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> npdata = np.array([-<span class="hljs-number">1.</span>, <span class="hljs-number">0.</span>, <span class="hljs-number">1.</span>, <span class="hljs-number">2.</span>])mynet = DummyNet(weight=<span class="hljs-number">2.0</span>, bias=-<span class="hljs-number">1.0</span>)<span class="hljs-built_in">print</span>(mynet(data))        <span class="hljs-comment"># array([-3., -1.,  1.,  3.])</span></code></pre></blockquote><ol><li>场景</li></ol><ul><li>别人写好了库（如 <code>DummyNet</code>），<strong>不能改源码</strong></li><li>但需要<strong>修改运行流程</strong>（如给线性层加 ReLU 激活）</li></ul><ol start="2"><li>闭包写法</li></ol><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">my_forward</span>(<span class="hljs-params">self</span>):               <span class="hljs-comment"># 外层函数接收 mynet 实例</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">forward</span>(<span class="hljs-params"><span class="hljs-built_in">input</span></span>):             <span class="hljs-comment"># 内层函数才是真正的 forward</span>        tmp = <span class="hljs-built_in">input</span> * <span class="hljs-variable language_">self</span>.weight + <span class="hljs-variable language_">self</span>.bias        tmp = np.maximum(<span class="hljs-number">0</span>, tmp)    <span class="hljs-comment"># 加上 ReLU 非线性激活</span>        <span class="hljs-keyword">return</span> tmp    <span class="hljs-keyword">return</span> forward                  <span class="hljs-comment"># 返回内层函数（闭包）</span><span class="hljs-comment"># 关键：把闭包绑定到实例上</span>mynet.forward = my_forward(mynet)   <span class="hljs-comment"># 不修改类，只改这个实例的 forward</span></code></pre><p>内层 <code>forward</code> 函数<strong>捕获了外层 <code>self</code> 变量</strong>（即 <code>mynet</code> 实例），即使外层函数执行完毕，<code>self</code> 仍然被内层函数”关”在里面，随时可用。</p><pre><code class="hljs python"><span class="hljs-built_in">print</span>(mynet(data))        <span class="hljs-comment"># array([0., 0., 1., 3.])</span><span class="hljs-comment"># 负数被 ReLU 截断为 0</span></code></pre><blockquote><p>等价于:</p><pre><code class="hljs python"><span class="hljs-comment"># my_forward(mynet) 执行后：</span><span class="hljs-comment">#   self = mynet</span><span class="hljs-comment">#   返回一个绑定了 self 的 forward 函数</span><span class="hljs-comment"># 等价于：</span>mynet.forward = <span class="hljs-keyword">lambda</span> <span class="hljs-built_in">input</span>: np.maximum(<span class="hljs-number">0</span>, <span class="hljs-built_in">input</span> * mynet.weight + mynet.bias)</code></pre></blockquote><h3 id="偏应用函数-Partical-Application"><a href="#偏应用函数-Partical-Application" class="headerlink" title="偏应用函数(Partical Application)"></a>偏应用函数(Partical Application)</h3><p>用于固定函数中的某些参数</p><pre><code class="hljs python"><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> particaladd=<span class="hljs-keyword">lambda</span> a,b:a+badd1024=partical(add,<span class="hljs-number">1024</span>)<span class="hljs-comment">#固定a</span><span class="hljs-built_in">print</span>(add1024(<span class="hljs-number">1</span>))<span class="hljs-built_in">print</span>(add1024(<span class="hljs-number">10</span>))</code></pre><h2 id="迭代器"><a href="#迭代器" class="headerlink" title="迭代器"></a>迭代器</h2><h3 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h3><ul><li><p>能用<code>for i in x</code>形式遍历的对象x称为<strong>可迭代对象(iterable)</strong></p></li><li><p>可迭代对象<strong>必须实现迭代器协议</strong>, 即<code>__iter__()</code>和<code>__next__()</code>方法</p><ul><li>前者方法返回<strong>对象本身</strong></li><li>后者方法返回<strong>下一元素</strong></li></ul></li><li><p><code>for i in x</code>循环中python会<strong>自动调用</strong><code>x.__iter__()</code>方法获得迭代器p, 并自动调用<code>next(p)</code>获取元素, 并<strong>自动检查StopIteration异常, 碰到即结束(否则无限循环)</strong></p><blockquote><pre><code class="hljs python">x = [<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>]<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> x:<span class="hljs-built_in">print</span>(i)<span class="hljs-comment">#→ 等价于</span>it = <span class="hljs-built_in">iter</span>(x)<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<span class="hljs-keyword">try</span>:<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(it))<span class="hljs-keyword">except</span> StopIteration:<span class="hljs-keyword">break</span> <span class="hljs-comment">#空语句，什么都不做</span></code></pre></blockquote></li></ul><h3 id="操作"><a href="#操作" class="headerlink" title="操作"></a>操作</h3><h4 id="获取与移动"><a href="#获取与移动" class="headerlink" title="获取与移动"></a>获取与移动</h4><pre><code class="hljs python">x=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>]it=<span class="hljs-built_in">iter</span>(x) <span class="hljs-comment">#获取迭代器</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(it))<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(it)) <span class="hljs-comment">#操作迭代器移向下一位</span></code></pre><p>若到达末尾, 执行next将抛出异常</p><h4 id="设置类迭代器"><a href="#设置类迭代器" class="headerlink" title="设置类迭代器"></a>设置类迭代器</h4><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">MyRange</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,n</span>):        <span class="hljs-variable language_">self</span>.idx=<span class="hljs-number">0</span>        <span class="hljs-variable language_">self</span>.n=n<span class="hljs-keyword">def</span> <span class="hljs-title function_">__iter__</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__next__</span>(<span class="hljs-params">self</span>):        <span class="hljs-keyword">if</span> <span class="hljs-variable language_">self</span>.idx&lt;<span class="hljs-variable language_">self</span>.n:            val=<span class="hljs-variable language_">self</span>.idx            <span class="hljs-variable language_">self</span>.idx+=<span class="hljs-number">1</span>            <span class="hljs-keyword">return</span> val        <span class="hljs-keyword">else</span>:            <span class="hljs-comment">#self.idx=0 #不加这行无法进行多次迭代</span>            <span class="hljs-keyword">raise</span> StopIteration()<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> MyRange(<span class="hljs-number">5</span>):    <span class="hljs-built_in">print</span>(i)<span class="hljs-built_in">print</span>([i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> MyRange(<span class="hljs-number">5</span>)])</code></pre><blockquote><p>更佳的复用方式</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">MyRange</span>:              <span class="hljs-comment"># 容器：只存数据，不存迭代状态</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, n</span>):     <span class="hljs-variable language_">self</span>.n = n <span class="hljs-keyword">def</span> <span class="hljs-title function_">__iter__</span>(<span class="hljs-params">self</span>):     <span class="hljs-keyword">return</span> MyRangeIterator(<span class="hljs-variable language_">self</span>.n)   <span class="hljs-comment"># 每次新建迭代器！</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">MyRangeIterator</span>:      <span class="hljs-comment"># 迭代器：存状态（i, n）</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, n</span>):     <span class="hljs-variable language_">self</span>.i = <span class="hljs-number">0</span>     <span class="hljs-variable language_">self</span>.n = n <span class="hljs-keyword">def</span> <span class="hljs-title function_">__iter__</span>(<span class="hljs-params">self</span>):     <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span> <span class="hljs-comment">#可不写</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">__next__</span>(<span class="hljs-params">self</span>):     <span class="hljs-keyword">if</span> <span class="hljs-variable language_">self</span>.i &lt; <span class="hljs-variable language_">self</span>.n:         val = <span class="hljs-variable language_">self</span>.i         <span class="hljs-variable language_">self</span>.i += <span class="hljs-number">1</span>         <span class="hljs-keyword">return</span> val     <span class="hljs-keyword">raise</span> StopIteration()x = MyRange(<span class="hljs-number">5</span>)<span class="hljs-built_in">print</span>([i*i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> x])<span class="hljs-built_in">print</span>([i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> x])it=<span class="hljs-built_in">iter</span>(x)<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(it))<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(it))<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> x: <span class="hljs-built_in">print</span>(i) <span class="hljs-comment">#才不会阶段输出</span><span class="hljs-comment"># [0, 1, 4, 9, 16]</span><span class="hljs-comment"># [0, 1, 2, 3, 4]</span><span class="hljs-comment"># 0</span><span class="hljs-comment"># 1</span><span class="hljs-comment"># 0</span><span class="hljs-comment"># 1</span><span class="hljs-comment"># 2</span><span class="hljs-comment"># 3</span><span class="hljs-comment"># 4</span></code></pre></blockquote><h3 id="迭代重载"><a href="#迭代重载" class="headerlink" title="迭代重载"></a>迭代重载</h3><p>只写 <code>__getitem__</code>，不写 <code>__iter__</code>，<code>for</code> 循环<strong>照样能跑</strong>。</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">stepper</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__getitem__</span>(<span class="hljs-params">self, i</span>):        <span class="hljs-keyword">return</span> <span class="hljs-variable language_">self</span>.data[i]X = stepper()X.data = <span class="hljs-string">&#x27;Spam&#x27;</span> <span class="hljs-comment">#临时创建一个</span><span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> X:      <span class="hljs-comment"># 没写 __iter__ 也能 for 循环！</span>    <span class="hljs-built_in">print</span>(item)     <span class="hljs-comment"># S p a m</span></code></pre><p>Python 的 <code>for</code> 循环有<strong>回退机制</strong>：</p><pre><code class="hljs python"><span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> X:    ...</code></pre><p>实际执行逻辑：</p><pre><code class="hljs python"><span class="hljs-comment"># 第1步：找 __iter__</span><span class="hljs-keyword">try</span>:    iterator = <span class="hljs-built_in">iter</span>(X)      <span class="hljs-comment"># 调用 X.__iter__()</span><span class="hljs-keyword">except</span> TypeError:    <span class="hljs-comment"># 第2步：没有 __iter__，就用 __getitem__ 硬凑</span>    iterator = 内部迭代器(X)   <span class="hljs-comment"># Python 自动创建一个临时迭代器</span><span class="hljs-comment"># 内部迭代器的行为：</span>i = <span class="hljs-number">0</span><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:    <span class="hljs-keyword">try</span>:        item = X[i]         <span class="hljs-comment"># 调用 X.__getitem__(i)</span>        i += <span class="hljs-number">1</span>    <span class="hljs-keyword">except</span> (IndexError, StopIteration):        <span class="hljs-keyword">break</span>               <span class="hljs-comment"># 越界就停</span></code></pre><p>过程拆解</p><pre><code class="hljs stylus">X<span class="hljs-selector-class">.data</span> = <span class="hljs-string">&#x27;Spam&#x27;</span><span class="hljs-keyword">for</span> 调用 <span class="hljs-built_in">iter</span>(X):    └─ 发现没有 __iter__    └─ Python 新建临时迭代器，<span class="hljs-selector-tag">i</span> = <span class="hljs-number">0</span>        ├─ X<span class="hljs-selector-attr">[0]</span> = <span class="hljs-string">&#x27;S&#x27;</span>   → 输出 S        ├─ X<span class="hljs-selector-attr">[1]</span> = <span class="hljs-string">&#x27;p&#x27;</span>   → 输出 <span class="hljs-selector-tag">p</span>        ├─ X<span class="hljs-selector-attr">[2]</span> = <span class="hljs-string">&#x27;a&#x27;</span>   → 输出 <span class="hljs-selector-tag">a</span>        ├─ X<span class="hljs-selector-attr">[3]</span> = <span class="hljs-string">&#x27;m&#x27;</span>   → 输出 m        └─ X<span class="hljs-selector-attr">[4]</span>         → IndexError → <span class="hljs-keyword">for</span> 捕获 → 结束</code></pre><p><code>stepper</code> 本身<strong>没有状态</strong>。每次 <code>for</code> 循环，Python 都<strong>新建一个临时迭代器</strong>（从零开始计数），所以：</p><pre><code class="hljs python"><span class="hljs-built_in">print</span>(<span class="hljs-built_in">list</span>(X))   <span class="hljs-comment"># [&#x27;S&#x27;, &#x27;p&#x27;, &#x27;a&#x27;, &#x27;m&#x27;]</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">list</span>(X))   <span class="hljs-comment"># [&#x27;S&#x27;, &#x27;p&#x27;, &#x27;a&#x27;, &#x27;m&#x27;]  ✅ 还能用！</span></code></pre><h2 id="生成器-generator"><a href="#生成器-generator" class="headerlink" title="生成器(generator)"></a>生成器(generator)</h2><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><ul><li>一种<strong>延时求值对象</strong>, 内部包含计算过程, 真正需要时才完成计算</li></ul><blockquote><p>例子:</p><pre><code class="hljs python">a=(i*i <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">5</span>)) <span class="hljs-comment">#a为生成器,其内容并未生成</span><span class="hljs-built_in">print</span>(a) <span class="hljs-comment">#&lt;generator object &lt;genexpr&gt; at 0x105b27b90&gt;</span><span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> a: <span class="hljs-built_in">print</span>(x,end=<span class="hljs-string">&#x27; &#x27;</span>)<span class="hljs-comment">#0 1 4 9 16 </span><span class="hljs-comment">#后面就迭代不了了</span></code></pre><pre><code class="hljs python">matrix = ((i*<span class="hljs-number">3</span>+j <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>)) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>))<span class="hljs-comment"># matrix 是生成器，其元素也是生成器</span><span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> matrix:<span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> x:<span class="hljs-built_in">print</span>(y,end=<span class="hljs-string">&quot; &quot;</span>) <span class="hljs-comment"># 0 1 2 3 4 5 6 7 8</span><span class="hljs-comment">#区别于写法二</span><span class="hljs-comment"># matrix = ([i*3+j for j in range(3)] for i in range(3))</span><span class="hljs-comment"># # matrix 是生成器，其元素也是生成器</span><span class="hljs-comment"># for x in matrix:</span><span class="hljs-comment">#     for y in x:</span><span class="hljs-comment">#         print(y,end=&quot; &quot;) # 0 1 2 3 4 5 6 7 8</span></code></pre><blockquote><p>延迟绑定Late Binding</p><p><strong>写法1</strong>如果先全部取出再遍历，<strong>结果会错</strong>：</p><pre><code class="hljs python">matrix = ((i*<span class="hljs-number">3</span>+j <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>)) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>))rows = <span class="hljs-built_in">list</span>(matrix)        <span class="hljs-comment"># ❌ 先全部取出来</span><span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> rows: <span class="hljs-built_in">print</span>(<span class="hljs-built_in">list</span>(row))       <span class="hljs-comment"># [6, 7, 8]</span><span class="hljs-comment"># [6, 7, 8]</span><span class="hljs-comment"># [6, 7, 8]   ← 全是 i=2 的结果！</span></code></pre><p><strong>为什么？</strong></p><p>内层生成器 <code>(i*3+j for j in range(3))</code> <strong>没有立刻算</strong>，它只记住了”以后要用 <code>i</code>“。</p><p>当 <code>list(matrix)</code> 把外层迭代完后，<code>i</code> 的最终值是 <code>2</code>。之后你再遍历内层生成器，它们才想起来去查 <code>i</code>，但此时 <code>i</code> 已经是 <code>2</code> 了。</p><pre><code class="hljs autoit"><span class="hljs-meta"># 内层生成器实际上存的是：</span><span class="hljs-meta"># gen0: <span class="hljs-string">&quot;等我运行时，去看看 i 是多少&quot;</span>  → 运行时 i=2</span><span class="hljs-meta"># gen1: <span class="hljs-string">&quot;等我运行时，去看看 i 是多少&quot;</span>  → 运行时 i=2</span><span class="hljs-meta"># gen2: <span class="hljs-string">&quot;等我运行时，去看看 i 是多少&quot;</span>  → 运行时 i=2</span></code></pre><p><strong>写法2</strong>没问题，因为内层列表推导式<strong>立即计算</strong>：</p><pre><code class="hljs stan"><span class="hljs-type">matrix</span> = ([i*<span class="hljs-number">3</span>+j <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> range(<span class="hljs-number">3</span>)] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">3</span>))<span class="hljs-built_in">rows</span> = list(<span class="hljs-type">matrix</span>)<span class="hljs-keyword">for</span> <span class="hljs-built_in">row</span> <span class="hljs-keyword">in</span> <span class="hljs-built_in">rows</span>: <span class="hljs-built_in">print</span>(<span class="hljs-built_in">row</span>)<span class="hljs-comment"># [0, 1, 2]</span><span class="hljs-comment"># [3, 4, 5]</span><span class="hljs-comment"># [6, 7, 8]   ✅ 正确！</span></code></pre><p>列表推导式在 <code>i=0,1,2</code> 的当下就把值算好存进列表了，不会受后续 <code>i</code> 变化的影响。</p><hr><p>写法1什么时候是对的</p><p><strong>边取边用</strong>，在内层生成器被消费时，外层还没跑完：</p><pre><code class="hljs python">matrix = ((i*<span class="hljs-number">3</span>+j <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>)) <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>))<span class="hljs-keyword">for</span> row <span class="hljs-keyword">in</span> matrix:          <span class="hljs-comment"># 外层取一个</span> <span class="hljs-built_in">print</span>(<span class="hljs-built_in">list</span>(row))        <span class="hljs-comment"># 内层立刻消费 ✅</span><span class="hljs-comment"># [0, 1, 2]</span><span class="hljs-comment"># [3, 4, 5]</span><span class="hljs-comment"># [6, 7, 8]</span></code></pre></blockquote></blockquote><ul><li>与列表解析式(即列表推导式list comprehension)区别:<ul><li><code>i=(x+1 for x in lst)</code> 生成器表达式, <strong>不需要生成结果列表</strong>, 延时求值</li><li><code>print([x+1 for x in lst])</code> 列表解析, <strong>生成了结果列表</strong></li></ul></li></ul><h3 id="yield关键字定义生成器"><a href="#yield关键字定义生成器" class="headerlink" title="yield关键字定义生成器"></a>yield关键字定义生成器</h3><p><strong>使用了yield的函数</strong>称为<strong>生成器</strong></p><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">test_yield</span>():    <span class="hljs-keyword">yield</span> <span class="hljs-number">1</span>    <span class="hljs-keyword">yield</span> <span class="hljs-number">2</span>    <span class="hljs-keyword">yield</span> (<span class="hljs-number">1</span>,<span class="hljs-number">2</span>)a=test_yield()<span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:    <span class="hljs-keyword">try</span>:        <span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(a))    <span class="hljs-keyword">except</span> StopIteration:        <span class="hljs-keyword">break</span>        <span class="hljs-keyword">def</span> <span class="hljs-title function_">h</span>(): <span class="hljs-built_in">print</span> (<span class="hljs-string">&#x27;To be brave&#x27;</span>)<span class="hljs-keyword">yield</span> <span class="hljs-number">5</span> x = h() <span class="hljs-comment">#无输出</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(x))  <span class="hljs-comment">#To be brave #5</span><span class="hljs-built_in">next</span>(x) <span class="hljs-comment">#引发异常</span></code></pre><blockquote><p>使用 yield 实现斐波那契数列：</p><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">fibonacci</span>(<span class="hljs-params">n</span>): <span class="hljs-comment"># 生成器函数 – 用于求斐波那契数列前n项</span>a, b, counter = <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span><span class="hljs-keyword">while</span> counter &lt;= n:<span class="hljs-keyword">yield</span> aa, b = b, a + bcounter += <span class="hljs-number">1</span>f = fibonacci(<span class="hljs-number">10</span>) <span class="hljs-comment"># f 是一个迭代器，由生成器返回生成</span><span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:<span class="hljs-keyword">try</span>:<span class="hljs-built_in">print</span> (<span class="hljs-built_in">next</span>(f), end=<span class="hljs-string">&quot; &quot;</span>)<span class="hljs-keyword">except</span> StopIteration:<span class="hljs-keyword">break</span><span class="hljs-comment">#或</span><span class="hljs-comment">#for i in f:</span><span class="hljs-comment">#print (i, end=&quot; &quot;)</span></code></pre><p>好处是:不用事先准备过程需要的所有元素, <strong>仅仅迭代到该元素时才计算</strong>, 可以处理♾️</p><p>称之为<strong>延迟计算</strong> 或 <strong>惰性求值(lazy evaluation)</strong></p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260523221745092.png" alt="image-20260523221745092"></p></blockquote><h3 id="send语句"><a href="#send语句" class="headerlink" title="send语句"></a>send语句</h3><p><strong>特点</strong></p><ul><li>带 <code>yield</code> 的函数，调用时返回生成器对象（迭代器）</li><li>执行到 <code>yield</code> 暂停，下次从断点恢复</li><li>遍历完即耗尽，不能复用</li><li><code>yield</code> 右边产出值给外部，左边接收 <code>send()</code> 的值</li></ul><p><strong>示例</strong></p><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">h</span>():     <span class="hljs-built_in">print</span> (<span class="hljs-string">&#x27;hello&#x27;</span>)     m = <span class="hljs-keyword">yield</span> <span class="hljs-number">5</span> <span class="hljs-comment">#m的值要从外部获得</span>    <span class="hljs-built_in">print</span> (<span class="hljs-string">&quot;m=&quot;</span>, m)     d = <span class="hljs-keyword">yield</span> <span class="hljs-number">12</span>     <span class="hljs-built_in">print</span> (<span class="hljs-string">&#x27;d=&#x27;</span> ,d )    <span class="hljs-keyword">yield</span> <span class="hljs-number">13</span>c = h() <span class="hljs-comment">#无输出</span>x = <span class="hljs-built_in">next</span>(c) <span class="hljs-comment">#默认等价于多了一句c.send(None)</span><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;x=&quot;</span>,x)y = <span class="hljs-built_in">next</span>(c) <span class="hljs-comment">#此时m赋值为了None</span><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;y=&quot;</span>,y)z = c.send(<span class="hljs-string">&quot;good&quot;</span>)<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;z=&quot;</span>,z)<span class="hljs-comment"># hello</span><span class="hljs-comment"># x= 5</span><span class="hljs-comment"># m= None</span><span class="hljs-comment"># y= 12</span><span class="hljs-comment"># d= good</span><span class="hljs-comment"># z= 13</span></code></pre><p><strong>应用</strong>⚠️⚠️⚠️</p><pre><code class="hljs python"><span class="hljs-comment"># ========== 1. 生成器做任务控制器（协程/状态机）==========</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">task_controller</span>():    task_id = <span class="hljs-number">1</span>    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:        action = <span class="hljs-keyword">yield</span> <span class="hljs-string">f&quot;任务<span class="hljs-subst">&#123;task_id&#125;</span> 等待指令&quot;</span>                <span class="hljs-keyword">if</span> action == <span class="hljs-string">&quot;start&quot;</span>:            <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;任务<span class="hljs-subst">&#123;task_id&#125;</span> 开始执行...&quot;</span>)        <span class="hljs-keyword">elif</span> action == <span class="hljs-string">&quot;pause&quot;</span>:            <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;任务<span class="hljs-subst">&#123;task_id&#125;</span> 已暂停&quot;</span>)        <span class="hljs-keyword">elif</span> action == <span class="hljs-string">&quot;stop&quot;</span>:            <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;任务<span class="hljs-subst">&#123;task_id&#125;</span> 已停止&quot;</span>)            task_id += <span class="hljs-number">1</span>        <span class="hljs-keyword">elif</span> action <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:            <span class="hljs-keyword">break</span>controller = task_controller()<span class="hljs-built_in">next</span>(controller)                    <span class="hljs-comment"># 启动</span><span class="hljs-built_in">print</span>(controller.send(<span class="hljs-string">&quot;start&quot;</span>))     <span class="hljs-comment"># 任务1开始 → 产出&quot;任务2等待指令&quot;</span><span class="hljs-built_in">print</span>(controller.send(<span class="hljs-string">&quot;pause&quot;</span>))     <span class="hljs-comment"># 任务2暂停 → 产出&quot;任务3等待指令&quot;</span><span class="hljs-built_in">print</span>(controller.send(<span class="hljs-string">&quot;stop&quot;</span>))      <span class="hljs-comment"># 任务3停止 → task_id=2 → 产出&quot;任务4等待指令&quot;</span><span class="hljs-comment"># ========== 2. 用生成器实现 map（惰性求值）==========</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">myMap</span>(<span class="hljs-params">func, iterable</span>):    <span class="hljs-keyword">for</span> arg <span class="hljs-keyword">in</span> iterable:        <span class="hljs-keyword">yield</span> func(arg)names = [<span class="hljs-string">&quot;ana&quot;</span>, <span class="hljs-string">&quot;bob&quot;</span>, <span class="hljs-string">&quot;dogge&quot;</span>]x = myMap(<span class="hljs-keyword">lambda</span> x: x.capitalize(), names)<span class="hljs-built_in">print</span>(x)           <span class="hljs-comment"># &lt;generator object ...&gt;</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">list</span>(x))     <span class="hljs-comment"># [&#x27;Ana&#x27;, &#x27;Bob&#x27;, &#x27;Dogge&#x27;]</span><span class="hljs-keyword">for</span> name <span class="hljs-keyword">in</span> x:     <span class="hljs-comment"># ❌ 无输出，已耗尽</span><span class="hljs-comment"># ========== 3. 用生成器求全排列（递归回溯）==========</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">perm</span>(<span class="hljs-params">items</span>):    n = <span class="hljs-built_in">len</span>(items)    <span class="hljs-keyword">if</span> n == <span class="hljs-number">1</span>:        <span class="hljs-keyword">yield</span> items    <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(n):        v = items[i:i+<span class="hljs-number">1</span>]        rest = items[:i] + items[i+<span class="hljs-number">1</span>:]        <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> perm(rest):            <span class="hljs-keyword">yield</span> v + pa = perm(<span class="hljs-string">&#x27;abc&#x27;</span>)<span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(a))     <span class="hljs-comment"># abc</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">next</span>(a))     <span class="hljs-comment"># acb</span><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;****&quot;</span>)<span class="hljs-keyword">for</span> b <span class="hljs-keyword">in</span> a:        <span class="hljs-comment"># 从剩余继续</span>    <span class="hljs-built_in">print</span>(b)       <span class="hljs-comment"># bac, bca, cab, cba</span></code></pre><blockquote><p> 双向通信：任务控制器（协程）</p> <pre><code class="hljs python">action = <span class="hljs-keyword">yield</span> msg      <span class="hljs-comment"># 产出 msg 给外部；恢复后 action = send 的值</span></code></pre><table><thead><tr><th>调用</th><th>生成器内部</th></tr></thead><tbody><tr><td><code>next(controller)</code></td><td>启动，跑到 <code>yield</code>，产出状态</td></tr><tr><td><code>send(&quot;start&quot;)</code></td><td>恢复，<code>action=&quot;start&quot;</code>，执行逻辑，再 <code>yield</code> 暂停</td></tr></tbody></table><p> 惰性计算：自定义 map</p><table><thead><tr><th>对比</th><th>列表推导式</th><th>生成器版</th></tr></thead><tbody><tr><td>内存</td><td>全部存列表</td><td>用到一个算一个</td></tr><tr><td>返回</td><td>列表</td><td>生成器对象</td></tr><tr><td>多次遍历</td><td>✅</td><td>❌ 只能一次</td></tr></tbody></table> <pre><code class="hljs python"><span class="hljs-comment"># 惰性 map：遍历时才计算</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">myMap</span>(<span class="hljs-params">func, iterable</span>): <span class="hljs-keyword">for</span> arg <span class="hljs-keyword">in</span> iterable:     <span class="hljs-keyword">yield</span> func(arg)<span class="hljs-comment"># 等价于</span><span class="hljs-built_in">map</span>(func, iterable)   <span class="hljs-comment"># 内置 map 也是返回迭代器</span></code></pre><p> <strong>陷阱</strong>：<code>list(x)</code> 或 <code>for</code> 遍历完后，生成器耗尽，再次遍历为空。</p><p> 递归回溯：全排列</p> <pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">perm</span>(<span class="hljs-params">items</span>): <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(items) == <span class="hljs-number">1</span>:     <span class="hljs-keyword">yield</span> items <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(items)):     v = items[i:i+<span class="hljs-number">1</span>]     rest = items[:i] + items[i+<span class="hljs-number">1</span>:]     <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> perm(rest):    <span class="hljs-comment"># 递归子问题</span>         <span class="hljs-keyword">yield</span> v + p          <span class="hljs-comment"># 拼接产出</span></code></pre><p> <strong>执行流程</strong>（<code>perm(&#39;abc&#39;)</code>）：</p> <pre><code class="hljs stylus"><span class="hljs-function"><span class="hljs-title">perm</span><span class="hljs-params">(<span class="hljs-string">&#x27;abc&#x27;</span>)</span></span>├─ 固定 <span class="hljs-string">&#x27;a&#x27;</span> + <span class="hljs-built_in">perm</span>(<span class="hljs-string">&#x27;bc&#x27;</span>) → abc, acb├─ 固定 <span class="hljs-string">&#x27;b&#x27;</span> + <span class="hljs-built_in">perm</span>(<span class="hljs-string">&#x27;ac&#x27;</span>) → bac, bca└─ 固定 <span class="hljs-string">&#x27;c&#x27;</span> + <span class="hljs-built_in">perm</span>(<span class="hljs-string">&#x27;ab&#x27;</span>) → cab, cba</code></pre><p> <strong>特点</strong>：</p><ul><li>深度优先遍历解空间</li><li>遇到完整解就 <code>yield</code>，不用等全部算完</li><li><code>next()</code> 和 <code>for</code> 可混用，共用迭代状态</li></ul><p> 易错点</p><table><thead><tr><th>错误</th><th>原因</th></tr></thead><tbody><tr><td>生成器遍历为空</td><td>迭代器已耗尽，需重新创建</td></tr><tr><td><code>send(非None)</code> 启动</td><td>未启动的生成器只能用 <code>next()</code> 或 <code>send(None)</code></td></tr><tr><td>递归生成器没 <code>yield from</code></td><td>子生成器的结果需要用 <code>for ... yield</code> 或 <code>yield from</code> 传递</td></tr></tbody></table> <pre><code class="hljs python"><span class="hljs-comment"># 3.3+ 可用 yield from 简化</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">perm</span>(<span class="hljs-params">items</span>):   <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(items) == <span class="hljs-number">1</span>:       <span class="hljs-keyword">yield</span> items   <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-built_in">len</span>(items)):       rest = items[:i] + items[i+<span class="hljs-number">1</span>:]       <span class="hljs-keyword">yield</span> <span class="hljs-keyword">from</span> (items[i:i+<span class="hljs-number">1</span>] + p <span class="hljs-keyword">for</span> p <span class="hljs-keyword">in</span> perm(rest))</code></pre></blockquote><h2 id="其他语法特性"><a href="#其他语法特性" class="headerlink" title="其他语法特性"></a>其他语法特性</h2><h3 id="eval函数"><a href="#eval函数" class="headerlink" title="eval函数"></a>eval函数</h3><h4 id="概念-1"><a href="#概念-1" class="headerlink" title="概念"></a>概念</h4><p><strong>把字符串看作python表达式请求其值, 返回其值</strong></p><pre><code class="hljs python">expression=<span class="hljs-built_in">input</span>(<span class="hljs-string">&quot;请输入算式&quot;</span>)result=<span class="hljs-built_in">eval</span>(expression)<span class="hljs-built_in">print</span>(result)</code></pre><h4 id="compile和exec函数"><a href="#compile和exec函数" class="headerlink" title="compile和exec函数"></a>compile和exec函数</h4><table><thead><tr><th>函数</th><th>作用</th><th>返回值</th></tr></thead><tbody><tr><td><code>eval</code></td><td>将字符串看作Python表达式求值</td><td>✅ 有返回值</td></tr><tr><td><code>exec</code></td><td>执行字符串中的Python语句</td><td>❌ 无返回值(None)</td></tr><tr><td><code>compile</code></td><td>编译字符串为代码对象，供eval&#x2F;exec使用</td><td>代码对象</td></tr></tbody></table><pre><code class="hljs python"><span class="hljs-comment"># eval有返回值</span>result = <span class="hljs-built_in">eval</span>(<span class="hljs-string">&quot;3*4+5&quot;</span>)  <span class="hljs-comment"># 17</span><span class="hljs-comment"># exec无返回值</span><span class="hljs-built_in">exec</span>(<span class="hljs-string">&#x27;a=10&#x27;</span>)<span class="hljs-built_in">print</span>(a)  <span class="hljs-comment"># 10</span>result = <span class="hljs-built_in">exec</span>(<span class="hljs-string">&quot;x = 10&quot;</span>)<span class="hljs-built_in">print</span>(result)  <span class="hljs-comment"># None</span></code></pre><p><strong><code>exec</code>可执行多行代码:</strong></p><pre><code class="hljs python"><span class="hljs-built_in">exec</span>(<span class="hljs-string">&quot;&quot;&quot;</span><span class="hljs-string">a = 10</span><span class="hljs-string">b = 20</span><span class="hljs-string">result = a + b</span><span class="hljs-string">print(result)</span><span class="hljs-string">&quot;&quot;&quot;</span>)  <span class="hljs-comment"># 输出: 30</span></code></pre><p><strong><code>compile</code>提高多次运行效率:</strong></p><pre><code class="hljs python"><span class="hljs-built_in">str</span> = <span class="hljs-string">&quot;for i in range(0,10): print (i,end = &#x27; &#x27;)&quot;</span>c = <span class="hljs-built_in">compile</span>(<span class="hljs-built_in">str</span>,<span class="hljs-string">&#x27;&#x27;</span>,<span class="hljs-string">&#x27;exec&#x27;</span>)      <span class="hljs-comment"># 编译</span><span class="hljs-built_in">exec</span>(c)     <span class="hljs-comment">#=&gt; 0 1 2 3 4 5 6 7 8 9</span>x=<span class="hljs-number">4</span>y=<span class="hljs-number">5</span>str2 = <span class="hljs-string">&quot;3*x + 4*y&quot;</span>c2 = <span class="hljs-built_in">compile</span>(str2, <span class="hljs-string">&#x27;&#x27;</span>, <span class="hljs-string">&#x27;eval&#x27;</span>)  <span class="hljs-comment"># compile过运行更快,适合多次调用</span>result = <span class="hljs-built_in">eval</span>(c2)<span class="hljs-built_in">print</span>(result)  <span class="hljs-comment"># 32</span></code></pre><p><strong>动态导入模块:</strong></p><pre><code class="hljs python">module_name = <span class="hljs-string">&quot;math&quot;</span><span class="hljs-built_in">exec</span>(<span class="hljs-string">f&quot;import <span class="hljs-subst">&#123;module_name&#125;</span>&quot;</span>)<span class="hljs-built_in">print</span>(sqrt(<span class="hljs-number">16</span>))  <span class="hljs-comment"># 4.0</span></code></pre><h5 id="指定作用域"><a href="#指定作用域" class="headerlink" title="指定作用域"></a>指定作用域</h5><p><code>eval</code>和<code>exec</code>可以通过字典指定作用域:</p><pre><code class="hljs python">a = <span class="hljs-number">10</span>b = <span class="hljs-number">20</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">x</span>):    <span class="hljs-keyword">return</span> x+<span class="hljs-number">1</span>scope=&#123;&#125; <span class="hljs-comment">#用字典当作用域</span>scope[<span class="hljs-string">&#x27;a&#x27;</span>] = <span class="hljs-number">3</span>scope[<span class="hljs-string">&#x27;b&#x27;</span>] = <span class="hljs-number">4</span>scope[<span class="hljs-string">&#x27;func&#x27;</span>] = <span class="hljs-keyword">lambda</span> x:x*x<span class="hljs-built_in">print</span>(<span class="hljs-built_in">eval</span>(<span class="hljs-string">&quot;a+b&quot;</span>))          <span class="hljs-comment">#=&gt; 30  (使用全局作用域)</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">eval</span>(<span class="hljs-string">&quot;a+b&quot;</span>,scope))    <span class="hljs-comment">#=&gt; 7   (使用自定义作用域)</span><span class="hljs-comment"># print(eval(&quot;a+b+c&quot;,scope))  # error, c无定义</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">eval</span>(<span class="hljs-string">&quot;func(7)&quot;</span>))          <span class="hljs-comment">#=&gt; 8   (调用全局func)</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">eval</span>(<span class="hljs-string">&quot;func(7)&quot;</span>,scope))    <span class="hljs-comment">#=&gt; 49  (调用scope中的lambda)</span><span class="hljs-built_in">exec</span>(<span class="hljs-string">&quot;print(a)&quot;</span>)          <span class="hljs-comment">#=&gt; 10</span><span class="hljs-built_in">exec</span>(<span class="hljs-string">&quot;print(a)&quot;</span>,scope)    <span class="hljs-comment">#=&gt; 3</span></code></pre><blockquote><p>⚠️ 作用域查找规则:</p><table><thead><tr><th>参数</th><th>说明</th></tr></thead><tbody><tr><td>不提供scope</td><td>使用当前全局&#x2F;局部作用域</td></tr><tr><td>提供<code>scope</code>字典</td><td>从字典中查找变量</td></tr><tr><td>变量不存在</td><td>抛出<code>NameError</code></td></tr></tbody></table></blockquote><h3 id="反射-reflection"><a href="#反射-reflection" class="headerlink" title="反射(reflection)"></a>反射(reflection)</h3><h4 id="概念-2"><a href="#概念-2" class="headerlink" title="概念"></a>概念</h4><p><strong>获取并使用对象的信息</strong></p><p>反射的核心是<strong>在运行时动态获取对象的属性和方法</strong>，并对其进行操作。</p><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>():    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x</span>):        <span class="hljs-variable language_">self</span>.x = x    <span class="hljs-keyword">def</span> <span class="hljs-title function_">func</span>(<span class="hljs-params">self</span>):        <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;x=&quot;</span>,<span class="hljs-variable language_">self</span>.x)a = A(<span class="hljs-number">12</span>)</code></pre><p><strong>四大反射函数:</strong></p><table><thead><tr><th>函数</th><th>作用</th><th>示例</th></tr></thead><tbody><tr><td><code>dir(obj)</code></td><td>列出对象的所有属性和方法</td><td><code>dir(a)</code></td></tr><tr><td><code>hasattr(obj, name)</code></td><td>判断对象是否有指定属性&#x2F;方法</td><td><code>hasattr(a, &#39;x&#39;)</code></td></tr><tr><td><code>getattr(obj, name)</code></td><td>获取对象的属性值或方法</td><td><code>getattr(a, &#39;x&#39;)</code></td></tr><tr><td><code>setattr(obj, name, value)</code></td><td>设置对象的属性值</td><td><code>setattr(a, &#39;x&#39;, 100)</code></td></tr></tbody></table><pre><code class="hljs python">a = A(<span class="hljs-number">12</span>)<span class="hljs-comment"># dir: 列出所有属性和方法</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">dir</span>(a))<span class="hljs-comment"># [&#x27;__class__&#x27;, &#x27;__delattr__&#x27;, &#x27;__dict__&#x27;, &#x27;__dir__&#x27;, &#x27;__doc__&#x27;, </span><span class="hljs-comment">#  &#x27;__eq__&#x27;, &#x27;__format__&#x27;, &#x27;__ge__&#x27;, &#x27;__getattribute__&#x27;, &#x27;__gt__&#x27;, </span><span class="hljs-comment">#  &#x27;__hash__&#x27;, &#x27;__init__&#x27;, &#x27;__le__&#x27;, &#x27;__lt__&#x27;, &#x27;__module__&#x27;, &#x27;__ne__&#x27;, </span><span class="hljs-comment">#  &#x27;__new__&#x27;, &#x27;__reduce__&#x27;, &#x27;__reduce_ex__&#x27;, &#x27;__repr__&#x27;, &#x27;__setattr__&#x27;, </span><span class="hljs-comment">#  &#x27;__sizeof__&#x27;, &#x27;__str__&#x27;, &#x27;__subclasshook__&#x27;, &#x27;__weakref__&#x27;, </span><span class="hljs-comment">#  &#x27;func&#x27;, &#x27;x&#x27;]</span><span class="hljs-comment"># hasattr: 判断是否存在</span><span class="hljs-keyword">if</span> <span class="hljs-built_in">hasattr</span>(a,<span class="hljs-string">&#x27;x&#x27;</span>):           <span class="hljs-comment"># True</span>    <span class="hljs-built_in">setattr</span>(a,<span class="hljs-string">&#x27;x&#x27;</span>,<span class="hljs-string">&#x27;hello,world&#x27;</span>)  <span class="hljs-comment"># 修改属性值</span>    <span class="hljs-built_in">print</span>(<span class="hljs-built_in">getattr</span>(a,<span class="hljs-string">&#x27;x&#x27;</span>))    <span class="hljs-comment"># hello,world</span><span class="hljs-comment"># getattr获取方法并调用</span><span class="hljs-keyword">if</span> <span class="hljs-built_in">hasattr</span>(a,<span class="hljs-string">&#x27;func&#x27;</span>):    <span class="hljs-built_in">getattr</span>(a,<span class="hljs-string">&#x27;func&#x27;</span>)()      <span class="hljs-comment"># x= hello,world</span>    <span class="hljs-comment"># 等价于 a.func()</span></code></pre><blockquote><p>反射的应用场景:</p><ul><li><strong>动态调用方法</strong>: 根据字符串名称调用对象方法</li><li><strong>动态配置</strong>: 通过配置文件指定要操作的属性名</li><li><strong>调试 introspection</strong>: 查看对象内部结构</li><li><strong>插件系统</strong>: 动态加载和调用模块中的功能</li></ul></blockquote><h3 id="异常处理"><a href="#异常处理" class="headerlink" title="异常处理"></a>异常处理</h3><h4 id="try-…-except"><a href="#try-…-except" class="headerlink" title="try … except"></a>try … except</h4><p>捕获异常，防止程序崩溃:</p><pre><code class="hljs python"><span class="hljs-comment"># 捕获所有异常</span><span class="hljs-keyword">try</span>:    f = <span class="hljs-built_in">open</span>(<span class="hljs-string">&quot;ssr.txt&quot;</span>,<span class="hljs-string">&quot;r&quot;</span>)<span class="hljs-keyword">except</span>:    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;error&quot;</span>)<span class="hljs-comment"># 捕获特定异常并获取错误信息</span><span class="hljs-keyword">try</span>:    <span class="hljs-built_in">print</span>(aa)<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:    <span class="hljs-built_in">print</span>(e)<span class="hljs-comment"># name aa is not defined</span></code></pre><p><strong>多分支捕获:</strong></p><pre><code class="hljs python"><span class="hljs-keyword">try</span>:    <span class="hljs-built_in">print</span>(aa)<span class="hljs-keyword">except</span> IOError <span class="hljs-keyword">as</span> e:    <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;IO错误: <span class="hljs-subst">&#123;e&#125;</span>&quot;</span>)<span class="hljs-keyword">except</span> NameError <span class="hljs-keyword">as</span> e:    <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;名称错误: <span class="hljs-subst">&#123;e&#125;</span>&quot;</span>)<span class="hljs-comment"># name &#x27;aa&#x27; is not defined</span><span class="hljs-comment"># 兜底捕获</span><span class="hljs-keyword">try</span>:    可能出错的代码<span class="hljs-keyword">except</span> 特定异常 <span class="hljs-keyword">as</span> e:    处理特定错误<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:   <span class="hljs-comment"># 捕获一切错误</span>    <span class="hljs-built_in">print</span>(<span class="hljs-string">f&quot;其他错误: <span class="hljs-subst">&#123;e&#125;</span>&quot;</span>)</code></pre><h4 id="try-…-finally"><a href="#try-…-finally" class="headerlink" title="try … finally"></a>try … finally</h4><p>无论有无异常，<code>finally</code>块都会执行:</p><pre><code class="hljs python"><span class="hljs-keyword">try</span>:    <span class="hljs-built_in">print</span>(aa)<span class="hljs-keyword">except</span>:    <span class="hljs-keyword">pass</span>           <span class="hljs-comment"># 空操作，忽略异常</span><span class="hljs-keyword">finally</span>:    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;done&quot;</span>)  <span class="hljs-comment"># 不论有无异常都会执行</span></code></pre><blockquote><p>异常处理最佳实践:</p><table><thead><tr><th>写法</th><th>说明</th></tr></thead><tbody><tr><td><code>except:</code></td><td>捕获所有异常（过于宽泛，不推荐）</td></tr><tr><td><code>except SpecificError:</code></td><td>捕获特定异常 ✅</td></tr><tr><td><code>except Exception as e:</code></td><td>捕获所有异常并获取信息</td></tr><tr><td><code>try...finally:</code></td><td>用于资源释放（如关闭文件）</td></tr><tr><td><code>pass</code></td><td>空语句，什么都不做</td></tr></tbody></table></blockquote><h3 id="装饰器"><a href="#装饰器" class="headerlink" title="装饰器"></a>装饰器</h3><h4 id="基本概念-1"><a href="#基本概念-1" class="headerlink" title="基本概念"></a>基本概念</h4><p><strong>在不改变原有函数代码的情况下扩展函数功能</strong></p><p>也许你已经在深度学习中见过装饰器:</p><pre><code class="hljs python"><span class="hljs-keyword">import</span> torchx = torch.tensor([<span class="hljs-number">1.0</span>, <span class="hljs-number">2.0</span>, <span class="hljs-number">3.0</span>], requires_grad=<span class="hljs-literal">True</span>)<span class="hljs-meta">@torch.no_grad()     </span><span class="hljs-comment"># 装饰器语法</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">double</span>(<span class="hljs-params">tensor</span>):    <span class="hljs-keyword">return</span> tensor * <span class="hljs-number">2</span>result = double(x)<span class="hljs-built_in">print</span>(result)<span class="hljs-comment"># tensor([2., 4., 6.])</span><span class="hljs-comment"># 对比：不用装饰器</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">double</span>(<span class="hljs-params">tensor</span>):    <span class="hljs-keyword">return</span> tensor * <span class="hljs-number">2</span>result = double(x)<span class="hljs-built_in">print</span>(result)<span class="hljs-comment"># tensor([2., 4., 6.], grad_fn=&lt;MulBackward0&gt;)</span></code></pre><h4 id="自定义装饰器"><a href="#自定义装饰器" class="headerlink" title="自定义装饰器"></a>自定义装饰器</h4><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">good</span>(<span class="hljs-params">func</span>):    <span class="hljs-keyword">def</span> <span class="hljs-title function_">wrapper</span>(<span class="hljs-params">*args</span>):        <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;%s called&quot;</span> % func.__name__)        <span class="hljs-keyword">return</span> func(*args)+<span class="hljs-number">5</span>    <span class="hljs-keyword">return</span> wrapper<span class="hljs-meta">@good       </span><span class="hljs-comment"># good是一个装饰器</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">mysum</span>(<span class="hljs-params">a,b,c</span>):    <span class="hljs-keyword">return</span> a + b + c<span class="hljs-built_in">print</span>(mysum(<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>))<span class="hljs-comment"># mysum called</span><span class="hljs-comment"># 17</span><span class="hljs-comment"># @good 等价于 mysum = good(mysum)</span><span class="hljs-comment"># mysum(3,4,5) 等价于 good(mysum)(3,4,5)</span></code></pre><h4 id="带参数的装饰器"><a href="#带参数的装饰器" class="headerlink" title="带参数的装饰器"></a>带参数的装饰器</h4><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">good2</span>(<span class="hljs-params">var1</span>):    <span class="hljs-keyword">def</span> <span class="hljs-title function_">decorator</span>(<span class="hljs-params">func</span>):        <span class="hljs-keyword">def</span> <span class="hljs-title function_">wrapper</span>(<span class="hljs-params">*args</span>):            <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;%s called&quot;</span> % func.__name__)            <span class="hljs-keyword">return</span> func(*args) + var1        <span class="hljs-keyword">return</span> wrapper    <span class="hljs-keyword">return</span> decorator<span class="hljs-meta">@good2(<span class="hljs-params"><span class="hljs-number">10</span></span>)</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">f</span>(<span class="hljs-params">x,y</span>):    <span class="hljs-keyword">return</span> x * y<span class="hljs-meta">@good2(<span class="hljs-params"><span class="hljs-number">100</span></span>)</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">f2</span>(<span class="hljs-params">x,y</span>):    <span class="hljs-keyword">return</span> x * y<span class="hljs-built_in">print</span>(f(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>))    <span class="hljs-comment"># f called  12   (1*2+10)</span><span class="hljs-built_in">print</span>(f2(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>))   <span class="hljs-comment"># f2 called 102  (1*2+100)</span><span class="hljs-comment"># @good2(10) 等价于 good2(10)(f)(1,2)</span></code></pre><h4 id="用对象做装饰器"><a href="#用对象做装饰器" class="headerlink" title="用对象做装饰器"></a>用对象做装饰器</h4><pre><code class="hljs python"><span class="hljs-keyword">class</span> <span class="hljs-title class_">decorator</span>:    <span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self,x</span>):        <span class="hljs-variable language_">self</span>.x = x    <span class="hljs-keyword">def</span> <span class="hljs-title function_">de</span>(<span class="hljs-params">self,func</span>):        <span class="hljs-keyword">def</span> <span class="hljs-title function_">wrapper</span>(<span class="hljs-params">*args</span>):            <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;%s called&quot;</span> % func.__name__)            <span class="hljs-keyword">return</span> func(*args) + <span class="hljs-variable language_">self</span>.x        <span class="hljs-keyword">return</span> wrappermyobj = decorator(<span class="hljs-number">100</span>)<span class="hljs-meta">@myobj.de</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">f3</span>(<span class="hljs-params">x,y,z</span>):    <span class="hljs-keyword">return</span> x + y + z<span class="hljs-built_in">print</span>(f3(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>))    <span class="hljs-comment"># f3 called  106  (1+2+3+100)</span>myobj.x = <span class="hljs-number">7</span>         <span class="hljs-comment"># 修改装饰器的参数</span><span class="hljs-built_in">print</span>(f3(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>))    <span class="hljs-comment"># f3 called  13   (1+2+3+7)</span></code></pre><blockquote><p>装饰器执行时机:</p><table><thead><tr><th>阶段</th><th>行为</th></tr></thead><tbody><tr><td>定义时</td><td><code>@decorator</code> 立即执行，原函数被替换为wrapper</td></tr><tr><td>调用时</td><td>执行的是wrapper函数，其中再调用原函数</td></tr></tbody></table><p>三层嵌套解析（带参数装饰器）:</p><pre><code class="hljs pgsql">@good2(<span class="hljs-number">10</span>)def f(x,y): <span class="hljs-keyword">return</span> x*y# 执行步骤:# <span class="hljs-number">1.</span> good2(<span class="hljs-number">10</span>) → 返回 decorator 函数# <span class="hljs-number">2.</span> decorator(f) → 返回 <span class="hljs-keyword">wrapper</span> 函数# <span class="hljs-number">3.</span> f = <span class="hljs-keyword">wrapper</span>  (原f被包装)</code></pre></blockquote>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/1bcc/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/1bcc/"/>
    <published>2026-05-22T16:00:00.000Z</published>
    <summary>函数式编程：函数作为对象与参数</summary>
    <title>Python修养4</title>
    <updated>2026-07-21T09:01:10.840Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--Python" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-Python/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="Python" scheme="https://flowwalker.github.io/coding-notes-blog/tags/Python/"/>
    <content>
      <![CDATA[<h1 id="Python修养2"><a href="#Python修养2" class="headerlink" title="Python修养2"></a>Python修养2</h1><h2 id="元组"><a href="#元组" class="headerlink" title="元组"></a>元组</h2><ul><li>一个元组由<strong>数个逗号分隔</strong>的值组成, 前后可加括号</li><li>⚠️可认为是个<strong>指针vector数组</strong>, 数组元素<strong>不可修改</strong>, <strong>不可增删元素</strong>, <strong>指向</strong>的东西<strong>可以修改</strong></li></ul><h3 id="具体操作"><a href="#具体操作" class="headerlink" title="具体操作"></a>具体操作</h3><p>定义:</p><pre><code class="hljs python">t=<span class="hljs-number">1</span>,<span class="hljs-number">3.14</span>,[<span class="hljs-number">1</span>,<span class="hljs-string">&#x27;hello&#x27;</span>]</code></pre><p>取值:</p><pre><code class="hljs python"><span class="hljs-built_in">print</span>(t[<span class="hljs-number">2</span>])<span class="hljs-comment"># 可修改其中的列表中的元素</span>t[<span class="hljs-number">2</span>][<span class="hljs-number">0</span>]=<span class="hljs-number">2</span><span class="hljs-comment"># 下标访问元组</span><span class="hljs-built_in">print</span>(t[<span class="hljs-number">0</span>])<span class="hljs-built_in">print</span>(t[<span class="hljs-number">2</span>])</code></pre><p>解包:</p><pre><code class="hljs Python"><span class="hljs-built_in">print</span>(t)</code></pre><p>元组拼接</p><pre><code class="hljs python">tup3=tup1+tup2</code></pre><p>运算与迭代</p><pre><code class="hljs python">x=(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>)*<span class="hljs-number">3</span> <span class="hljs-comment">#表示复制三份拼接</span><span class="hljs-built_in">print</span>(<span class="hljs-number">3</span> <span class="hljs-keyword">in</span> (<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>))<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> x:    <span class="hljs-built_in">print</span>(i)</code></pre><h3 id="Tips"><a href="#Tips" class="headerlink" title="Tips"></a>Tips</h3><ul><li><p>元组元素<strong>本身可能被修改</strong>, 例如<strong>其中的列表</strong></p><blockquote><p><del>组建的球队人员不可更改, 但球员的特性可以修改</del></p></blockquote></li><li><p>关于逗号</p><pre><code class="hljs python">empty=()singleton=<span class="hljs-string">&#x27;hello&#x27;</span>, <span class="hljs-comment">#此处逗号不省略, 表示元组</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">len</span>(empty))<span class="hljs-built_in">print</span>(<span class="hljs-built_in">len</span>(singleton))x=(<span class="hljs-string">&#x27;hello&#x27;</span>,) <span class="hljs-comment"># 无逗号则为字符串</span><span class="hljs-built_in">print</span>(x)</code></pre></li><li><pre><code class="hljs python">x = (<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>)b = x<span class="hljs-built_in">print</span>(b <span class="hljs-keyword">is</span> x) <span class="hljs-comment"># true</span>x += (<span class="hljs-number">100</span>,)<span class="hljs-built_in">print</span> (x) <span class="hljs-comment"># (1, 2, 3, 100)</span><span class="hljs-built_in">print</span> (b) <span class="hljs-comment"># (1, 2, 3)</span></code></pre><p><code>b = x</code> 确实是<strong>引用赋值</strong>，<code>b</code> 和 <code>x</code> 一开始指向<strong>同一个对象</strong>。问题出在：<strong>元组是不可变的</strong>（immutable），<code>+=</code> 对它来说不是”原地追加”，而是<strong>创建一个新元组</strong>。</p></li></ul><h2 id="列表"><a href="#列表" class="headerlink" title="列表"></a>列表</h2><ul><li>可以有<strong>任意数量个</strong>元素, 下标访问</li><li>可以增删, 可以修改, <strong>元素类型随意</strong></li></ul><h3 id="操作"><a href="#操作" class="headerlink" title="操作"></a>操作</h3><p><strong>基本操作</strong></p><pre><code class="hljs python"><span class="hljs-comment"># 空初始化</span>my_list=[]<span class="hljs-comment"># 追加任意类型元素</span>my_list.append(<span class="hljs-number">10</span>)my_list.append(<span class="hljs-string">&quot;hello&quot;</span>)<span class="hljs-comment">#删除元素</span><span class="hljs-keyword">del</span> my_list[<span class="hljs-number">1</span>]<span class="hljs-comment">#列表合并</span>list1+=[<span class="hljs-number">100.0</span>]</code></pre><p><strong>“运算”</strong></p><p>$$[a]+[b] \rightarrow [a,b]$$</p><p>$$[a]*2 \rightarrow [a,a]$$</p><blockquote><p>python的变量是引用</p><pre><code class="hljs python">a=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>]x=[<span class="hljs-string">&#x27;a&#x27;</span>,<span class="hljs-string">&#x27;b&#x27;</span>,<span class="hljs-string">&#x27;c&#x27;</span>]n=[a,x]<span class="hljs-built_in">print</span>(n)<span class="hljs-comment">#注意!此时n[1]和a指向同一个对象[1, 2, 3]</span>a.append(<span class="hljs-number">4</span>)<span class="hljs-built_in">print</span>(n)<span class="hljs-comment">#a.append()操作改变原对象,n也改变</span>a=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>]<span class="hljs-built_in">print</span>(n)<span class="hljs-comment">#a指向新对象,x仍指向原对象,n不改变</span></code></pre></blockquote><p><strong>in关键字</strong></p><p>可用于判断列表是否包含某个元素</p><p><code>x in list</code>返回bool值</p><pre><code class="hljs python">l=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>]ll=[<span class="hljs-number">1</span>]<span class="hljs-built_in">print</span>(<span class="hljs-number">4</span> <span class="hljs-keyword">in</span> l, <span class="hljs-number">4</span> <span class="hljs-keyword">in</span> ll)<span class="hljs-comment">#True False</span></code></pre><h3 id="切片"><a href="#切片" class="headerlink" title="切片"></a>切片</h3><p><strong>基本语法</strong>( 左开右闭 )</p><pre><code class="hljs python">a[start:end:step]<span class="hljs-comment">#缺省情况为为开头,结尾+1,1</span></code></pre><p><strong>范围</strong></p><pre><code class="hljs python">a=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>]b=a[<span class="hljs-number">1</span>:<span class="hljs-number">3</span>]</code></pre><p><strong>负数</strong></p><pre><code class="hljs python">c=a[-<span class="hljs-number">1</span>] <span class="hljs-comment">#取尾元素</span><span class="hljs-comment">#逆序</span>d=a[::-<span class="hljs-number">1</span>]</code></pre><h3 id="列表深拷贝"><a href="#列表深拷贝" class="headerlink" title="列表深拷贝"></a>列表深拷贝</h3><pre><code class="hljs python"><span class="hljs-keyword">import</span> copya=[<span class="hljs-number">1</span>,[<span class="hljs-number">2</span>]]b=copy.deepcopy(a) <span class="hljs-comment">#深拷贝</span>bb=a[:]b.append(<span class="hljs-number">4</span>)bb.append(<span class="hljs-number">4</span>)a[<span class="hljs-number">1</span>].append(<span class="hljs-number">3</span>)<span class="hljs-built_in">print</span>(a)<span class="hljs-built_in">print</span>(b)<span class="hljs-built_in">print</span>(bb)<span class="hljs-comment"># [1, [2,3]]</span><span class="hljs-comment"># [1, [2], 4]</span><span class="hljs-comment"># [1, [2,3], 4]</span></code></pre><blockquote><p><code>a=a+b</code>先创建一个新对象,a后指向新对象</p><p><code>a+=b</code>原地追加</p><p>⚠️对于元组: 则是无论如何都是重新创建并指向,因为<strong>元素不可修改</strong></p></blockquote><h3 id="列表生成式"><a href="#列表生成式" class="headerlink" title="列表生成式"></a>列表生成式</h3><pre><code class="hljs python">[x*x <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>,<span class="hljs-number">11</span>)]<span class="hljs-comment"># [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]</span>[m+n <span class="hljs-keyword">for</span> m <span class="hljs-keyword">in</span> <span class="hljs-string">&#x27;ABC&#x27;</span> <span class="hljs-keyword">for</span> n <span class="hljs-keyword">in</span> <span class="hljs-string">&#x27;XYZ&#x27;</span>]<span class="hljs-comment">#[&#x27;AX&#x27;, &#x27;AY&#x27;, &#x27;AZ&#x27;, &#x27;BX&#x27;, &#x27;BY&#x27;, &#x27;BZ&#x27;, &#x27;CX&#x27;, &#x27;CY&#x27;, &#x27;CZ&#x27;]</span>L=[<span class="hljs-string">&#x27;Hello&#x27;</span>,<span class="hljs-number">18</span>,<span class="hljs-string">&#x27;Apple&#x27;</span>,<span class="hljs-literal">None</span>][s.lower() <span class="hljs-keyword">for</span> s <span class="hljs-keyword">in</span> L <span class="hljs-keyword">if</span> <span class="hljs-built_in">isinstance</span>(s,<span class="hljs-built_in">str</span>)]<span class="hljs-comment">#[&#x27;hello&#x27;,&#x27;apple&#x27;]</span></code></pre><blockquote><p>元组生成式</p><p><code>print(tuple(x*x for x in range(1,11)))</code></p></blockquote><h4 id="用列表生成式处理输入"><a href="#用列表生成式处理输入" class="headerlink" title="用列表生成式处理输入"></a>用列表生成式处理输入</h4><pre><code class="hljs python"><span class="hljs-keyword">try</span>:    <span class="hljs-keyword">while</span> <span class="hljs-literal">True</span>:        s=<span class="hljs-built_in">input</span>()        <span class="hljs-keyword">if</span> s.strip()==<span class="hljs-string">&quot;&quot;</span>:        <span class="hljs-keyword">continue</span>        a=s.split()        b=[x <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> a <span class="hljs-keyword">if</span> x!=<span class="hljs-string">&#x27;&#x27;</span>] <span class="hljs-comment">#去除空串</span>        name,age,gpa=b[<span class="hljs-number">0</span>],b[<span class="hljs-number">1</span>],b[<span class="hljs-number">2</span>]        <span class="hljs-built_in">print</span>(name,age,gpa)<span class="hljs-keyword">except</span> EOFError:        <span class="hljs-keyword">pass</span></code></pre><pre><code class="hljs plain">标准输入：jack 12 3.5marry 34 7.8Jane 34 7.8输出：jack 12 3.5marry 34 7.8Jane 34 7.8</code></pre><h3 id="相关函数"><a href="#相关函数" class="headerlink" title="相关函数"></a>相关函数</h3><ul><li><code>index(v)</code>查找元素v, 返回首次出现的下标, <strong>如果没有则异常</strong></li><li><code>insert(i,v)</code>插入元素v到下标i处</li><li><code>remove(v)</code>删除首次出现的元素v</li><li><code>append(value)</code></li><li><code>len(x)</code></li><li><code>extend(list)</code>添加其他表中的元素到尾部</li><li><code>reverse()</code>颠倒</li></ul><h3 id="更多函数"><a href="#更多函数" class="headerlink" title="更多函数"></a>更多函数</h3><h4 id="map和filter"><a href="#map和filter" class="headerlink" title="map和filter"></a>map和filter</h4><blockquote><p>此处返回的迭代器对象–表示<strong>延时求值</strong>, 只是规划, 不占内存</p></blockquote><ul><li><code>map(function,sequence)</code>将一个列表(元组)中的元素<strong>一一作用</strong>, <strong>返回迭代器对象</strong></li><li><code>fliter(function,sequence)</code>将一个列表(元组)中的<strong>不满足function元素过滤掉, 返回迭代器对象</strong></li></ul><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">f1</span>(<span class="hljs-params">x</span>):    <span class="hljs-keyword">return</span> x*<span class="hljs-number">2</span><span class="hljs-keyword">def</span> <span class="hljs-title function_">f2</span>(<span class="hljs-params">x</span>):    <span class="hljs-keyword">return</span> x%<span class="hljs-number">2</span>==<span class="hljs-number">0</span>ls=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>]ls1=<span class="hljs-built_in">tuple</span>(<span class="hljs-built_in">map</span>(f1,ls))<span class="hljs-built_in">print</span>(ls1)<span class="hljs-comment"># (2, 4, 6, 8, 10)</span>ls1=<span class="hljs-built_in">list</span>(<span class="hljs-built_in">filter</span>(f2,ls))<span class="hljs-built_in">print</span>(ls1)<span class="hljs-comment"># [2, 4]</span></code></pre><p><strong>高级用法</strong></p><p><code>map(func,iterable1,itrable2,...)</code></p><p>函数传入参数个数要对应</p><h4 id="reduce"><a href="#reduce" class="headerlink" title="reduce"></a>reduce</h4><p><code>reduce(function,sequence,startValue)</code></p><p>将一个列表累积起来</p><pre><code class="hljs python"><span class="hljs-keyword">from</span> functools <span class="hljs-keyword">import</span> reduce<span class="hljs-keyword">def</span> <span class="hljs-title function_">f2</span>(<span class="hljs-params">x,y</span>):    <span class="hljs-keyword">return</span> x+yls=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>]<span class="hljs-built_in">print</span>(reduce(f2,ls)) <span class="hljs-comment">#15</span><span class="hljs-built_in">print</span>(reduce(f2,ls,<span class="hljs-number">10</span>)) <span class="hljs-comment">#25</span></code></pre><h3 id="定义二维数组"><a href="#定义二维数组" class="headerlink" title="定义二维数组"></a>定义二维数组</h3><pre><code class="hljs python"><span class="hljs-comment">#直接定义</span><span class="hljs-comment">#生成定义</span>matrix=[[i*<span class="hljs-number">3</span>+j <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>)] <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">3</span>)]</code></pre><blockquote><p>❌错误做法:</p><pre><code class="hljs python">array=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">4</span>]matrix=[array*<span class="hljs-number">3</span>]<span class="hljs-built_in">print</span>(matrix)<span class="hljs-comment">#得到[[1, 2, 3, 1, 2, 3, 1, 2, 3]]非目的</span>matrix=[array]*<span class="hljs-number">3</span><span class="hljs-built_in">print</span>(matrix)<span class="hljs-comment">#得到[[1, 2, 4], [1, 2, 4], [1, 2, 4]]但是三行指向同一对象,参见:(非目的)</span>matrix[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>]=<span class="hljs-number">0</span><span class="hljs-built_in">print</span>(matrix)<span class="hljs-comment">#得到[[0, 2, 4], [0, 2, 4], [0, 2, 4]],三行首元素被同改,非目的</span></code></pre><p>⚠️注意:</p><p>这里确实有个比较奇怪的事实:</p><p>对于<code>[1]*3</code>表示的是深拷贝三遍形成一个列表,修改a[0]其余元素不变</p><p>而对于<code>[[1]]*3</code>表示的是浅拷贝三遍一维列表形成一个二维数组,修改<code>a[0][0]</code>其余行元素也改变</p></blockquote><h3 id="列表大小比较"><a href="#列表大小比较" class="headerlink" title="列表大小比较"></a>列表大小比较</h3><ul><li><p><strong>逐元素相比,直到分出胜负</strong></p></li><li><p>若出现不能比较情况, <strong>报错</strong></p></li></ul><h3 id="列表排序"><a href="#列表排序" class="headerlink" title="列表排序"></a>列表排序</h3><blockquote><p>python的排序是稳定的, 相同key排序前后顺序不变</p></blockquote><pre><code class="hljs python">a.sort()a.sort(reverse=<span class="hljs-literal">True</span>)b=<span class="hljs-built_in">sorted</span>(a) <span class="hljs-comment">#a不变</span><span class="hljs-comment">#此外还内置key用于生成被排序的值以自定义排序</span>a=[<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>,<span class="hljs-number">6</span>,<span class="hljs-number">7</span>,<span class="hljs-number">8</span>,<span class="hljs-number">9</span>]b=<span class="hljs-built_in">sorted</span>(a,key=(<span class="hljs-keyword">lambda</span> x:x%<span class="hljs-number">5</span>),reverse=<span class="hljs-literal">True</span>)<span class="hljs-built_in">print</span>(b)</code></pre><p>⚠️key: 传入一个参数生成一个用于排序的值</p><blockquote><p>元组不可修改, 因此无<code>sort</code>, 但可用<code>sorted</code></p></blockquote><p><strong>对于二维数组的指定排序</strong></p><pre><code class="hljs python"><span class="hljs-keyword">from</span> operator <span class="hljs-keyword">import</span> *<span class="hljs-built_in">print</span>(<span class="hljs-built_in">sorted</span>(students,key=itemgetter(<span class="hljs-number">0</span>,<span class="hljs-number">1</span>)))<span class="hljs-comment">#先按第一个排,再按第二个排</span></code></pre><blockquote><p> <code>itemgetter(n)</code>取对象的第n个元素</p></blockquote><h2 id="字典"><a href="#字典" class="headerlink" title="字典"></a>字典</h2><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><ul><li><code>dict</code></li><li>每个元素由<code>键:值</code>构成, 可根据<code>键</code> 查找, <code>键</code>必须可哈希</li><li><strong>键的内容不能一样</strong>, 且键必须是<strong>不可变数据类型</strong> ( 尤其不可是list )</li><li>快速查找, <strong>速度高于list, 查找速度与元素个数无关</strong> </li><li><strong>可以混合不同类型的键值</strong></li></ul><h3 id="格式"><a href="#格式" class="headerlink" title="格式"></a>格式</h3><pre><code class="hljs python">d=&#123;    key1:value1,    key2:value2,    ...&#125;<span class="hljs-comment"># 定义中键不能重复, 否则最终只会保留一个</span></code></pre><blockquote><p>重复定义的键, 后面的<strong>覆盖前面的</strong>, 最后只保留最后的那个元素</p></blockquote><h3 id="操作-1"><a href="#操作-1" class="headerlink" title="操作"></a>操作</h3><h4 id="构造"><a href="#构造" class="headerlink" title="构造"></a>构造</h4><pre><code class="hljs python"><span class="hljs-comment"># way 1</span>items=[(<span class="hljs-string">&#x27;name&#x27;</span>,<span class="hljs-string">&#x27;Gumby&#x27;</span>),(<span class="hljs-string">&#x27;age&#x27;</span>,<span class="hljs-number">42</span>)]d=<span class="hljs-built_in">dict</span>(items)<span class="hljs-built_in">print</span>(d)<span class="hljs-comment"># way 2</span>d=<span class="hljs-built_in">dict</span>(name=<span class="hljs-string">&#x27;Gumby&#x27;</span>,age=<span class="hljs-number">42</span>)<span class="hljs-built_in">print</span>(d)<span class="hljs-comment">#&#123;&#x27;name&#x27;: &#x27;Gumby&#x27;, &#x27;age&#x27;: 42&#125;</span><span class="hljs-comment">#查询键是否在字典内</span><span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;age&#x27;</span> <span class="hljs-keyword">in</span> d)<span class="hljs-comment">#True</span><span class="hljs-comment">#正常=指向同一对象, 正常元素赋值</span>d=&#123;<span class="hljs-string">&#x27;name&#x27;</span>: <span class="hljs-string">&#x27;Gumby&#x27;</span>, <span class="hljs-string">&#x27;age&#x27;</span>: <span class="hljs-number">42</span>&#125;b = d;b[<span class="hljs-string">&#x27;name&#x27;</span>] = <span class="hljs-string">&quot;Tom&quot;</span><span class="hljs-built_in">print</span>(d)<span class="hljs-comment"># &#123;&#x27;name&#x27;: &#x27;Tom&#x27;, &#x27;age&#x27;: 42&#125;</span></code></pre><h4 id="添加元素"><a href="#添加元素" class="headerlink" title="添加元素"></a>添加元素</h4><pre><code class="hljs python">scope=&#123;&#125;scope[<span class="hljs-string">&#x27;a&#x27;</span>]=<span class="hljs-number">3</span></code></pre><h4 id="删除操作"><a href="#删除操作" class="headerlink" title="删除操作"></a>删除操作</h4><pre><code class="hljs python"><span class="hljs-keyword">del</span> scope[<span class="hljs-string">&#x27;a&#x27;</span>]</code></pre><blockquote><p>删除和[]访问没有的键<strong>都会报错</strong></p></blockquote><h4 id="安全访问"><a href="#安全访问" class="headerlink" title="安全访问"></a>安全访问</h4><pre><code class="hljs python">scope.get(key,default)</code></pre><ul><li>这里的default缺省为<code>None</code>, 可自行设置默认返回值</li><li>若不存在返回默认返回值</li></ul><h4 id="输出"><a href="#输出" class="headerlink" title="输出"></a>输出</h4><pre><code class="hljs python">phonebook=&#123;<span class="hljs-string">&#x27;Alice&#x27;</span>:<span class="hljs-string">&#x27;2341&#x27;</span>,<span class="hljs-string">&#x27;Beth&#x27;</span>:<span class="hljs-string">&#x27;9102&#x27;</span>,<span class="hljs-string">&#x27;Cecil&#x27;</span>:<span class="hljs-string">&#x27;3258&#x27;</span>&#125;<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;Cecil&#x27;s phone number is %(Cecil)s.&quot;</span>%phonebook)<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;Cecil&#x27;s phone number is %s.&quot;</span>%phonebook[Cecil])<span class="hljs-comment">#同样输出, 如今更常用f字符串</span></code></pre><h3 id="字典函数"><a href="#字典函数" class="headerlink" title="字典函数"></a>字典函数</h3><ul><li><p><code>clear</code>: 清空字典</p></li><li><p><code>keys</code>: 用于取字典的键, 为一种只读,支持集合运算的数据类型</p><blockquote><p>可以理解成是监视字典键的窗口</p><pre><code class="hljs python">d = &#123;<span class="hljs-string">&#x27;Alice&#x27;</span>: <span class="hljs-number">90</span>&#125;keys = d.keys()        <span class="hljs-comment"># 拿到窗口</span><span class="hljs-built_in">print</span>(keys)            <span class="hljs-comment"># dict_keys([&#x27;Alice&#x27;])</span>d[<span class="hljs-string">&#x27;Bob&#x27;</span>] = <span class="hljs-number">85</span>          <span class="hljs-comment"># 字典变了</span><span class="hljs-built_in">print</span>(keys)            <span class="hljs-comment"># dict_keys([&#x27;Alice&#x27;, &#x27;Bob&#x27;])  ← 窗口自动变了！</span>d.pop(<span class="hljs-string">&#x27;Alice&#x27;</span>)         <span class="hljs-comment"># 删掉 Alice</span><span class="hljs-built_in">print</span>(keys)            <span class="hljs-comment"># dict_keys([&#x27;Bob&#x27;])           ← 又自动变了！</span></code></pre><p>支持集合运算</p><pre><code class="hljs python">d1 = &#123;<span class="hljs-string">&#x27;Alice&#x27;</span>: <span class="hljs-number">1</span>, <span class="hljs-string">&#x27;Bob&#x27;</span>: <span class="hljs-number">2</span>, <span class="hljs-string">&#x27;Charlie&#x27;</span>: <span class="hljs-number">3</span>&#125;d2 = &#123;<span class="hljs-string">&#x27;Bob&#x27;</span>: <span class="hljs-number">4</span>, <span class="hljs-string">&#x27;David&#x27;</span>: <span class="hljs-number">5</span>, <span class="hljs-string">&#x27;Alice&#x27;</span>: <span class="hljs-number">6</span>&#125;<span class="hljs-comment"># 交集：两个字典都有的键</span><span class="hljs-built_in">print</span>(d1.keys() &amp; d2.keys())   <span class="hljs-comment"># &#123;&#x27;Alice&#x27;, &#x27;Bob&#x27;&#125;</span><span class="hljs-comment"># 并集：所有出现过的键</span><span class="hljs-built_in">print</span>(d1.keys() | d2.keys())   <span class="hljs-comment"># &#123;&#x27;Alice&#x27;, &#x27;Bob&#x27;, &#x27;Charlie&#x27;, &#x27;David&#x27;&#125;</span><span class="hljs-comment"># 差集：d1 有但 d2 没有的键</span><span class="hljs-built_in">print</span>(d1.keys() - d2.keys())   <span class="hljs-comment"># &#123;&#x27;Charlie&#x27;&#125;</span></code></pre></blockquote></li><li><p><code>items</code>: 取字典的元素</p></li><li><p><code>values</code>: 取字典的值</p><pre><code class="hljs python"><span class="hljs-comment">#常用</span><span class="hljs-comment">#遍历字典⚠️</span><span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> d.items():    <span class="hljs-built_in">print</span>(x,end=<span class="hljs-string">&quot;,&quot;</span>)<span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> d.values():    <span class="hljs-built_in">print</span>(x,end=<span class="hljs-string">&quot;,&quot;</span>)<span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> d.keys():    <span class="hljs-built_in">print</span>(x,end=<span class="hljs-string">&quot;,&quot;</span>)</code></pre></li><li><p><code>copy</code>: 浅拷贝</p></li><li><p>深拷贝:</p><pre><code class="hljs python"><span class="hljs-keyword">import</span> copyx=&#123;<span class="hljs-string">&#x27;username&#x27;</span>:<span class="hljs-string">&#x27;admin&#x27;</span>,<span class="hljs-string">&#x27;machine&#x27;</span>:[<span class="hljs-string">&#x27;foo&#x27;</span>,<span class="hljs-string">&#x27;bar&#x27;</span>,<span class="hljs-string">&#x27;baz&#x27;</span>]&#125;y=copy.deepcopy(x)y[<span class="hljs-string">&#x27;username&#x27;</span>]=<span class="hljs-string">&#x27;mlh&#x27;</span>y[<span class="hljs-string">&#x27;machine&#x27;</span>].remove(<span class="hljs-string">&#x27;bar&#x27;</span>)<span class="hljs-built_in">print</span>(y)<span class="hljs-built_in">print</span>(x)</code></pre></li></ul><h2 id="集合"><a href="#集合" class="headerlink" title="集合"></a>集合</h2><h3 id="概念-1"><a href="#概念-1" class="headerlink" title="概念"></a>概念</h3><ul><li><code>set</code></li><li><strong>可修改</strong>, 概念同数学</li><li><strong>无重复元素</strong></li><li><strong>无序</strong></li><li><strong>列表和集合不可作为集合的元素</strong>, 元素必须<strong>可哈希</strong></li><li>快速查找, <strong>查找时间和元素个数无关</strong></li><li>若有重复, 会<strong>自动去重</strong></li></ul><h3 id="操作-2"><a href="#操作-2" class="headerlink" title="操作"></a>操作</h3><ul><li><p>创建</p><pre><code class="hljs python">s=&#123;&#125;s=&#123;<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-string">&#x27;ok&#x27;</span>,(<span class="hljs-number">1</span>,<span class="hljs-number">3</span>)&#125;<span class="hljs-built_in">print</span>(s)<span class="hljs-comment">#&#123;&#x27;ok&#x27;, 1, 2, (1, 3)&#125;</span>s=<span class="hljs-built_in">set</span>(<span class="hljs-string">&#x27;abc&#x27;</span>) <span class="hljs-comment">#字符串转集合</span><span class="hljs-built_in">print</span>(s)<span class="hljs-comment">#&#123;&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;&#125;</span>s=<span class="hljs-built_in">set</span>([<span class="hljs-number">1</span>,<span class="hljs-string">&#x27;ok&#x27;</span>,<span class="hljs-number">2.4</span>])<span class="hljs-built_in">print</span>(s)</code></pre></li><li><p><code>add(x)</code>: 增加</p></li><li><p>集合运算</p><pre><code class="hljs python">a=&#123;<span class="hljs-number">1</span>,<span class="hljs-number">3</span>,<span class="hljs-number">3</span>,<span class="hljs-string">&#x27;e&#x27;</span>&#125;b=&#123;<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-string">&#x27;e&#x27;</span>&#125;<span class="hljs-built_in">print</span>(a&amp;b) <span class="hljs-comment">#求交</span><span class="hljs-built_in">print</span>(a|b) <span class="hljs-comment">#求并</span><span class="hljs-built_in">print</span>(a-b) <span class="hljs-comment">#求差</span>a-=b<span class="hljs-built_in">print</span>(a)</code></pre></li><li><p><code>update(x)</code>: 将参数分开并加入集合(参数可以是集合\字典\列表\元组等, x可有多个(逗号隔开))</p><pre><code class="hljs python">a=&#123;<span class="hljs-number">1</span>&#125;a.update([<span class="hljs-number">34</span>,<span class="hljs-number">22</span>,<span class="hljs-number">1</span>])<span class="hljs-built_in">print</span>(a)a.update(<span class="hljs-string">&quot;hello&quot;</span>)<span class="hljs-built_in">print</span>(a)</code></pre></li><li><p><code>remove(x)</code>: 删除元素, <strong>若不存在会报错</strong></p></li><li><p><code>discard(x)</code>:移除元素, <strong>若不存在不会异常</strong></p></li><li><p>比较运算符, 判断是不是超集</p></li><li><p><code>clear()</code>: 清空</p></li><li><p><code>difference(x)</code>: 返回在s而不在x中的元素的集合,不改变原内容</p></li><li><p><code>symmetric_difference(x)</code>: 返回<strong>对称差集</strong>,即只在其中一个集合中出现的元素, 不改变原内容, </p></li><li><p><code>in</code></p></li><li><p><code>union(x)</code>: 返回s和x的并集,不改变原内容</p></li><li><p><code>intersection(x)</code> 返回交集,不改变原内容</p></li><li><p><code>issubset(x)</code> 判断集合s是否是集合x子集</p></li><li><p><code>issuperset(x)</code> s是否是x的超集</p></li><li><p><code>pop()</code>: 随机删除并返回集合中的某个值</p></li></ul><blockquote><p>⚠️集合和字典都没有<code>+</code>的相关运算, set有add方法, <strong>字典没有</strong></p></blockquote>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/194c/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/194c/"/>
    <published>2026-05-18T16:00:00.000Z</published>
    <summary>元组、列表与序列操作</summary>
    <title>Python修养2</title>
    <updated>2026-07-21T09:00:33.271Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--Python" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-Python/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="Python" scheme="https://flowwalker.github.io/coding-notes-blog/tags/Python/"/>
    <content>
      <![CDATA[<h1 id="Python修养1"><a href="#Python修养1" class="headerlink" title="Python修养1"></a>Python修养1</h1><ul><li><p>思想:</p><ul><li><p>换行当<code>;</code></p></li><li><p>缩进当{}</p></li><li><p>对象三属性</p><ul><li>值: 可变&#x2F;不可变</li><li>身份: 内存唯一地址,严格只读</li><li>类型( 可用<code>type(you_want)</code>来读取)</li></ul></li><li><p><strong>每个变量都相当于指向某个对象的引用</strong></p><blockquote><p>引用对象可变, 则可以通过变量修改</p><p>引用对象<strong>不可变</strong>,则<strong>只能让变量指向另一个新对象</strong></p></blockquote><p><img src="https://cdn.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260506195354560.png" alt="image-20260506195354560"></p></li></ul></li><li><p>⚠️python里的<code>=</code><strong>永远是指向对象操作</strong>而非拷贝</p><ul><li><p><code>a=b</code> 指向同一个对象</p></li><li><p><strong>对象可变且做原地修改</strong>, 原地改动</p></li><li><p>🌊对象不可变且做了”修改”操作, <strong>必须创建新的对象</strong></p><p><code>a=a+b</code>创建新对象, a然后指向他</p><p><code>a+=b</code>原地修改,a不指向新对象</p></li></ul></li><li><p>关于注释: </p><ul><li>单行<code>#</code></li><li>多行<code>command</code>+<code>/</code></li></ul></li><li><p>关于赋值的随意性</p><p><code>s1,s2,s4,s3=s4,s3,s2,s1</code></p></li><li><p>关于变量</p><ul><li><p>不需声明, 使用前必须赋值</p></li><li><p><strong>类型可变</strong></p></li><li><p>没有<code>double</code>（ 或者说<code>double</code>就叫<code>float</code>）, 多了<code>complex</code>和<code>tuple</code>和<code>dict</code>, <code>string</code>叫<code>str</code>, 列表叫<code>list</code> ——类型名相当于类名</p><pre><code class="hljs python">a=<span class="hljs-built_in">str</span>()b=<span class="hljs-number">1</span>+<span class="hljs-number">2j</span></code></pre></li><li><p>元组本身<strong>不可变</strong>, 但是⚠️<strong>其中可变对象元素仍可变</strong></p></li></ul></li><li><p>关于运算符</p><p><code>**</code>表示幂运算</p></li><li><p>关于布尔类型</p><ul><li><p>注意是<code>True</code>和<code>False</code>, 大小写有规范</p></li><li><p><code>0</code> 空 <code>str</code> <code>tuple</code> <code>list</code> <code>dist</code>都<strong>相当于</strong><code>False</code> ( 但<strong>不是等于</strong>)</p><pre><code class="hljs Python"><span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> ():<span class="hljs-built_in">print</span> (<span class="hljs-string">&quot;ok&quot;</span>) <span class="hljs-comment"># ok</span><span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> &#123;&#125;:<span class="hljs-built_in">print</span> (<span class="hljs-string">&quot;ok&quot;</span>) <span class="hljs-comment"># ok</span><span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> <span class="hljs-string">&quot;&quot;</span>:<span class="hljs-built_in">print</span> (<span class="hljs-string">&quot;ok&quot;</span>) <span class="hljs-comment"># ok</span><span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> []:<span class="hljs-built_in">print</span> (<span class="hljs-string">&quot;ok&quot;</span>) <span class="hljs-comment"># ok</span></code></pre></li><li><p><code>True</code>可以看作<code>1</code>, <code>False</code>可以看作<code>0</code></p></li></ul><pre><code class="hljs Python"><span class="hljs-literal">True</span> == <span class="hljs-number">1</span> <span class="hljs-comment">#True</span><span class="hljs-literal">False</span> == <span class="hljs-number">0</span> <span class="hljs-comment">#True</span><span class="hljs-string">&quot;&quot;</span> == <span class="hljs-literal">False</span> <span class="hljs-comment">#False</span><span class="hljs-number">2</span> == <span class="hljs-literal">True</span> <span class="hljs-comment">#False</span>[] == <span class="hljs-literal">False</span> <span class="hljs-comment">#False</span>[<span class="hljs-number">2</span>,<span class="hljs-number">3</span>] == <span class="hljs-literal">True</span> <span class="hljs-comment">#False</span></code></pre></li><li><p>关于逻辑运算符</p><p>注意是<code>and</code> 和 <code>or</code> 和 <code>not</code></p></li><li><p>关于类型转换函数</p><ul><li><p>⚠️<code>repr(x)</code>将x转换为<strong>字符串表达式</strong>, 注意类型是<strong>字符串</strong></p></li><li><p><code>chr(x)</code>将x转换为对应ASCII码字符</p><blockquote><p><code>ord(x)</code>将字符转换为整数编码值(16位)</p><pre><code class="hljs Python"><span class="hljs-built_in">print</span>(<span class="hljs-built_in">repr</span>(<span class="hljs-number">12.334</span>)) <span class="hljs-comment"># 12.334 </span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">str</span>(<span class="hljs-string">&quot;hello&quot;</span>)) <span class="hljs-comment"># hello </span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">repr</span>(<span class="hljs-string">&quot;hello&quot;</span>)) <span class="hljs-comment"># &#x27;hello&#x27;</span></code></pre></blockquote></li><li><p>列表和字符串的转换</p><p>语法: <code>&lt;str&gt; = &lt;separator&gt;.join(&lt;list&gt;)</code></p><pre><code class="hljs Python">newstr = <span class="hljs-built_in">list</span>(<span class="hljs-string">&#x27;abcdafg&#x27;</span>)<span class="hljs-built_in">print</span>(newstr) <span class="hljs-comment"># [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;, &#x27;d&#x27;, &#x27;a&#x27;, &#x27;f&#x27;, &#x27;g&#x27;]</span>newstr[<span class="hljs-number">4</span>] = <span class="hljs-string">&#x27;e&#x27;</span><span class="hljs-built_in">str</span> = <span class="hljs-string">&#x27;&#x27;</span>.join(newstr) <span class="hljs-comment">#列表到字符串转换</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">str</span>) <span class="hljs-comment"># abcdefg</span></code></pre></li><li><p><code>int(x)</code>不会把x变成整数</p></li><li><p>⚠️<code>eval(x)</code>把字符串x看做一个表达式求其值</p><blockquote><p>理想情况下</p><p><code>eval(repr(x))=x</code></p></blockquote></li></ul></li></ul><h2 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h2><p>[TOC]</p><h2 id="关于运算符"><a href="#关于运算符" class="headerlink" title="关于运算符"></a>关于运算符</h2><ul><li><p>运算符中<strong>只要有一个操作数是小数</strong>结果就是<strong>小数</strong>, 若需要结果整数, 需要<strong>额外强制转换</strong></p></li><li><p>使用<code>/</code>即使整除也是<strong>浮点数</strong></p></li><li><p><code>//</code>整除向下取整,而非<del>向零</del>(c++向0)</p></li></ul><h2 id="关于循环"><a href="#关于循环" class="headerlink" title="关于循环"></a>关于循环</h2><pre><code class="hljs python"><span class="hljs-keyword">for</span> &lt;变量&gt; <span class="hljs-keyword">in</span> &lt;序列&gt;:    &lt;语句组&gt;<span class="hljs-keyword">else</span>:    &lt;语句组&gt;</code></pre><pre><code class="hljs Python"><span class="hljs-keyword">while</span> &lt;逻辑表达式&gt;:    &lt;语句组&gt;<span class="hljs-keyword">else</span>:    &lt;语句组&gt;</code></pre><ul><li>没有<code>switch</code></li><li>&lt;序列&gt;可用<code>range</code>生成</li><li><code>pass</code>表示什么都不做, 占位; <code>continue</code>和<code>break</code>同用</li></ul><h2 id="关于print"><a href="#关于print" class="headerlink" title="关于print"></a>关于print</h2><p><code>print(s,end=&quot; &quot;)</code>  缺省情况<code>end=&#39;\n&#39;</code></p><p>简单构造字符串: “xxxx %s xxxx %(s)”</p><h2 id="关于is和-的区别"><a href="#关于is和-的区别" class="headerlink" title="关于is和&#x3D;&#x3D;的区别"></a>关于is和&#x3D;&#x3D;的区别</h2><ul><li><code>a is b</code>为<code>True</code>说明a和b<strong>指向同一个地方</strong></li><li><code>a==b</code>为<code>True</code>则说明<strong>放的东西相同</strong>,不一定指向同一个地方</li></ul><blockquote><p><code>a=b</code>使得a和b指向同一个地方</p></blockquote><p>⚠️一般需要:</p><ul><li><p>用<code>==</code>比较值</p></li><li><p>用<code>is</code>比较是否同一个对象</p><blockquote><p><code>=</code>会导致变量别名, ⚠️一个赋值给另一个, 两个变量将<strong>指向同一个对象</strong>, <strong>修改任何一个都会影响另一个</strong></p></blockquote></li></ul><blockquote><p>为了复用同一个对象, 常常有驻留, <code>is</code>难预测→对于**不可变类型只需关注<code>==</code>, 不得用<code>is</code>判断值是否相等 **</p><blockquote><p>推荐使用<code>is</code>的场景</p><p><code>if x is None</code></p></blockquote></blockquote><blockquote><p>小整数有缓存机制, 元组一般没有驻留( 小整数可能会)</p></blockquote><h2 id="关于整数类型"><a href="#关于整数类型" class="headerlink" title="关于整数类型"></a>关于整数类型</h2><p><strong>任意长</strong></p><ul><li>0b前缀表示<strong>二</strong>进制</li><li>0o前缀表示<strong>八</strong>进制</li><li>0x前缀表示<strong>十六</strong>进制</li></ul><p>可以使用例如<code>12.99.is_integer()</code>来判断是否整数</p><blockquote><p>查询是否是某个类型</p><p><code>isinstance(&lt;变量名&gt;,&lt;type&gt;)</code></p></blockquote><h2 id="关于浮点数相等的判断"><a href="#关于浮点数相等的判断" class="headerlink" title="关于浮点数相等的判断"></a>关于浮点数相等的判断</h2><p>⚠️用<code>equal_float</code>判断</p><pre><code class="hljs Python"><span class="hljs-keyword">import</span> sys<span class="hljs-keyword">def</span> <span class="hljs-title function_">equal_float</span>(<span class="hljs-params">a,b</span>):<span class="hljs-keyword">return</span> <span class="hljs-built_in">abs</span>(a-b) &lt;= sys.float_info.epsilon<span class="hljs-comment">#最小浮点数间隔,32位机为 2e-16</span><span class="hljs-built_in">print</span>(equal_float(<span class="hljs-number">0.3</span>,<span class="hljs-number">0.1</span>+<span class="hljs-number">0.2</span>))</code></pre><blockquote><p>想看看<code>sys.float_info</code></p><p>可以</p><pre><code class="hljs python"><span class="hljs-keyword">import</span> sys<span class="hljs-built_in">print</span>(sys.float_info)</code></pre><p>此外</p><pre><code class="hljs python"><span class="hljs-keyword">import</span> mathx = <span class="hljs-number">123.50</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">round</span>(x)) <span class="hljs-comment">#不精确，如print(round(119.49999999999999999)) =&gt; 120</span><span class="hljs-built_in">print</span>(math.floor(x))<span class="hljs-built_in">print</span>(math.ceil(x))<span class="hljs-built_in">print</span>(<span class="hljs-number">12.3</span>.is_integer())</code></pre></blockquote><h2 id="关于输入和输出"><a href="#关于输入和输出" class="headerlink" title="关于输入和输出"></a>关于输入和输出</h2><ul><li><p>关于<code>input(&lt;问候语&gt;)</code></p><ul><li>输出问候语, 读取输入的<strong>字符串</strong>, 需要<strong>强制类型转换才能当数字用</strong></li></ul></li><li><p>一行多输入</p><pre><code class="hljs Python">lst=<span class="hljs-built_in">input</span>().split()x,y,z=<span class="hljs-built_in">int</span>(lst[<span class="hljs-number">0</span>]),lst[<span class="hljs-number">1</span>],<span class="hljs-built_in">int</span>(lst[<span class="hljs-number">2</span>])<span class="hljs-comment"># x,z是整数,y是字符串</span><span class="hljs-comment"># ...</span><span class="hljs-comment"># split函数内部可以指定分割符如&quot;,.&quot;表示以&quot;,.&quot;为分割符而⚠️不是其中任意字符</span></code></pre><p><code>split(s)</code>开头和结尾有<strong>非缺省</strong>分割符的<strong>字符串列表</strong>会额外输出空串</p><p>( <strong>缺省</strong>情况下智能<strong>合并连续分割符</strong>并<strong>忽略开头和结尾分割符</strong>)</p></li><li><p>输入输出的重定向</p><pre><code class="hljs Python"><span class="hljs-keyword">import</span> sysf=<span class="hljs-built_in">open</span>(<span class="hljs-string">&quot;t.txt&quot;</span>,<span class="hljs-string">&quot;r&quot;</span>)g=<span class="hljs-built_in">open</span>(<span class="hljs-string">&quot;d.txt&quot;</span>,<span class="hljs-string">&quot;w&quot;</span>)sys.stdin=fsys.stdout=gs=<span class="hljs-built_in">input</span>()<span class="hljs-built_in">print</span>(s)f.close()g.close()</code></pre></li><li><p><code>x.split()</code>的值是一个列表, 包含字符串经过<strong>空格, 制表符, 换行符</strong>分隔得到的所有子串, 但是<strong>input默认情况下只读一行</strong></p></li></ul><h2 id="关于字符串"><a href="#关于字符串" class="headerlink" title="关于字符串"></a>关于字符串</h2><ul><li><code>*</code>可以构成重复字符串</li></ul><p>⚠️重点</p><h3 id="赋值"><a href="#赋值" class="headerlink" title="赋值"></a>赋值</h3><p>单引号\双引号\三引号 皆可</p><p>其中<strong>三双引号可以包含换行符\制表符\特殊符号</strong></p><ul><li><p>字符串太长</p><pre><code class="hljs python"><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;this \</span><span class="hljs-string">is \</span><span class="hljs-string">good&quot;</span>)</code></pre><blockquote><p>太长了使用<code>()</code>或<code>\</code></p><pre><code class="hljs Python"><span class="hljs-keyword">if</span> a&gt;<span class="hljs-number">3</span> <span class="hljs-keyword">and</span> \a&lt;<span class="hljs-number">9</span>:    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)<span class="hljs-keyword">if</span>(a&gt;<span class="hljs-number">3</span> <span class="hljs-keyword">and</span>  a&lt;<span class="hljs-number">9</span>):    <span class="hljs-built_in">print</span>(<span class="hljs-string">&#x27;ok&#x27;</span>)</code></pre></blockquote></li></ul><h3 id="访问"><a href="#访问" class="headerlink" title="访问"></a>访问</h3><p><code>变量[序号或切片]</code>访问子串</p><p>完成切片语法</p><p><code>x[start:stop:step]</code></p><pre><code class="hljs Python">x=<span class="hljs-string">&quot;aggfdfd&quot;</span><span class="hljs-built_in">print</span>(x[-<span class="hljs-number">3</span>:-<span class="hljs-number">1</span>])<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;hhh&quot;</span>[<span class="hljs-number">2</span>])<span class="hljs-built_in">print</span>(x[-<span class="hljs-number">1</span>:])<span class="hljs-built_in">print</span>(x[:])<span class="hljs-built_in">print</span>(::-<span class="hljs-number">1</span>) <span class="hljs-comment"># 反转字符串</span></code></pre><p>⚠️字符串是不可修改的</p><blockquote><p>如果确实需要,应先转换为列表</p><pre><code class="hljs Python">s = <span class="hljs-built_in">list</span>(<span class="hljs-string">&quot;abc&quot;</span>)   <span class="hljs-comment"># [&#x27;a&#x27;, &#x27;b&#x27;, &#x27;c&#x27;]</span>s[<span class="hljs-number">0</span>] = <span class="hljs-string">&quot;z&quot;</span>        <span class="hljs-comment"># 可以改</span><span class="hljs-string">&quot;&quot;</span>.join(s)        <span class="hljs-comment"># &quot;zbc&quot;</span><span class="hljs-comment">#否则</span>s=<span class="hljs-string">&quot;kskksk&quot;</span>s[<span class="hljs-number">1</span>]=<span class="hljs-string">&quot;d&quot;</span> <span class="hljs-comment">#error</span></code></pre></blockquote><h3 id="输出不转义字符"><a href="#输出不转义字符" class="headerlink" title="输出不转义字符"></a>输出不转义字符</h3><p><code>print(r&#39;ab\ncd&#39;)</code></p><h3 id="判断子串"><a href="#判断子串" class="headerlink" title="判断子串"></a>判断子串</h3><p><code>in</code></p><p><code>not in</code> </p><p>正常语言即可</p><p>print(<code>&quot;hello&quot; in s</code>)</p><h3 id="字符串函数"><a href="#字符串函数" class="headerlink" title="字符串函数"></a>字符串函数</h3><ul><li><p><code>count</code>求解子串出现次数</p></li><li><p><code>len</code>求解字符串长度</p></li><li><p>其他的</p><ul><li><code>s.upper()</code>, <code>s.lower()</code>, <code>s.isdigit()</code>(是否全为数字)</li><li><code>s.startwith()</code>, <code>s.endwith()</code></li><li><code>s.find(want)</code>找不到返回<code>-1</code>,<code>s.index(want)</code>抛出异常</li><li><code>s.replace(target_index,replacement)</code></li></ul></li><li><p><code>s.strip(s)</code> 除去两端空格, <code>\r</code> , <code>\t</code> , <code>\n</code> </p><ul><li><p><code>s.lstrip(s)</code>除左端</p></li><li><p><code>s.rstrip(s)</code>除右端</p><p><code>s</code>缺省情况下为空白字符, 指定情况下为s中的<strong>所有字符</strong></p></li></ul></li></ul><h3 id="用多个字符分割"><a href="#用多个字符分割" class="headerlink" title="用多个字符分割"></a>用多个字符分割</h3><p>格式:</p><p><code>re.split(pattern,string)</code></p><p>pattern: 匹配的正则表达式</p><p>string: 要匹配的字符串</p><pre><code class="hljs Python"><span class="hljs-keyword">import</span> rea=<span class="hljs-string">&quot;Beautiful, is; better*than\nugly&quot;</span><span class="hljs-built_in">print</span>(re.split(<span class="hljs-string">&#x27;;| |,|\*|\n&#x27;</span>,a))<span class="hljs-comment"># [&#x27;Beautiful&#x27;, &#x27;&#x27;, &#x27;is&#x27;, &#x27;&#x27;, &#x27;better&#x27;, &#x27;than&#x27;, &#x27;ugly&#x27;]</span></code></pre><blockquote><p>正则 <code>;| |,|\*|\n</code> 表示遇到 <strong>分号、空格、逗号、星号、换行</strong> 都要切一刀。</p><p>字符串的编码在内存中的编码是unicode的。没有字符类型</p><pre><code class="hljs Python"><span class="hljs-built_in">print</span>(<span class="hljs-built_in">ord</span>(<span class="hljs-string">&quot;a&quot;</span>))<span class="hljs-built_in">print</span>(<span class="hljs-built_in">ord</span>(<span class="hljs-string">&quot;好&quot;</span>))<span class="hljs-built_in">print</span>(<span class="hljs-built_in">chr</span>(<span class="hljs-number">22900</span>))<span class="hljs-built_in">print</span>(<span class="hljs-built_in">chr</span>(<span class="hljs-number">97</span>))</code></pre></blockquote><p>🌊以下为AI整理, 若有时间需勤加复习</p><h3 id="字符串格式化"><a href="#字符串格式化" class="headerlink" title="字符串格式化"></a>字符串格式化</h3><pre><code class="hljs python"><span class="hljs-comment"># % 格式化: %s字符串 %d整数 %f浮点数 %.nf保留n位小数</span><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;My name is %s, I am %.2fm tall.&quot;</span> % (<span class="hljs-string">&quot;tom&quot;</span>, <span class="hljs-number">1.746</span>))<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;My age is %d.&quot;</span> % <span class="hljs-number">18</span>)<span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;%d%s&quot;</span> % (<span class="hljs-number">18</span>, <span class="hljs-string">&quot;hello&quot;</span>))<span class="hljs-comment"># format方法: &#123;序号:宽度.精度.类型&#125;</span>x = <span class="hljs-string">&quot;Hello &#123;0&#125; &#123;1:10&#125;, you get $&#123;2:0.4f&#125;&quot;</span>.<span class="hljs-built_in">format</span>(<span class="hljs-string">&quot;Mr.&quot;</span>, <span class="hljs-string">&quot;Jack&quot;</span>, <span class="hljs-number">3.2</span>)<span class="hljs-comment"># &gt; 右对齐, &lt; 左对齐, ^ 中对齐</span>x = <span class="hljs-string">&quot;Hello &#123;0&#125; &#123;1:&gt;10&#125;, you get $&#123;2:0.4f&#125;&quot;</span>.<span class="hljs-built_in">format</span>(<span class="hljs-string">&quot;Mr.&quot;</span>, <span class="hljs-string">&quot;Jack&quot;</span>, <span class="hljs-number">3.2</span>)x = <span class="hljs-string">&quot;Hello &#123;0&#125; &#123;1:^10&#125;, you get $&#123;2:0.4f&#125;&quot;</span>.<span class="hljs-built_in">format</span>(<span class="hljs-string">&quot;Mr.&quot;</span>, <span class="hljs-string">&quot;Jack&quot;</span>, <span class="hljs-number">3.2</span>)</code></pre><p>⚠️**<code>%.nf</code> 不是四舍五入，是”四舍六入五成双”**</p><ul><li>≤4 舍去，≥6 进一</li><li>5 看前面数字奇偶：前为奇则进，前为偶则舍；5后面还有有效数字则一定进</li></ul><pre><code class="hljs python"><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;%.2f, %.2f&quot;</span> % (<span class="hljs-number">5.225</span>, <span class="hljs-number">5.325</span>))  <span class="hljs-comment"># 5.22, 5.33</span><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;%.1f&quot;</span> % <span class="hljs-number">1.15</span>)  <span class="hljs-comment"># 1.2</span><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;%.1f&quot;</span> % <span class="hljs-number">1.25</span>)  <span class="hljs-comment"># 1.2  (2是偶数，舍)</span><span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;%.1f&quot;</span> % <span class="hljs-number">1.25012</span>)  <span class="hljs-comment"># 1.3  (5后面还有数，进)</span></code></pre><hr><h3 id="关于字符编码"><a href="#关于字符编码" class="headerlink" title="关于字符编码"></a>关于字符编码</h3><ul><li><strong>ASCII</strong>：1字节，只表示英文、数字、标点（如 <code>&#39;a&#39;</code> 是 <code>0x61</code>）</li><li><strong>GB2312&#x2F;GBK</strong>：兼容ASCII，中文用<strong>2个最高位为1的字节</strong>表示</li><li><strong>Unicode</strong>：内存编码，几乎涵盖所有文字，每个字符2字节（个别4字节）；Python字符串即Unicode</li><li><strong>UTF-8</strong>：<strong>可变长</strong>（1-6字节），英文1字节、中文通常3字节；<strong>文件存储&#x2F;网络传输一般用UTF-8</strong></li></ul><pre><code class="hljs python"><span class="hljs-built_in">print</span>(<span class="hljs-built_in">ord</span>(<span class="hljs-string">&#x27;好&#x27;</span>))   <span class="hljs-comment"># 22920  Unicode码点</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">ord</span>(<span class="hljs-string">&#x27;a&#x27;</span>))    <span class="hljs-comment"># 97</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">chr</span>(<span class="hljs-number">22920</span>))  <span class="hljs-comment"># 好</span></code></pre><p>⚠️UTF-8文件开头可能有3字节标记 <strong>BOM</strong>（<code>EF BB BF</code>），记事本能正常显示，但C++用 <code>cin</code> 读取会出错。C++需用 <code>_wfopen(L&quot;utf8.txt&quot;, L&quot;r,ccs=utf-8&quot;)</code> 之类方式读取。</p><hr><h3 id="关于字符串与字节流"><a href="#关于字符串与字节流" class="headerlink" title="关于字符串与字节流"></a>关于字符串与字节流</h3><p>Python字符串是Unicode，要保存到文件或发送需<strong>编码</strong>为字节流；读取时自动&#x2F;手动<strong>解码</strong>：</p><pre><code class="hljs python">s = <span class="hljs-string">&#x27;ABC好的&#x27;</span><span class="hljs-comment"># 编码为字节流</span>bs = s.encode(<span class="hljs-string">&#x27;utf-8&#x27;</span>)<span class="hljs-built_in">print</span>(bs)        <span class="hljs-comment"># b&#x27;ABC\xe5\xa5\xbd\xe7\x9a\x84&#x27;</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">len</span>(bs))   <span class="hljs-comment"># 9  (中文3字节×2 + 英文1字节×3)</span>bs = s.encode(<span class="hljs-string">&#x27;gbk&#x27;</span>)<span class="hljs-built_in">print</span>(<span class="hljs-built_in">len</span>(bs))   <span class="hljs-comment"># 7  (中文2字节×2 + 英文1字节×3)</span><span class="hljs-comment"># 另一种写法</span>bs = <span class="hljs-built_in">bytes</span>(<span class="hljs-string">&#x27;ABC好的&#x27;</span>, encoding=<span class="hljs-string">&#x27;gbk&#x27;</span>)<span class="hljs-comment"># 解码回字符串</span>s = <span class="hljs-built_in">str</span>(bs, encoding=<span class="hljs-string">&#x27;utf-8&#x27;</span>)   <span class="hljs-comment"># ABC好的</span><span class="hljs-built_in">print</span>(<span class="hljs-built_in">str</span>(<span class="hljs-string">b&#x27;abc\xe5\xa5\xbd\xe7\x9a\x84&#x27;</span>, encoding=<span class="hljs-string">&#x27;utf-8&#x27;</span>))  <span class="hljs-comment"># abc好的</span></code></pre><hr><h3 id="关于源程序编码"><a href="#关于源程序编码" class="headerlink" title="关于源程序编码"></a>关于源程序编码</h3><p>Python 3 默认认为 <code>.py</code> 源文件是 <strong>UTF-8</strong> 编码（且期望有BOM）。如果源文件实际是GBK且无编码声明，运行报错：</p><pre><code class="hljs clean">SyntaxError: Non-UTF<span class="hljs-number">-8</span> <span class="hljs-keyword">code</span> starting <span class="hljs-keyword">with</span> <span class="hljs-string">&#x27;\xb7&#x27;</span> <span class="hljs-keyword">in</span> file testansi.py...</code></pre><p>解决办法：在源文件<strong>第一行或第二行</strong>加声明</p><pre><code class="hljs python"><span class="hljs-comment"># -*- coding: GBK -*-</span></code></pre><blockquote><p>PyCharm编写的 <code>.py</code> 文件默认就是UTF-8，一般无需额外声明。</p></blockquote><hr><h3 id="C-与Python字符串对比"><a href="#C-与Python字符串对比" class="headerlink" title="C++与Python字符串对比"></a>C++与Python字符串对比</h3><table><thead><tr><th align="left">特性</th><th align="left">C++ <code>std::string</code></th><th align="left">Python <code>str</code></th></tr></thead><tbody><tr><td align="left">可变性</td><td align="left"><strong>可变</strong>（可直接改 <code>s[0]=&#39;H&#39;</code>）</td><td align="left"><strong>不可变</strong>（修改需创建新对象）</td></tr><tr><td align="left">越界访问</td><td align="left">需手动注意，可能崩溃</td><td align="left">自动抛异常</td></tr><tr><td align="left">引号</td><td align="left">双引号（单引号是<code>char</code>）</td><td align="left">单&#x2F;双&#x2F;三引号均可</td></tr><tr><td align="left">Unicode</td><td align="left">需<code>std::wstring</code>或第三方库</td><td align="left"><strong>原生支持</strong></td></tr><tr><td align="left">空值</td><td align="left"><code>&quot;&quot;</code></td><td align="left"><code>&quot;&quot;</code> 或 <code>None</code></td></tr><tr><td align="left">性能</td><td align="left">直接操作内存，快</td><td align="left">因不可变性+GC稍慢，但开发效率高</td></tr></tbody></table><p><strong>操作语法差异：</strong></p><pre><code class="hljs python"><span class="hljs-comment"># 初始化</span>s1 = <span class="hljs-string">&quot;hello&quot;</span>s2 = <span class="hljs-string">&#x27;a&#x27;</span> * <span class="hljs-number">5</span>          <span class="hljs-comment"># C++: string s2(5, &#x27;a&#x27;)</span><span class="hljs-comment"># 长度</span>len1 = <span class="hljs-built_in">len</span>(s1)        <span class="hljs-comment"># C++: s1.size() 或 s1.length()</span><span class="hljs-comment"># 拼接</span>s3 = s1 + <span class="hljs-string">&quot; &quot;</span> + s2    <span class="hljs-comment"># 同C++，但Python不可变，结果是新对象</span><span class="hljs-comment"># 访问</span>c = s1[<span class="hljs-number">0</span>]             <span class="hljs-comment"># 同C++，但 s1[0] = &#x27;H&#x27; 会报错！</span><span class="hljs-comment"># 比较</span>is_equal = (s1 == s2) <span class="hljs-comment"># 同C++</span>is_less = (s1 &gt; s2)   <span class="hljs-comment"># 同C++，按字典序</span>result = (s1 &gt; s2) - (s1 &lt; s2)  <span class="hljs-comment"># C++: s1.compare(s2) 返回1/0/-1</span><span class="hljs-comment"># 交换</span>s1, s2 = s2, s1       <span class="hljs-comment"># C++: swap(s1, s2)</span><span class="hljs-comment"># 切片/子串</span>sub = s1[<span class="hljs-number">1</span>:<span class="hljs-number">4</span>]         <span class="hljs-comment"># &quot;ell&quot;  左闭右开；C++: s1.substr(1, 3)</span><span class="hljs-comment"># 查找</span>pos = s1.find(<span class="hljs-string">&quot;ell&quot;</span>)  <span class="hljs-comment"># 返回索引或-1；C++: 返回索引或 string::npos</span><span class="hljs-comment"># 替换</span>s1 = s1.replace(<span class="hljs-string">&quot;ell&quot;</span>, <span class="hljs-string">&quot;ipp&quot;</span>)  <span class="hljs-comment"># ⚠️返回新字符串！C++: s1.replace(1,3,&quot;ipp&quot;)原地改</span><span class="hljs-comment"># 字符串↔数字</span>num = <span class="hljs-built_in">int</span>(<span class="hljs-string">&quot;123&quot;</span>)      <span class="hljs-comment"># C++: stoi(s)</span>s1 = <span class="hljs-built_in">str</span>(<span class="hljs-number">123</span>)         <span class="hljs-comment"># C++: to_string(num)</span>f = <span class="hljs-built_in">float</span>(<span class="hljs-string">&quot;3.14&quot;</span>)     <span class="hljs-comment"># C++: stof(s)</span>s1 = <span class="hljs-built_in">str</span>(<span class="hljs-number">3.14</span>)        <span class="hljs-comment"># C++: to_string(f)</span></code></pre><h2 id="关于错误日志"><a href="#关于错误日志" class="headerlink" title="关于错误日志"></a>关于错误日志</h2><pre><code class="hljs python"><span class="hljs-keyword">try</span>:    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;ok&quot;</span>)<span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:    <span class="hljs-built_in">print</span>(e)<span class="hljs-comment">#如果报错打印错误报告</span></code></pre><h2 id="lambda表达式"><a href="#lambda表达式" class="headerlink" title="lambda表达式"></a>lambda表达式</h2><p><code>lambda 参数1,参数2,...: 返回值</code></p><h3 id="配合map"><a href="#配合map" class="headerlink" title="配合map"></a>配合map</h3><p><code>ls=list(map(lambda x:x*2,ls))</code></p><h3 id="配合reduce"><a href="#配合reduce" class="headerlink" title="配合reduce"></a>配合reduce</h3><p><code>result=reduce(lambda x,y:x+y,ls)</code></p>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/180c/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/180c/"/>
    <published>2026-05-05T16:00:00.000Z</published>
    <summary>Python基础思想：变量引用、对象属性</summary>
    <title>Python修养1</title>
    <updated>2026-07-21T09:00:31.857Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <content>
      <![CDATA[<h1 id="c-特性"><a href="#c-特性" class="headerlink" title="c++特性"></a>c++特性</h1><blockquote><p>以下按常用频次排序。每个特性给出最精简的语法和示例。</p></blockquote><hr><h2 id="Lambda-表达式"><a href="#Lambda-表达式" class="headerlink" title="Lambda 表达式"></a>Lambda 表达式</h2><pre><code class="hljs cpp"><span class="hljs-comment">// [捕获](参数) -&gt; 返回类型 &#123; 函数体 &#125;</span><span class="hljs-keyword">auto</span> add = [](<span class="hljs-type">int</span> a, <span class="hljs-type">int</span> b) -&gt; <span class="hljs-type">int</span> &#123; <span class="hljs-keyword">return</span> a + b; &#125;;<span class="hljs-keyword">auto</span> f = [&amp;x, y](<span class="hljs-type">int</span> z) &#123; x += y + z; &#125;;  <span class="hljs-comment">// x引用捕获, y值捕获</span><span class="hljs-comment">// 捕获简写</span>[=]  &#123; <span class="hljs-comment">/* 全部值捕获 */</span> &#125;[&amp;]  &#123; <span class="hljs-comment">/* 全部引用捕获 */</span> &#125;[=, &amp;x] &#123; <span class="hljs-comment">/* x引用，其余值捕获 */</span> &#125;</code></pre><h2 id="auto-关键字"><a href="#auto-关键字" class="headerlink" title="auto 关键字"></a>auto 关键字</h2><pre><code class="hljs cpp"><span class="hljs-keyword">auto</span> i = <span class="hljs-number">42</span>;              <span class="hljs-comment">// int</span><span class="hljs-keyword">auto</span> s = string&#123;<span class="hljs-string">&quot;hi&quot;</span>&#125;;    <span class="hljs-comment">// string</span><span class="hljs-keyword">auto</span> it = v.<span class="hljs-built_in">begin</span>();      <span class="hljs-comment">// vector&lt;int&gt;::iterator</span><span class="hljs-comment">// 结合引用/const</span><span class="hljs-type">const</span> <span class="hljs-keyword">auto</span>&amp; ref = vec;    <span class="hljs-comment">// const 引用</span></code></pre><h2 id="空指针-nullptr"><a href="#空指针-nullptr" class="headerlink" title="空指针 nullptr"></a>空指针 nullptr</h2><pre><code class="hljs cpp"><span class="hljs-type">int</span>* p = <span class="hljs-literal">nullptr</span>;   <span class="hljs-comment">// 替代 NULL，类型安全</span><span class="hljs-comment">// 函数重载时：f(nullptr) 走 f(int*)，f(NULL) 可能走错</span></code></pre><h2 id="基于范围的-for-循环"><a href="#基于范围的-for-循环" class="headerlink" title="基于范围的 for 循环"></a>基于范围的 for 循环</h2><pre><code class="hljs cpp"><span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span>&amp; x : vec) &#123; x *= <span class="hljs-number">2</span>; &#125;          <span class="hljs-comment">// 修改用引用</span><span class="hljs-keyword">for</span> (<span class="hljs-type">const</span> <span class="hljs-keyword">auto</span>&amp; x : vec) &#123; cout &lt;&lt; x; &#125; <span class="hljs-comment">// 只读用 const 引用</span></code></pre><h2 id="统一初始化"><a href="#统一初始化" class="headerlink" title="{} 统一初始化"></a>{} 统一初始化</h2><pre><code class="hljs cpp"><span class="hljs-type">int</span> a&#123;<span class="hljs-number">5</span>&#125;;vector&lt;<span class="hljs-type">int</span>&gt; v&#123;<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>&#125;;<span class="hljs-keyword">struct</span> <span class="hljs-title class_">P</span> &#123; <span class="hljs-type">int</span> x, y; &#125;;P p&#123;<span class="hljs-number">1</span>, <span class="hljs-number">2</span>&#125;;           <span class="hljs-comment">// 聚合初始化</span></code></pre><h2 id="成员变量默认初始值"><a href="#成员变量默认初始值" class="headerlink" title="成员变量默认初始值"></a>成员变量默认初始值</h2><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123;  <span class="hljs-type">int</span> x = <span class="hljs-number">0</span>;      <span class="hljs-comment">// 直接给默认值</span>  string s&#123;<span class="hljs-string">&quot;hi&quot;</span>&#125;;&#125;;</code></pre><h2 id="右值引用和-move-语义"><a href="#右值引用和-move-语义" class="headerlink" title="右值引用和 move 语义"></a>右值引用和 move 语义</h2><pre><code class="hljs cpp"><span class="hljs-comment">// 左值：可取地址的；右值：字面量、临时对象、表达式结果</span><span class="hljs-type">int</span> a = <span class="hljs-number">5</span>;<span class="hljs-type">int</span>&amp; lref = a;         <span class="hljs-comment">// 左值引用</span><span class="hljs-type">int</span>&amp;&amp; rref = <span class="hljs-number">5</span>;        <span class="hljs-comment">// 右值引用</span><span class="hljs-comment">// move：将左值转为右值引用，触发移动语义</span>vector&lt;<span class="hljs-type">int</span>&gt; v2 = <span class="hljs-built_in">move</span>(v1);  <span class="hljs-comment">// v1 内容被移走，v1 变为空</span><span class="hljs-comment">// 移动构造函数（浅拷贝指针，移交所有权）</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">Buffer</span> &#123;  <span class="hljs-type">char</span>* data;<span class="hljs-keyword">public</span>:  <span class="hljs-built_in">Buffer</span>(Buffer&amp;&amp; other) <span class="hljs-keyword">noexcept</span>    : <span class="hljs-built_in">data</span>(other.data) &#123; other.data = <span class="hljs-literal">nullptr</span>; &#125;&#125;;</code></pre><h2 id="unique-ptr（独占智能指针）"><a href="#unique-ptr（独占智能指针）" class="headerlink" title="unique_ptr（独占智能指针）"></a>unique_ptr（独占智能指针）</h2><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;memory&gt;</span></span><span class="hljs-keyword">auto</span> p = <span class="hljs-built_in">make_unique</span>&lt;<span class="hljs-type">int</span>&gt;(<span class="hljs-number">42</span>);       <span class="hljs-comment">// 推荐写法</span><span class="hljs-keyword">auto</span> p2 = <span class="hljs-built_in">move</span>(p);                   <span class="hljs-comment">// 转移所有权，p 变 nullptr</span><span class="hljs-comment">// 离开作用域自动 delete，不可拷贝，不可容器传参（可 move）</span></code></pre><h2 id="shared-ptr（共享智能指针）"><a href="#shared-ptr（共享智能指针）" class="headerlink" title="shared_ptr（共享智能指针）"></a>shared_ptr（共享智能指针）</h2><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;memory&gt;</span></span><span class="hljs-keyword">auto</span> sp = <span class="hljs-built_in">make_shared</span>&lt;<span class="hljs-type">int</span>&gt;(<span class="hljs-number">42</span>);      <span class="hljs-comment">// 推荐写法</span><span class="hljs-keyword">auto</span> sp2 = sp;                        <span class="hljs-comment">// 引用计数</span><span class="hljs-comment">// 计数归零自动 delete。注意循环引用导致泄漏。</span></code></pre><blockquote><p><code>make_unique</code>&#x2F;<code>make_shared</code> 比 <code>new</code> 更安全（无裸 new，异常安全）。</p></blockquote><h2 id="decltype-关键字"><a href="#decltype-关键字" class="headerlink" title="decltype 关键字"></a>decltype 关键字</h2><pre><code class="hljs cpp"><span class="hljs-type">int</span> x = <span class="hljs-number">0</span>;<span class="hljs-keyword">decltype</span>(x) y = <span class="hljs-number">1</span>;           <span class="hljs-comment">// y 类型为 int</span><span class="hljs-keyword">decltype</span>((x)) z = x;         <span class="hljs-comment">// 双括号→int&amp;</span><span class="hljs-comment">// 主要用于泛型中推导返回类型</span></code></pre><h2 id="万能引用与-forward-转发"><a href="#万能引用与-forward-转发" class="headerlink" title="万能引用与 forward 转发"></a>万能引用与 forward 转发</h2><pre><code class="hljs cpp"><span class="hljs-comment">// T&amp;&amp; 在模板中为万能引用，可接受左/右值</span><span class="hljs-function"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">typename</span> T&gt;</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">wrapper</span><span class="hljs-params">(T&amp;&amp; arg)</span> </span>&#123;  <span class="hljs-built_in">foo</span>(forward&lt;T&gt;(arg));  <span class="hljs-comment">// 保持原值类别转发</span>&#125;</code></pre><hr><h2 id="C-14-补充"><a href="#C-14-补充" class="headerlink" title="C++14 补充"></a>C++14 补充</h2><table><thead><tr><th>特性</th><th>示例</th></tr></thead><tbody><tr><td>二进制常量</td><td><code>int b = 0b1010;</code></td></tr><tr><td>返回类型自动推导</td><td><code>auto f() { return 42; }</code></td></tr><tr><td>泛型 lambda</td><td><code>auto f = [](auto x) { return x * 2; };</code></td></tr><tr><td>make_unique</td><td>C++14 引入，用法见上</td></tr></tbody></table><hr><h2 id="C-17-补充"><a href="#C-17-补充" class="headerlink" title="C++17 补充"></a>C++17 补充</h2><table><thead><tr><th>特性</th><th>示例</th></tr></thead><tbody><tr><td>结构化绑定</td><td><code>auto [x, y] = make_pair(1, 2);</code></td></tr><tr><td>if 初始化</td><td><code>if (auto it = m.find(k); it != m.end()) { ... }</code></td></tr><tr><td>CTAD</td><td><code>vector v{1, 2, 3};</code> 自动推导为 <code>vector&lt;int&gt;</code></td></tr><tr><td><code>std::optional</code></td><td>可能无值的返回值，<code>if (opt.has_value())</code></td></tr></tbody></table>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/f9a7/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/f9a7/"/>
    <published>2026-04-16T16:00:00.000Z</published>
    <summary>C++11常用特性速查：Lambda、auto、智能指针</summary>
    <title>c++11特性</title>
    <updated>2026-07-21T09:04:27.283Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="STL" scheme="https://flowwalker.github.io/coding-notes-blog/tags/STL/"/>
    <content>
      <![CDATA[<h1 id="STL进阶"><a href="#STL进阶" class="headerlink" title="STL进阶"></a>STL进阶</h1><h2 id="关联容器"><a href="#关联容器" class="headerlink" title="关联容器"></a>关联容器</h2><ul><li>有序（默认 <code>&lt;</code> 排序）</li><li>插入位置取决于值，不可指定位置</li><li>查找 O(log n)（红黑树实现）</li><li>双向迭代器</li></ul><h3 id="共有成员函数"><a href="#共有成员函数" class="headerlink" title="共有成员函数"></a>共有成员函数</h3><table><thead><tr><th>函数</th><th>说明</th></tr></thead><tbody><tr><td><code>find(val)</code></td><td>查找，返回迭代器，失败返回 <code>end()</code></td></tr><tr><td><code>lower_bound(val)</code></td><td>第一个 ≥ val 的位置</td></tr><tr><td><code>upper_bound(val)</code></td><td>第一个 &gt; val 的位置</td></tr><tr><td><code>count(val)</code></td><td>统计等于 val 的元素数</td></tr><tr><td><code>insert(val)</code></td><td>插入</td></tr><tr><td><code>erase(iter)</code></td><td>删除</td></tr></tbody></table><blockquote><p><code>[lower_bound, upper_bound)</code> 恰好等于目标元素区间。</p></blockquote><h3 id="set-multiset"><a href="#set-multiset" class="headerlink" title="set &#x2F; multiset"></a>set &#x2F; multiset</h3><ul><li>头文件 <code>&lt;set&gt;</code></li><li><code>set</code>：元素唯一，不可重复</li><li><code>multiset</code>：允许重复</li></ul><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;set&gt;</span></span>set&lt;<span class="hljs-type">int</span>&gt; s;s.<span class="hljs-built_in">insert</span>(<span class="hljs-number">3</span>); s.<span class="hljs-built_in">insert</span>(<span class="hljs-number">1</span>); s.<span class="hljs-built_in">insert</span>(<span class="hljs-number">2</span>);  <span class="hljs-comment">// 自动排序: 1 2 3</span>s.<span class="hljs-built_in">erase</span>(<span class="hljs-number">2</span>);<span class="hljs-keyword">if</span> (s.<span class="hljs-built_in">find</span>(<span class="hljs-number">3</span>) != s.<span class="hljs-built_in">end</span>()) &#123; <span class="hljs-comment">/* 找到了 */</span> &#125;multiset&lt;<span class="hljs-type">int</span>&gt; ms;ms.<span class="hljs-built_in">insert</span>(<span class="hljs-number">1</span>); ms.<span class="hljs-built_in">insert</span>(<span class="hljs-number">1</span>);  <span class="hljs-comment">// 重复允许</span></code></pre><h3 id="map-multimap"><a href="#map-multimap" class="headerlink" title="map &#x2F; multimap"></a>map &#x2F; multimap</h3><ul><li>头文件 <code>&lt;map&gt;</code></li><li>存储 <code>pair&lt;const Key, Value&gt;</code></li><li><code>map</code>：key 唯一；<code>multimap</code>：允许重复 key</li><li><code>[]</code> 运算符：key 不存在时自动插入默认值</li></ul><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;map&gt;</span></span>map&lt;string, <span class="hljs-type">int</span>&gt; m;m[<span class="hljs-string">&quot;cpp&quot;</span>] = <span class="hljs-number">90</span>;            <span class="hljs-comment">// 若 &quot;cpp&quot; 不存在则插入</span>m.<span class="hljs-built_in">insert</span>(&#123;<span class="hljs-string">&quot;py&quot;</span>, <span class="hljs-number">85</span>&#125;);m.<span class="hljs-built_in">insert</span>(<span class="hljs-built_in">make_pair</span>(<span class="hljs-string">&quot;js&quot;</span>, <span class="hljs-number">80</span>));<span class="hljs-keyword">for</span> (<span class="hljs-keyword">auto</span>&amp; [k, v] : m) &#123; <span class="hljs-comment">/* 按 key 排序遍历 */</span> &#125;multimap&lt;string, <span class="hljs-type">int</span>&gt; mm;mm.<span class="hljs-built_in">insert</span>(&#123;<span class="hljs-string">&quot;a&quot;</span>, <span class="hljs-number">1</span>&#125;);mm.<span class="hljs-built_in">insert</span>(&#123;<span class="hljs-string">&quot;a&quot;</span>, <span class="hljs-number">2</span>&#125;);      <span class="hljs-comment">// key &quot;a&quot; 重复</span></code></pre><hr><h2 id="容器适配器"><a href="#容器适配器" class="headerlink" title="容器适配器"></a>容器适配器</h2><h3 id="stack"><a href="#stack" class="headerlink" title="stack"></a>stack</h3><ul><li>头文件 <code>&lt;stack&gt;</code>，默认底层 <code>deque</code></li><li><code>push</code> &#x2F; <code>pop</code> &#x2F; <code>top</code> &#x2F; <code>empty</code> &#x2F; <code>size</code></li><li>无迭代器，只能访问栈顶</li></ul><h3 id="queue"><a href="#queue" class="headerlink" title="queue"></a>queue</h3><ul><li>头文件 <code>&lt;queue&gt;</code>，默认底层 <code>deque</code></li><li><code>push</code> &#x2F; <code>pop</code> &#x2F; <code>front</code> &#x2F; <code>back</code> &#x2F; <code>empty</code> &#x2F; <code>size</code></li></ul><h3 id="priority-queue"><a href="#priority-queue" class="headerlink" title="priority_queue"></a>priority_queue</h3><ul><li>头文件 <code>&lt;queue&gt;</code>，默认底层 <code>vector</code></li><li>默认<strong>大根堆</strong>（最大元素在队首）</li><li>小根堆写法：<code>priority_queue&lt;int, vector&lt;int&gt;, greater&lt;int&gt;&gt; pq;</code></li><li><code>push</code> &#x2F; <code>pop</code> &#x2F; <code>top</code> &#x2F; <code>empty</code> &#x2F; <code>size</code></li></ul><pre><code class="hljs cpp">priority_queue&lt;<span class="hljs-type">int</span>&gt; pq;pq.<span class="hljs-built_in">push</span>(<span class="hljs-number">3</span>); pq.<span class="hljs-built_in">push</span>(<span class="hljs-number">1</span>); pq.<span class="hljs-built_in">push</span>(<span class="hljs-number">5</span>);pq.<span class="hljs-built_in">top</span>();  <span class="hljs-comment">// 5（最大）</span>pq.<span class="hljs-built_in">pop</span>();  <span class="hljs-comment">// 移除 5</span></code></pre><hr><h2 id="常用算法一览"><a href="#常用算法一览" class="headerlink" title="常用算法一览"></a>常用算法一览</h2><p>头文件 <code>&lt;algorithm&gt;</code>、<code>&lt;numeric&gt;</code></p><table><thead><tr><th>算法</th><th>说明</th></tr></thead><tbody><tr><td><code>sort(b, e)</code></td><td>排序，需随机迭代器</td></tr><tr><td><code>stable_sort(b, e)</code></td><td>稳定排序</td></tr><tr><td><code>find(b, e, val)</code></td><td>线性查找</td></tr><tr><td><code>binary_search(b, e, val)</code></td><td>二分查找（有序），需随机迭代器</td></tr><tr><td><code>lower_bound(b, e, val)</code></td><td>首个 ≥ val</td></tr><tr><td><code>count(b, e, val)</code></td><td>计数</td></tr><tr><td><code>reverse(b, e)</code></td><td>反转</td></tr><tr><td><code>max_element(b, e)</code></td><td>最大元素位置</td></tr><tr><td><code>next_permutation(b, e)</code></td><td>下一排列</td></tr><tr><td><code>accumulate(b, e, init)</code></td><td>累加（<code>&lt;numeric&gt;</code>）</td></tr></tbody></table>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/ad77/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/ad77/"/>
    <published>2026-04-07T16:00:00.000Z</published>
    <summary>关联容器与STL进阶用法</summary>
    <title>STL进阶</title>
    <updated>2026-07-21T09:00:13.415Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="STL" scheme="https://flowwalker.github.io/coding-notes-blog/tags/STL/"/>
    <content>
      <![CDATA[<h1 id="STL初步"><a href="#STL初步" class="headerlink" title="STL初步"></a>STL初步</h1><h2 id="泛型程序设计（generic-programming）"><a href="#泛型程序设计（generic-programming）" class="headerlink" title="泛型程序设计（generic programming）"></a>泛型程序设计（generic programming）</h2><h3 id="设计思想"><a href="#设计思想" class="headerlink" title="设计思想"></a>设计思想</h3><ul><li>C++语言的核心优势之一 —— <strong>软件的重用</strong></li><li>C++中有两个方面体现重用:<ol><li><strong>面向对象的思想</strong>：继承和多态，标准类库</li><li><strong>泛型程序设计的思想</strong>：<ul><li>模板机制</li><li>标准模板库 <strong>STL</strong></li></ul></li></ol></li></ul><h4 id="模板机制"><a href="#模板机制" class="headerlink" title="模板机制"></a>模板机制</h4><ul><li><p>将一些常用的<strong>数据结构</strong>（比如链表，数组，二叉树）和<strong>算法</strong>（比如排序，查找）写成模板</p></li><li><p>以后不论数据结构里放的是什么对象，算法针对什么样的对象<br>→ 都不必重新实现数据结构，重新编写算法</p></li></ul><h4 id="标准模板库（Standard-Template-Library）"><a href="#标准模板库（Standard-Template-Library）" class="headerlink" title="标准模板库（Standard Template Library）"></a>标准模板库（Standard Template Library）</h4><ul><li>常用数据结构和算法的模板的集合</li><li>无需写过多的标准数据结构和算法</li><li>同时可获得非常高的性能</li></ul><h2 id="STL的基本概念"><a href="#STL的基本概念" class="headerlink" title="STL的基本概念"></a>STL的基本概念</h2><ul><li><strong>容器</strong>：可容纳<strong>各种数据类型</strong>的通用<strong>数据结构</strong>，是类模板</li><li><strong>迭代器</strong>：可用于依次<strong>存取</strong>容器中元素，类似于指针<ul><li>普通的C++指针就是一种迭代器</li></ul></li><li><strong>算法</strong>：用来<strong>操作</strong>容器中的元素的<strong>函数模板</strong></li></ul><blockquote><ul><li><code>sort()</code> 来对一个数组中的数据进行排序</li><li><code>find()</code> 来搜索一个数组中的对象<br>算法本身与他们操作的数据的类型无关，<br>  因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用</li></ul><pre><code class="hljs cpp"><span class="hljs-type">int</span> array[<span class="hljs-number">100</span>];    <span class="hljs-comment">// 该数组就是容器，而int* 类型的指针变量就可以作为迭代器</span><span class="hljs-built_in">sort</span>(array, array<span class="hljs-number">+70</span>);  <span class="hljs-comment">// sort 算法可以作用于该容器上，对其进行排序</span></code></pre></blockquote><h3 id="迭代器"><a href="#迭代器" class="headerlink" title="迭代器"></a>迭代器</h3><ul><li><p>用于指向<strong>第一类容器</strong>的元素</p><ul><li>可以读取指向元素</li><li>非const迭代器可以修改指向元素</li></ul></li><li><p>使用方法：</p><pre><code class="hljs c++">/定义一个容器类的迭代器的方法：容器类名::iterator 变量名;容器类名::const_iterator 变量名;<span class="hljs-comment">//访问一个迭代器指向的元素：</span>* 迭代器变量名</code></pre></li><li><p>不同容器支持的迭代器功能<strong>强弱不同</strong>→决定支持的算法</p><ul><li><p>只有<strong>第一类容器</strong>可以使用迭代器<strong>遍历</strong></p></li><li><p>强弱</p><pre><code class="hljs mermaid">flowchart LR        direction LR        A[输入迭代器&lt;br&gt;只读访问&lt;br&gt;&lt;br&gt;++p, p++&lt;br&gt;value=*p, p=p1&lt;br&gt;p==p1, p!=p1] --&gt; B[输出迭代器&lt;br&gt;只写访问&lt;br&gt;*p=value, p=p1]        B --&gt; C[正向迭代器&lt;br&gt;读写 + 单向步进前进]        C --&gt; D[双向迭代器&lt;br&gt;读写 + 双向步进移动&lt;br&gt;&lt;br&gt;--p, p--]        D --&gt; E[随机访问迭代器&lt;br&gt;读写 + 随机跳转&lt;br&gt;&lt;br&gt;移动i个单元（+=i or -=i）&lt;br&gt;大小比较&lt;br&gt;取下标]</code></pre><blockquote><p>→表示包含前者功能</p></blockquote></li><li><p>容器对应的迭代器类别</p><blockquote><table><thead><tr><th align="left">容器</th><th align="left">迭代器类别</th></tr></thead><tbody><tr><td align="left">vector</td><td align="left">随机</td></tr><tr><td align="left">deque</td><td align="left">随机</td></tr><tr><td align="left">list</td><td align="left">双向</td></tr><tr><td align="left">set&#x2F;multiset</td><td align="left">双向</td></tr><tr><td align="left">map&#x2F;multimap</td><td align="left">双向</td></tr><tr><td align="left">stack</td><td align="left">不支持迭代器</td></tr><tr><td align="left">queue</td><td align="left">不支持迭代器</td></tr><tr><td align="left">priority_queue</td><td align="left">不支持迭代器</td></tr></tbody></table><blockquote><p><strong>备注</strong>：如图中提示，像 <code>sort</code>、<code>binary_search</code> 等算法要求<strong>随机访问迭代器</strong>，因此 <strong>list</strong> 以及 <strong>set&#x2F;multiset</strong>、<strong>map&#x2F;multimap</strong> 等关联容器无法直接使用这些算法，通常需要借助成员函数或手动实现。</p></blockquote><blockquote><p>⚠️书写应严格按照表格支持的类别，例如list<strong>不能使用</strong><code>it&lt;l.end()</code>和<code>it+=2</code>和<code>l[i]</code>语法</p></blockquote></blockquote></li></ul></li></ul><h3 id="容器"><a href="#容器" class="headerlink" title="容器"></a>容器</h3><h4 id="分类"><a href="#分类" class="headerlink" title="分类"></a>分类</h4><ul><li><p>顺序容器&#x2F;序列容器</p><p><code>vector</code>, <code>deque</code>, <code>list</code></p></li><li><p>关联容器&#x2F;有序容器</p><p><code>set</code>, <code>multiset</code>, <code>map</code> <code>multimap</code></p></li><li><p>容器适配器</p><p><code>stack</code>, <code>queue</code>, <code>priority_queue</code></p></li></ul><blockquote><p>其中前两类属于<strong>第一类容器</strong></p></blockquote><h4 id="容器概述"><a href="#容器概述" class="headerlink" title="容器概述"></a>容器概述</h4><ul><li>插入的是对象的一个复制品</li><li>往往需要重载 &#x3D;&#x3D; 和 &lt;  运算符以比较→进而实现查找、排序……</li></ul><h4 id="成员函数概述"><a href="#成员函数概述" class="headerlink" title="成员函数概述"></a>成员函数概述</h4><h5 id="共有成员函数"><a href="#共有成员函数" class="headerlink" title="共有成员函数"></a>共有成员函数</h5><ul><li>按照<strong>词典序</strong>比较两个容器的运算符<code>==</code>, <code>!=</code>, <code>&gt;</code>, <code>&lt;</code>, <code>&gt;=</code>, <code>&lt;=</code></li><li><code>empty</code> 判断是否为空</li><li><code>max_size</code> 容器最多能装元素个数（常上万）</li><li><code>size</code> 容器中元素个数</li><li><code>swap</code> 交换容器内容</li></ul><h5 id="第一类容器特有的成员函数"><a href="#第一类容器特有的成员函数" class="headerlink" title="第一类容器特有的成员函数"></a>第一类容器特有的成员函数</h5><table><thead><tr><th>函数</th><th>说明</th></tr></thead><tbody><tr><td><code>begin()</code> &#x2F; <code>end()</code></td><td>首&#x2F;尾后迭代器</td></tr><tr><td><code>rbegin()</code> &#x2F; <code>rend()</code></td><td>反向迭代器</td></tr><tr><td><code>erase(iter)</code></td><td>删除迭代器指向元素</td></tr><tr><td><code>erase(begin, end)</code></td><td>删除区间</td></tr><tr><td><code>clear()</code></td><td>清空</td></tr><tr><td><code>insert(iter, val)</code></td><td>在迭代器位置前插入</td></tr></tbody></table><h5 id="顺序容器特有成员函数"><a href="#顺序容器特有成员函数" class="headerlink" title="顺序容器特有成员函数"></a>顺序容器特有成员函数</h5><table><thead><tr><th>函数</th><th>说明</th></tr></thead><tbody><tr><td><code>push_back(val)</code></td><td>尾插</td></tr><tr><td><code>pop_back()</code></td><td>尾删</td></tr><tr><td><code>front()</code> &#x2F; <code>back()</code></td><td>首&#x2F;尾元素引用</td></tr><tr><td><code>resize(n)</code></td><td>调整大小</td></tr><tr><td><code>assign(n, val)</code></td><td>赋 n 个 val</td></tr></tbody></table><h4 id="详细介绍"><a href="#详细介绍" class="headerlink" title="详细介绍"></a>详细介绍</h4><h5 id="顺序容器"><a href="#顺序容器" class="headerlink" title="顺序容器"></a>顺序容器</h5><h6 id="vector"><a href="#vector" class="headerlink" title="vector"></a>vector</h6><ul><li>头文件<code>&lt;vector&gt;</code></li><li>动态数组，内存连续</li><li>随机存取→常数时间</li><li><strong>尾端</strong>增删性能佳，中间增删 O(n)</li><li>扩容时重新分配内存，原迭代器失效</li></ul><pre><code class="hljs cpp">vector&lt;<span class="hljs-type">int</span>&gt; v;v.<span class="hljs-built_in">push_back</span>(<span class="hljs-number">1</span>);               <span class="hljs-comment">// 尾插</span>v.<span class="hljs-built_in">pop_back</span>();                 <span class="hljs-comment">// 尾删</span>v.<span class="hljs-built_in">insert</span>(v.<span class="hljs-built_in">begin</span>()+i, val);   <span class="hljs-comment">// 位置 i 前插入</span>v.<span class="hljs-built_in">erase</span>(v.<span class="hljs-built_in">begin</span>()+i);         <span class="hljs-comment">// 删除位置 i</span><span class="hljs-built_in">sort</span>(v.<span class="hljs-built_in">begin</span>(), v.<span class="hljs-built_in">end</span>());     <span class="hljs-comment">// 排序（随机迭代器）</span></code></pre><h6 id="deque"><a href="#deque" class="headerlink" title="deque"></a>deque</h6><ul><li>头文件<code>&lt;deque&gt;</code></li><li>双向队列，<strong>首尾</strong>增删 O(1)</li><li>支持 <code>[]</code> 下标、随机迭代器</li><li>内存分段，<code>sort</code> 效率略低于 <code>vector</code></li></ul><pre><code class="hljs cpp">deque&lt;<span class="hljs-type">int</span>&gt; dq;dq.<span class="hljs-built_in">push_back</span>(<span class="hljs-number">1</span>);  dq.<span class="hljs-built_in">push_front</span>(<span class="hljs-number">2</span>);dq.<span class="hljs-built_in">pop_back</span>();    dq.<span class="hljs-built_in">pop_front</span>();</code></pre><h6 id="list"><a href="#list" class="headerlink" title="list"></a>list</h6><ul><li>头文件<code>&lt;list&gt;</code></li><li>双向链表，<strong>任意位置</strong>增删 O(1)</li><li>仅双向迭代器：<strong>不支持</strong> <code>[]</code>、<code>it+=n</code>、<code>it&lt;end</code></li><li>自带 <code>sort()</code>、<code>reverse()</code>、<code>merge()</code>、<code>remove(val)</code> 成员函数</li></ul><pre><code class="hljs cpp">list&lt;<span class="hljs-type">int</span>&gt; lst;lst.<span class="hljs-built_in">push_back</span>(<span class="hljs-number">1</span>);   lst.<span class="hljs-built_in">push_front</span>(<span class="hljs-number">0</span>);lst.<span class="hljs-built_in">insert</span>(it, val);   <span class="hljs-comment">// it 前插入</span>lst.<span class="hljs-built_in">erase</span>(it);          <span class="hljs-comment">// 删除 it</span>lst.<span class="hljs-built_in">sort</span>();             <span class="hljs-comment">// 成员 sort（非全局 sort）</span></code></pre><blockquote><p>频繁中间增删用 list；需随机访问用 vector。</p></blockquote>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/62e5/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/62e5/"/>
    <published>2026-04-03T16:00:00.000Z</published>
    <summary>STL泛型编程与标准模板库入门</summary>
    <title>STL初步</title>
    <updated>2026-07-21T09:00:12.135Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="string" scheme="https://flowwalker.github.io/coding-notes-blog/tags/string/"/>
    <content>
      <![CDATA[<h1 id="String库"><a href="#String库" class="headerlink" title="String库"></a>String库</h1><blockquote><ul><li><code>s.find(&#39;a&#39;)</code> 返回的是<strong>位置下标</strong>（<code>std::string::size_type</code>，无符号整数），而 <code>std::find(s.begin(), s.end(), &#39;a&#39;)</code> 返回的是<strong>迭代器</strong>。整数和迭代器类型不匹配，<strong>不能用 <code>==</code> 比较</strong>。</li><li></li></ul></blockquote><h2 id="思维导图"><a href="#思维导图" class="headerlink" title="思维导图"></a>思维导图</h2><h3 id="简略版"><a href="#简略版" class="headerlink" title="简略版"></a>简略版</h3><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/20260404232417609.png"></p><h3 id="详细版"><a href="#详细版" class="headerlink" title="详细版"></a>详细版</h3><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/21aca11046d859a79cf3b2bebb308dfb.jpg" alt="21aca11046d859a79cf3b2bebb308dfb"></p><h2 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h2><ul><li><p>string类要包含头文件 <strong>#include <string></strong></p></li><li><p><strong>string</strong>类<strong>是一个模板类</strong>定义如下：</p><p><code>typedef basic_string&lt;char&gt; string;</code></p></li></ul><h3 id="初始化-赋值："><a href="#初始化-赋值：" class="headerlink" title="初始化&amp;赋值："></a>初始化&amp;赋值：</h3><ol><li><p>构造初始化：string s1(“Hello”); string s2(8,’x’); string s3&#x3D;”March”; string s4;</p></li><li><p>assign(s)：全串赋值</p></li><li><p>assign(s,pos,n)：从s的pos位置取n个字符赋值</p></li><li><p>单字符赋值：s&#x3D;’a’</p></li></ol><p>正确例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s1</span><span class="hljs-params">(<span class="hljs-string">&quot;Hello&quot;</span>)</span>,<span class="hljs-title">s2</span><span class="hljs-params">(<span class="hljs-number">8</span>,<span class="hljs-string">&#x27;x&#x27;</span>)</span>,s3</span>;s<span class="hljs-number">3.</span><span class="hljs-built_in">assign</span>(s1);s<span class="hljs-number">3.</span><span class="hljs-built_in">assign</span>(s1,<span class="hljs-number">1</span>,<span class="hljs-number">3</span>);string s;s=<span class="hljs-string">&#x27;n&#x27;</span>;</code></pre><p>错误例子：</p><pre><code class="hljs c++">string error1=<span class="hljs-string">&#x27;c&#x27;</span>;<span class="hljs-function">string <span class="hljs-title">error2</span><span class="hljs-params">(<span class="hljs-string">&#x27;u&#x27;</span>)</span></span>;string error3=<span class="hljs-number">22</span>;<span class="hljs-function">string <span class="hljs-title">error4</span><span class="hljs-params">(<span class="hljs-number">8</span>)</span></span>;</code></pre><h3 id="属性"><a href="#属性" class="headerlink" title="属性"></a>属性</h3><p>length()：获取长度<br>size()：等价length()<br>empty()：判断是否为空<br>capacity()：获取当前容量<br>max_size()：获取最大可容纳字符数<br>resize(n)：重置长度为n<br>resize(n,ch)：重置长度为n，填充字符ch<br>例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s</span><span class="hljs-params">(<span class="hljs-string">&quot;hello&quot;</span>)</span></span>;cout&lt;&lt;s.<span class="hljs-built_in">length</span>()&lt;&lt;s.<span class="hljs-built_in">size</span>()&lt;&lt;s.<span class="hljs-built_in">empty</span>()&lt;&lt;s.<span class="hljs-built_in">capacity</span>()&lt;&lt;s.<span class="hljs-built_in">max_size</span>();s.<span class="hljs-built_in">resize</span>(<span class="hljs-number">10</span>);s.<span class="hljs-built_in">resize</span>(<span class="hljs-number">15</span>,<span class="hljs-string">&#x27;a&#x27;</span>);</code></pre><h3 id="访问："><a href="#访问：" class="headerlink" title="访问："></a>访问：</h3><ol><li>s[pos]：下标访问，无越界检查</li><li>at(pos)：成员函数访问，越界抛异常<br>例子：</li></ol><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s</span><span class="hljs-params">(<span class="hljs-string">&quot;Hello&quot;</span>)</span></span>;<span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i&lt;s.<span class="hljs-built_in">length</span>();i++)cout&lt;&lt;s[i]&lt;&lt;s.<span class="hljs-built_in">at</span>(i);</code></pre><h3 id="连接："><a href="#连接：" class="headerlink" title="连接："></a>连接：</h3><ol><li>+&#x3D;：字符串拼接</li><li>append(s)：拼接s</li><li>append(s,pos,n)：拼接s从pos开始的n个字符<br>例子：</li></ol><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s1</span><span class="hljs-params">(<span class="hljs-string">&quot;good &quot;</span>)</span>,<span class="hljs-title">s2</span><span class="hljs-params">(<span class="hljs-string">&quot;morning!&quot;</span>)</span></span>;s1+=s2;s<span class="hljs-number">1.</span><span class="hljs-built_in">append</span>(s2);s<span class="hljs-number">2.</span><span class="hljs-built_in">append</span>(s1,<span class="hljs-number">3</span>,s<span class="hljs-number">1.</span><span class="hljs-built_in">size</span>());</code></pre><h3 id="比较："><a href="#比较：" class="headerlink" title="比较："></a>比较：</h3><ol><li>运算符：&#x3D;&#x3D;、!&#x3D;、&lt;、&lt;&#x3D;、&gt;、&gt;&#x3D;</li><li>compare(s)：与s比较</li><li>compare(pos,n,s)：从本串pos取n个与s比较</li><li>compare(pos1,n1,s,pos2,n2)：本串pos1取n1，s串pos2取n2比较<br>例子：</li></ol><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s1</span><span class="hljs-params">(<span class="hljs-string">&quot;hello&quot;</span>)</span>,<span class="hljs-title">s2</span><span class="hljs-params">(<span class="hljs-string">&quot;hello&quot;</span>)</span>,<span class="hljs-title">s3</span><span class="hljs-params">(<span class="hljs-string">&quot;hell&quot;</span>)</span></span>;<span class="hljs-type">bool</span> b=(s1==s2);<span class="hljs-type">int</span> f=s<span class="hljs-number">1.</span><span class="hljs-built_in">compare</span>(s3);</code></pre><h3 id="子串："><a href="#子串：" class="headerlink" title="子串："></a>子串：</h3><p>substr(pos&#x3D;0,n&#x3D;npos)：从pos开始取n个字符，n省略则取到末尾<br>例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s1</span><span class="hljs-params">(<span class="hljs-string">&quot;hello world&quot;</span>)</span>,s2</span>;s2=s<span class="hljs-number">1.</span><span class="hljs-built_in">substr</span>(<span class="hljs-number">4</span>,<span class="hljs-number">5</span>);s2=s<span class="hljs-number">1.</span><span class="hljs-built_in">substr</span>(<span class="hljs-number">4</span>);</code></pre><h3 id="交换："><a href="#交换：" class="headerlink" title="交换："></a>交换：</h3><p>swap(s)：交换两个string内容<br>例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s1</span><span class="hljs-params">(<span class="hljs-string">&quot;hello&quot;</span>)</span>,<span class="hljs-title">s2</span><span class="hljs-params">(<span class="hljs-string">&quot;world&quot;</span>)</span></span>;s<span class="hljs-number">1.</span><span class="hljs-built_in">swap</span>(s2);</code></pre><h3 id="查找："><a href="#查找：" class="headerlink" title="查找："></a>查找：</h3><p>find(str,pos&#x3D;0)：从pos开始从前查找str<br>rfind(str,pos&#x3D;npos)：从pos开始从后查找str<br>find_first_of(str,pos&#x3D;0)：查找str中任意字符首次出现<br>find_last_of(str,pos&#x3D;npos)：查找str中任意字符末次出现<br>find_first_not_of(str,pos&#x3D;0)：查找非str中字符首次出现<br>find_last_not_of(str,pos&#x3D;npos)：查找非str中字符末次出现<br>例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s</span><span class="hljs-params">(<span class="hljs-string">&quot;hello worlld&quot;</span>)</span></span>;cout&lt;&lt;s.<span class="hljs-built_in">find</span>(<span class="hljs-string">&quot;ll&quot;</span>)&lt;&lt;s.<span class="hljs-built_in">rfind</span>(<span class="hljs-string">&quot;ll&quot;</span>)&lt;&lt;s.<span class="hljs-built_in">find_first_of</span>(<span class="hljs-string">&quot;abcd&quot;</span>);</code></pre><h3 id="删除："><a href="#删除：" class="headerlink" title="删除："></a>删除：</h3><p>erase(pos&#x3D;0,n&#x3D;npos)：从pos删除n个字符，省略则删至末尾<br>例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s</span><span class="hljs-params">(<span class="hljs-string">&quot;hello world&quot;</span>)</span></span>;s.<span class="hljs-built_in">erase</span>(<span class="hljs-number">5</span>);s.<span class="hljs-built_in">erase</span>(<span class="hljs-number">2</span>,<span class="hljs-number">3</span>);</code></pre><h3 id="替换："><a href="#替换：" class="headerlink" title="替换："></a>替换：</h3><p>replace(pos,n,str)：从pos替换n个字符为str<br>例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s</span><span class="hljs-params">(<span class="hljs-string">&quot;hello world&quot;</span>)</span></span>;s.<span class="hljs-built_in">replace</span>(<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-string">&quot;haha&quot;</span>);</code></pre><h3 id="插入："><a href="#插入：" class="headerlink" title="插入："></a>插入：</h3><p>insert(pos,str)：pos位置插入str<br>insert(pos,str,subpos,sublen)：pos插入str从subpos开始的sublen个字符<br>例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s1</span><span class="hljs-params">(<span class="hljs-string">&quot;hello world&quot;</span>)</span>,<span class="hljs-title">s2</span><span class="hljs-params">(<span class="hljs-string">&quot;show&quot;</span>)</span></span>;s<span class="hljs-number">1.</span><span class="hljs-built_in">insert</span>(<span class="hljs-number">5</span>,s2);s<span class="hljs-number">1.</span><span class="hljs-built_in">insert</span>(<span class="hljs-number">2</span>,s2,<span class="hljs-number">1</span>,<span class="hljs-number">2</span>);</code></pre><h3 id="类型转换："><a href="#类型转换：" class="headerlink" title="类型转换："></a>类型转换：</h3><p>c_str()：转为const char*，末尾带’\0’<br>copy(buf,len,pos&#x3D;0)：从pos复制len个字符到buf<br>例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">s</span><span class="hljs-params">(<span class="hljs-string">&quot;hello&quot;</span>)</span></span>;<span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%s&quot;</span>,s.<span class="hljs-built_in">c_str</span>());<span class="hljs-type">char</span> p[<span class="hljs-number">6</span>];s.<span class="hljs-built_in">copy</span>(p,<span class="hljs-number">5</span>,<span class="hljs-number">0</span>);p[<span class="hljs-number">5</span>]=<span class="hljs-string">&#x27;\0&#x27;</span>;</code></pre><h3 id="输入输出："><a href="#输入输出：" class="headerlink" title="输入输出："></a>输入输出：</h3><p>cin&gt;&gt;s：流读取，遇空格停止<br>getline(cin,s)：读取整行，包含空格<br>例子：</p><pre><code class="hljs c++">string s;cin&gt;&gt;s;<span class="hljs-built_in">getline</span>(cin,s);</code></pre><h3 id="字符串流："><a href="#字符串流：" class="headerlink" title="字符串流："></a>字符串流：</h3><p>istringstream：字符串输入流<br>ostringstream：字符串输出流<br>例子：</p><pre><code class="hljs c++"><span class="hljs-function">string <span class="hljs-title">input</span><span class="hljs-params">(<span class="hljs-string">&quot;test 123&quot;</span>)</span></span>;<span class="hljs-function">istringstream <span class="hljs-title">in</span><span class="hljs-params">(input)</span></span>;ostringstream out;out&lt;&lt;input;</code></pre>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/9cf8/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/9cf8/"/>
    <published>2026-04-03T16:00:00.000Z</published>
    <summary>C++ string类用法速查与思维导图</summary>
    <title>string库</title>
    <updated>2026-07-21T09:01:06.722Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="类函数与函数模板" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%B1%BB%E5%87%BD%E6%95%B0%E4%B8%8E%E5%87%BD%E6%95%B0%E6%A8%A1%E6%9D%BF/"/>
    <content>
      <![CDATA[<h1 id="类函数与函数模板"><a href="#类函数与函数模板" class="headerlink" title="类函数与函数模板"></a>类函数与函数模板</h1><blockquote><p>完全匹配的普通函数 &gt; 完全匹配的模板函数 &gt; 需要转换的普通函数 &gt; 需要转换的模板函数</p></blockquote><h2 id="泛型程序设计-Generic-Programming"><a href="#泛型程序设计-Generic-Programming" class="headerlink" title="泛型程序设计(Generic Programming)"></a>泛型程序设计(Generic Programming)</h2><blockquote><p>算法实现时不指定具体要操作的数据的类型</p><ul><li><p><strong>泛型</strong>: 算法实现一遍 → 适用于多种数据结构→减少重复代码的编写</p></li><li><p>大量编写模板, 使用模板的程序设计</p><ul><li><p><strong>函数</strong>模板</p></li><li><p><strong>类</strong>模板</p></li></ul></li></ul></blockquote><h2 id="函数模板"><a href="#函数模板" class="headerlink" title="函数模板"></a>函数模板</h2><blockquote><p>问题根源：排序或者更广地说，算法完全相同，但被排序数组元素的变量的<strong>类型声明不同</strong></p><p><strong>两种可能的解法</strong></p><p><strong>函数重载</strong></p><ul><li>同名函数</li><li>编译系统根据参数调用时实参类型，确定实际执行的函数</li></ul><blockquote><p>问题在于：要是类有无数，要重载无数</p></blockquote><p><strong>函数模板</strong></p><pre><code class="hljs c++"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;</code></pre><p><strong>由编译系统根据sort函数调用时实参的类型，自动生成相应的模板函数</strong></p></blockquote><h3 id="范式"><a href="#范式" class="headerlink" title="范式"></a>范式</h3><h4 id="单类型参数"><a href="#单类型参数" class="headerlink" title="单类型参数"></a>单类型参数</h4><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">class</span> T&gt;</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-type">const</span> T array[],<span class="hljs-type">int</span> size)</span></span>&#123; <span class="hljs-comment">//此处T为函数模板的类型参数</span>    <span class="hljs-type">int</span> i;    <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i&lt;size;i++) cout&lt;&lt;array[i];    <span class="hljs-keyword">return</span>;&#125;<span class="hljs-comment">// 要能编译通过当然要有对&lt;&lt;的适当重载</span></code></pre><h4 id="多个类型参数"><a href="#多个类型参数" class="headerlink" title="多个类型参数"></a>多个类型参数</h4><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">class</span> T1,<span class="hljs-keyword">class</span> T2&gt;</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(T1 arg1,T2 arg2)</span></span>&#123;    cout&lt;&lt;arg1&lt;&lt;<span class="hljs-string">&quot; &quot;</span>&lt;&lt;arg2&lt;&lt;endl;    <span class="hljs-keyword">return</span>;&#125;</code></pre><blockquote><p>函数模板的<strong>参数类型</strong>可以是</p><ul><li>类型参数</li><li>基本数据类型，例如<code>...void print(T1 arg1,T2 arg2,string s){...}</code></li></ul></blockquote><blockquote><p>类型参数可以用于函数模板的<strong>局部变量声明</strong>（就是在函数模板里调用类型参数）,也可以用来<strong>作为返回值</strong></p></blockquote><blockquote><p>二义性：</p><ul><li><p>对于<code>Function(T arg1,T arg2)</code>，<code>Function(1,1.0)</code>——<code>error:replace T with int or double?</code></p></li><li><p>采用<code>Function(T1 arg1,T2 arg2)</code>避免二义性</p></li><li><p>⚠️显式指定**避免二义性</p></li><li><p>(⚠️如果可以自动匹配可以不指定)</p></li><li><pre><code class="language-c++">int c=10;func(c); //自动匹配func&lt;double&gt;(c);  //注意：此处会发生隐式转换func&lt;int&gt;(1,1.0); //ok，统一转化为int<pre><code class="hljs cpp">  - ⚠️函数模板可以重载（同一个函数名，**参数数量不同**）- ⚠️：函数与模板匹配的顺序：  - 先找参数**完全**匹配的**函数**  - 再找参数**完全**匹配的**模板**  - 函数无二义性前提下，找可**转换后匹配**的**函数**（⚠️函数）    ```c++    <span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span>    <span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;                    <span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Max</span><span class="hljs-params">( T a, T b )</span> </span>&#123;        cout &lt;&lt; <span class="hljs-string">&quot;TemplateMax&quot;</span> &lt;&lt;endl;        <span class="hljs-keyword">return</span>;    &#125;                    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Max</span><span class="hljs-params">(<span class="hljs-type">double</span> a, <span class="hljs-type">double</span> b)</span></span>&#123;        cout &lt;&lt; <span class="hljs-string">&quot;MyMax&quot;</span> &lt;&lt; endl;        <span class="hljs-keyword">return</span>;    &#125;                    <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;        <span class="hljs-type">int</span> i=<span class="hljs-number">4</span>, j=<span class="hljs-number">5</span>;        <span class="hljs-built_in">Max</span>(<span class="hljs-number">1.2</span>, <span class="hljs-number">3.4</span>);      <span class="hljs-comment">//输出MyMax</span>        <span class="hljs-built_in">Max</span>(i, j);          <span class="hljs-comment">//输出TemplateMax</span>        <span class="hljs-built_in">Max</span>(<span class="hljs-number">1.2</span>, <span class="hljs-number">3</span>);        <span class="hljs-comment">//模板有二义性，强制类型转换3为double，调用Max函数</span>        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;    &#125;</code></pre></code></pre></li></ul></blockquote><h5 id="相关延伸"><a href="#相关延伸" class="headerlink" title="相关延伸"></a>相关延伸</h5><p><strong>数组或者函数名作为值传入：</strong></p><ul><li><p>数组退化：退化为指向数组首元素的指针，<code>Type[N]</code>退化为<code>Type*</code> </p></li><li><p>函数退化：退化为指向函数的指针，<code>Ret(Args)</code>退化为<code>Ret(*)(Args)</code></p><blockquote><ul><li><p>函数指针<code>Ret(*)(Args)</code></p></li><li><p>函数类型<code>Ret(Args)</code>，实际传递通常退化</p></li><li><p>举个例子 void foo(int)变成指针 void(*)(int), 具体写的指针是void(*p)(int),⬅️这个可以写在函数参数表里</p></li><li><blockquote><p>一个细节:</p><p>auto p1 &#x3D; foo;      &#x2F;&#x2F; 函数到指针转换，p1 是 void (<em>)(int)<br>auto p2 &#x3D; &foo;     &#x2F;&#x2F; 显式取地址，结果也是 void (</em>)(int)</p></blockquote></li><li><pre><code class="language-cpp">//推导函数不隐式转化为指针decltype(foo) x;                // ✅ x 的类型是 void(int)，不是指针<pre><code class="hljs angelscript"> **实例化：** 即：函数模版的类型参数**实际转化**为**什么参数类型**```c++#include &lt;iostream&gt;#include &lt;typeinfo&gt;<span class="hljs-comment">/**</span><span class="hljs-comment">* * 1. 数组退化 (Array Decay): </span><span class="hljs-comment">* 当数组名作为值传递给模板时，T[N] 会退化为 T*。</span><span class="hljs-comment">* * 2. 函数退化 (Function Decay): </span><span class="hljs-comment">* 当函数名作为值传递给模板时，void(int) 会退化为函数指针 void(*)(int)。</span><span class="hljs-comment">* * 3. 模板匹配规则:</span><span class="hljs-comment">* - 若形参是 T*，而实参是 int*，则 T 推导为 int。</span><span class="hljs-comment">* - 若形参是 T，而实参是 int*，则 T 推导为 int*。</span><span class="hljs-comment">*/</span>template &lt;<span class="hljs-keyword">class</span> <span class="hljs-symbol">T1, <span class="hljs-symbol">class</span></span> <span class="hljs-symbol">T2, <span class="hljs-symbol">class</span></span> <span class="hljs-symbol">T3</span>&gt;<span class="hljs-symbol">T1</span> <span class="hljs-symbol">func</span>(<span class="hljs-symbol">T1</span> * <span class="hljs-symbol">a, <span class="hljs-symbol">T2</span></span> <span class="hljs-symbol">b, <span class="hljs-symbol">T3</span></span> <span class="hljs-symbol">c</span>) &#123;   <span class="hljs-comment">// 我们可以利用 C++ 内部机制打印推导出的类型名（取决于编译器输出）</span>   <span class="hljs-comment">// std::cout &lt;&lt; typeid(T1).name() &lt;&lt; std::endl; </span>   <span class="hljs-keyword">return</span> T1(); &#125;<span class="hljs-comment">// 全局变量与函数声明</span><span class="hljs-built_in">int</span> a[<span class="hljs-number">10</span>];       <span class="hljs-comment">// 类型：int [10]</span><span class="hljs-built_in">int</span> b[<span class="hljs-number">10</span>];       <span class="hljs-comment">// 类型：int [10]</span><span class="hljs-built_in">void</span> f(<span class="hljs-built_in">int</span> n) &#123;&#125; <span class="hljs-comment">// 类型：void(int)</span><span class="hljs-built_in">int</span> main() &#123;   <span class="hljs-comment">/* * 调用过程：func(a, b, f);</span><span class="hljs-comment">    * * 参数 [1]: T1 * a  &lt;-- 传入实参 a (int [10])</span><span class="hljs-comment">    * --------------------------------------------------</span><span class="hljs-comment">    * 逻辑：数组名 a 在这里退化为指向首元素的指针 int*。</span><span class="hljs-comment">    * 匹配：T1* = int* =&gt;  T1 被实例化为 【int】。</span><span class="hljs-comment">    * * 参数 [2]: T2 b    &lt;-- 传入实参 b (int [10])</span><span class="hljs-comment">    * --------------------------------------------------</span><span class="hljs-comment">    * 逻辑：数组名 b 同样退化为 int*。</span><span class="hljs-comment">    * 匹配：T2 直接接收这个指针  =&gt;  T2 被实例化为 【int *】。</span><span class="hljs-comment">    * * 参数 [3]: T3 c    &lt;-- 传入实参 f (函数名)</span><span class="hljs-comment">    * --------------------------------------------------</span><span class="hljs-comment">    * 逻辑：函数名 f 在非引用传递时，自动退化为函数指针类型。</span><span class="hljs-comment">    * 匹配：void(int) 变为 void(*)(int)。</span><span class="hljs-comment">    * 结果：T3 被实例化为 【void(*)(int)】。</span><span class="hljs-comment">    */</span>   func(a, b, f);   <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;<span class="hljs-comment">// T1: int,    T2: int *,    T3: void(*)(int)  </span></code></pre></code></pre></li></ul></blockquote></li></ul><blockquote><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">foo</span><span class="hljs-params">(<span class="hljs-type">int</span> a, <span class="hljs-type">int</span> b)</span> </span>&#123; &#125;<span class="hljs-built_in">void</span> (*p)(<span class="hljs-type">int</span>, <span class="hljs-type">int</span>) = foo;<span class="hljs-built_in">foo</span>(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);      <span class="hljs-comment">// 直接调用</span><span class="hljs-built_in">p</span>(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);        <span class="hljs-comment">// 函数指针直接调用，编译器自动解引用</span>(*p)(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);     <span class="hljs-comment">// 显式解引用后调用</span>(****p)(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);  <span class="hljs-comment">// 甚至这样也行，多层解引用编译器自动归一化</span></code></pre></blockquote><h2 id="类模板"><a href="#类模板" class="headerlink" title="类模板"></a>类模板</h2><blockquote><p>目的：快速地定义出一批<strong>相似的类</strong>，例如<strong>数组类</strong>（包元素、基本操作）</p><p>特点：除了<strong>元素类型</strong>之外，其他完全相同</p></blockquote><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><ul><li><p>在定义类的时候给它一个&#x2F;多个参数, 这个&#x2F;些参数表示不同的数据类型</p></li><li><p>在调用类模板时, 指定参数, <strong>由编译系统根据</strong>参数提供的数据类型<strong>自动产生</strong>相应的<strong>模板类</strong>（类模板+指定具体数据类型）</p></li></ul><h3 id="范式-1"><a href="#范式-1" class="headerlink" title="范式"></a>范式</h3><pre><code class="hljs c++"><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt; <span class="hljs-comment">//关键就这一行，类模板的首部, 声明类模板的参数</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">CArray</span>&#123;T *ptrElement;<span class="hljs-type">int</span> size;<span class="hljs-keyword">public</span>:<span class="hljs-built_in">CArray</span>(<span class="hljs-type">int</span> length);~<span class="hljs-built_in">CArray</span>();<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">len</span><span class="hljs-params">()</span></span>;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">setElement</span><span class="hljs-params">(T arg, <span class="hljs-type">int</span> index)</span></span>;<span class="hljs-function">T <span class="hljs-title">getElement</span><span class="hljs-params">(<span class="hljs-type">int</span> index)</span></span>;&#125;;</code></pre><p>More detail:</p><pre><code class="hljs c++"><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T1</span>, <span class="hljs-keyword">class</span> <span class="hljs-title class_">T2</span>&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Pair</span> &#123;<span class="hljs-keyword">public</span>:    T1 key;    <span class="hljs-comment">//关键字</span>    T2 value;  <span class="hljs-comment">//值</span>    <span class="hljs-built_in">Pair</span>(T1 k, T2 v):<span class="hljs-built_in">key</span>(k), <span class="hljs-built_in">value</span>(v) &#123; &#125;    <span class="hljs-type">bool</span> <span class="hljs-keyword">operator</span> &lt; ( <span class="hljs-type">const</span> Pair&lt;T1, T2&gt; &amp; p) <span class="hljs-type">const</span>;&#125;;<span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T1</span>, <span class="hljs-keyword">class</span> <span class="hljs-title class_">T2</span>&gt;<span class="hljs-type">bool</span> Pair&lt;T1, T2&gt;::<span class="hljs-keyword">operator</span> &lt; ( <span class="hljs-type">const</span> Pair&lt;T1, T2&gt; &amp; p) <span class="hljs-type">const</span><span class="hljs-comment">//Pair的成员函数 operator &lt;</span>&#123;    <span class="hljs-keyword">return</span> key &lt; p.key;    &#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    <span class="hljs-function">Pair&lt;string, <span class="hljs-type">int</span>&gt; <span class="hljs-title">student</span><span class="hljs-params">(<span class="hljs-string">&quot;Tom&quot;</span>, <span class="hljs-number">19</span>)</span></span>; <span class="hljs-comment">//实例化出一个类</span>    cout &lt;&lt; student.key &lt;&lt; <span class="hljs-string">&quot; &quot;</span> &lt;&lt; student.value;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;<span class="hljs-comment">// 输出：Tom 19</span></code></pre><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260404161620247.png" alt="image-20260404161620247"></p><h3 id="模板类"><a href="#模板类" class="headerlink" title="模板类"></a>模板类</h3><h4 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h4><p>类模板A+<strong>指定具体类型数据1</strong>→模板类A1→生成该模板类的对象或指针</p><p>类模板A+<strong>指定具体类型数据2</strong>→模板类A2</p><p>…</p><p>类模板A+<strong>指定具体类型数据n</strong>→模板类An</p><p>类模板B+<strong>指定具体类型数据1</strong>→模板类B1</p><p>…</p><blockquote><p>数据类型<strong>可以是类</strong></p><p>同一个<strong>类模板</strong>的两个<strong>模板类</strong>是<strong>不兼容</strong>的（类名字相同,但是类型参数显然不同）（不能赋值、不能传指针&#x2F;引用）</p></blockquote><h5 id="定义类模板的成员函数"><a href="#定义类模板的成员函数" class="headerlink" title="定义类模板的成员函数"></a>定义类模板的成员函数</h5><blockquote><p>小注:</p><ul><li><code>arg</code>→arguement 参数</li><li><code>argc</code>→argument count 参数数量</li><li><code>argv</code>→argument vector 参数数组</li></ul></blockquote><h6 id="数组类模板实例"><a href="#数组类模板实例" class="headerlink" title="数组类模板实例"></a>数组类模板实例</h6><p><strong>类模板声明</strong> </p><pre><code class="hljs cpp"><span class="hljs-comment">//类模板的首部，声明类模板的参数</span><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CArray</span>&#123;    T *ptrElement;    <span class="hljs-type">int</span> size;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">CArray</span>(<span class="hljs-type">int</span> length);    ~<span class="hljs-built_in">CArray</span>();    <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">len</span><span class="hljs-params">()</span></span>;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">setElement</span><span class="hljs-params">(T arg, <span class="hljs-type">int</span> index)</span></span>;    <span class="hljs-function">T <span class="hljs-title">getElement</span><span class="hljs-params">(<span class="hljs-type">int</span> index)</span></span>;&#125;;</code></pre><hr><p><strong>构造函数与析构函数实现</strong></p><pre><code class="hljs cpp"><span class="hljs-comment">//模板类CArray&lt;T&gt;的构造函数</span><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;CArray&lt;T&gt;:: <span class="hljs-built_in">CArray</span>(<span class="hljs-type">int</span> length) &#123;    ptrElement = <span class="hljs-keyword">new</span> T[length];    size = length;&#125;<span class="hljs-comment">//模板类CArray&lt;T&gt;的析构函数</span><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;CArray&lt;T&gt;:: ~ <span class="hljs-built_in">CArray</span>()&#123;    <span class="hljs-keyword">delete</span> [] ptrElement;&#125;</code></pre><p><strong>定义类模板的成员函数</strong></p><pre><code class="hljs cpp"><span class="hljs-comment">//模板类CArray&lt;T&gt;的成员函数 len()</span><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;<span class="hljs-type">int</span> CArray&lt;T&gt;:: <span class="hljs-built_in">len</span>()&#123;    <span class="hljs-keyword">return</span> size;&#125;<span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;<span class="hljs-type">void</span> CArray&lt;T&gt;::<span class="hljs-built_in">setElement</span>(T arg, <span class="hljs-type">int</span> index) &#123;    *(ptr+index) = arg;    <span class="hljs-keyword">return</span>;&#125;<span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;T CArray&lt;T&gt;::<span class="hljs-built_in">getElement</span>(<span class="hljs-type">int</span> index)    <span class="hljs-keyword">return</span> *(ptrElement+index);&#125;</code></pre><h5 id="函数模板作为类模板成员"><a href="#函数模板作为类模板成员" class="headerlink" title="函数模板作为类模板成员"></a>函数模板作为类模板成员</h5><p>成员函数模板<strong>只有调用时</strong>才会实例化</p><pre><code class="hljs c++"><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>&#123;<span class="hljs-keyword">public</span>:    <span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T2</span>&gt;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Func</span><span class="hljs-params">(T2 t)</span></span>&#123;cout&lt;&lt;t;&#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    A&lt;<span class="hljs-type">int</span>&gt; a;    a.<span class="hljs-built_in">Func</span>(‘K’);    a.<span class="hljs-built_in">Func</span>(<span class="hljs-string">&quot;Hello&quot;</span>);    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h5 id="非类型参数"><a href="#非类型参数" class="headerlink" title="非类型参数"></a>非类型参数</h5><p>⚠️类模板的<code>&lt;类型参数表&gt;</code>中<strong>可以包含非类型参数</strong></p><ul><li>用来说明<strong>属性</strong>，常用于定义模板内<strong>常量</strong>，<u>例如数组大小</u></li><li>类型参数则用来说明<strong>属性类型</strong>，<u>例如成员函数参数类型和返回值</u></li></ul><pre><code class="hljs c++"><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>,<span class="hljs-type">int</span> size&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CArray</span>&#123;    T array[size];<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">()</span></span>&#123;        <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i&lt;size;i++)&#123;            cout&lt;&lt;array[i]&lt;&lt;endl;        &#125;    &#125;&#125;;CArray&lt;<span class="hljs-type">double</span>,<span class="hljs-number">40</span>&gt; a2;CArray&lt;<span class="hljs-type">int</span>,<span class="hljs-number">50</span>&gt; a3; <span class="hljs-comment">//编译后size直接替换</span></code></pre><p>⚠️ 类中<strong>并没有</strong>条件添加一个int size成员变量</p><blockquote><p>类模板参数声明中的非类型参数→编译链接即确定→可以提高程序执行效率</p></blockquote><h4 id="继承与派生"><a href="#继承与派生" class="headerlink" title="继承与派生"></a>继承与派生</h4><pre><code class="hljs mermaid">flowchart LR    A[类模板]    B[模板类]    C[普通类]    A1[类模板raw]        A--&gt;|实例化|B    B--&gt;|派生|A    A1--&gt;|派生|A    C--&gt;|派生|A    B--&gt;|派生|C</code></pre><h5 id="1-类模板派生类模板"><a href="#1-类模板派生类模板" class="headerlink" title="1. 类模板派生类模板"></a>1. 类模板派生类模板</h5><ul><li><strong>核心逻辑</strong>：父类是类模板，子类也保持模板特性，继承时必须传递父类的模板参数。</li></ul><pre><code class="hljs cpp"><span class="hljs-comment">// 父类：类模板</span><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T1</span>,<span class="hljs-keyword">class</span> <span class="hljs-title class_">T2</span>&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">public</span>:    T1 num;    T2 hh;&#125;;<span class="hljs-comment">// 子类：类模板（继承类模板）</span><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T1</span>,<span class="hljs-keyword">class</span> <span class="hljs-title class_">T2</span>&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> Base&lt;T2,T1&gt; &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function">T1 <span class="hljs-title">getNum</span><span class="hljs-params">()</span> </span>&#123; <span class="hljs-keyword">return</span> num; &#125;&#125;;<span class="hljs-comment">//想清楚上面就迎刃而解</span></code></pre><h5 id="2-模板类派生类模板"><a href="#2-模板类派生类模板" class="headerlink" title="2. 模板类派生类模板"></a>2. 模板类派生类模板</h5><ul><li><strong>核心逻辑</strong>：父类是<strong>已经实例化的模板类</strong>（类型固定），子类可以是新的类模板。</li></ul><pre><code class="hljs cpp"><span class="hljs-comment">// 父类：模板类（已实例化，T=int固定）</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">BaseInt</span> : <span class="hljs-keyword">public</span> Base&lt;<span class="hljs-type">int</span>&gt; &#123;&#125;;<span class="hljs-comment">// 子类：类模板，继承固定的模板类</span><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> BaseInt &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function">T <span class="hljs-title">add</span><span class="hljs-params">(T a, T b)</span> </span>&#123; <span class="hljs-keyword">return</span> a + b; &#125;&#125;;</code></pre><h5 id="3-普通类派生类模板"><a href="#3-普通类派生类模板" class="headerlink" title="3. 普通类派生类模板"></a>3. 普通类派生类模板</h5><ul><li><strong>核心逻辑</strong>：父类是普通类，子类是类模板，继承时父类的类型需匹配子类模板参数。</li></ul><pre><code class="hljs cpp"><span class="hljs-comment">// 父类：普通类</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> id = <span class="hljs-number">10</span>;&#125;;<span class="hljs-comment">// 子类：类模板，继承普通类</span><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">public</span>:    T value;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">setValue</span><span class="hljs-params">(T v)</span> </span>&#123; value = v; &#125;&#125;;</code></pre><h5 id="4-模板类派生普通类"><a href="#4-模板类派生普通类" class="headerlink" title="4. 模板类派生普通类"></a>4. 模板类派生普通类</h5><ul><li><strong>核心逻辑</strong>：父类是<strong>模板类</strong>（类型固定），子类是普通类，直接继承固定的模板类实例。</li></ul><pre><code class="hljs cpp"><span class="hljs-comment">// 父类：模板类（已实例化）</span><span class="hljs-keyword">template</span> &lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">public</span>:    T data;&#125;;<span class="hljs-comment">// 子类：普通类，继承固定的模板类（Base&lt;string&gt;）</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> Base&lt;string&gt; &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">printData</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; data; &#125;&#125;;</code></pre><hr><h4 id="友元"><a href="#友元" class="headerlink" title="友元"></a>友元</h4><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/54d2126467529235b4d85a77647cbda5.jpg" alt="54d2126467529235b4d85a77647cbda5"></p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260404182527844.png" alt="image-20260404182527844"></p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260404182442452.png" alt="image-20260404182442452"></p><h4 id="static成员"><a href="#static成员" class="headerlink" title="static成员"></a>static成员</h4><ul><li>类模板中可以定义<strong>静态成员</strong>, 那么从该类模板<strong>同一个实例化</strong>得到的模板类的<strong>所有对象</strong>, 都包含同样的静态成员</li></ul><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260404182834272.png" alt="image-20260404182834272"></p><pre><code class="hljs c++"><span class="hljs-comment">//普通类静态成员初始化</span><span class="hljs-type">int</span> MyClass::count = <span class="hljs-number">0</span>;<span class="hljs-comment">//类模板静态成员初始化（默认值）</span><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;<span class="hljs-type">int</span> A&lt;T&gt;::count = <span class="hljs-number">0</span>;<span class="hljs-comment">//为特定类型的类模板静态成员初始化</span><span class="hljs-keyword">template</span>&lt;&gt; <span class="hljs-comment">//标准写法</span><span class="hljs-type">int</span> A&lt;<span class="hljs-type">int</span>&gt;::count = <span class="hljs-number">0</span>;<span class="hljs-keyword">template</span>&lt;&gt;<span class="hljs-type">int</span> A&lt;<span class="hljs-type">double</span>&gt;::count = <span class="hljs-number">1</span>;</code></pre><h4 id="模板特化（考试不要求）"><a href="#模板特化（考试不要求）" class="headerlink" title="模板特化（考试不要求）"></a>模板特化（考试不要求）</h4><blockquote><h5 id="一、函数模板的特化（考试不要求）"><a href="#一、函数模板的特化（考试不要求）" class="headerlink" title="一、函数模板的特化（考试不要求）"></a>一、函数模板的特化（考试不要求）</h5><h6 id="1-核心语法与示例"><a href="#1-核心语法与示例" class="headerlink" title="1. 核心语法与示例"></a>1. 核心语法与示例</h6><pre><code class="hljs cpp"><span class="hljs-comment">// 通用函数模板（默认实现，适用于所有类型T）</span><span class="hljs-function"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">class</span> T&gt;</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(T x)</span> </span>&#123;     cout &lt;&lt; <span class="hljs-string">&quot;Default Print: &quot;</span> &lt;&lt; x &lt;&lt; endl; &#125;<span class="hljs-comment">// 对bool类型的全特化（为特定类型提供专属实现）</span><span class="hljs-keyword">template</span>&lt;&gt;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-type">bool</span> x)</span> </span>&#123;     cout &lt;&lt; (x ? <span class="hljs-string">&quot;Good&quot;</span> : <span class="hljs-string">&quot;Bad&quot;</span>); &#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-built_in">print</span>(<span class="hljs-number">5</span>);        <span class="hljs-comment">// 匹配通用模板，输出：Default Print: 5</span>    <span class="hljs-built_in">print</span>(<span class="hljs-string">&quot;hello&quot;</span>);  <span class="hljs-comment">// 匹配通用模板，输出：Default Print: hello</span>    <span class="hljs-built_in">print</span>(<span class="hljs-number">5</span> == <span class="hljs-number">1</span>);   <span class="hljs-comment">// 匹配bool特化版本，输出：Bad</span>    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h6 id="2-关键说明"><a href="#2-关键说明" class="headerlink" title="2. 关键说明"></a>2. 关键说明</h6><ul><li><strong>全特化</strong>：用<code>template&lt;&gt;</code>标识，为<strong>完全确定的类型</strong>提供独立实现，调用优先级远高于通用模板。</li><li><strong>函数模板不支持部分特化</strong>：若需要针对某一类类型（如所有指针、所有容器）做定制，直接使用<strong>函数重载</strong>是更简洁、易维护的方案。</li><li>补充：函数模板特化本质是为通用模板的特定实例提供专属实现，而非重载（重载是不同的函数签名）。</li></ul><hr><h5 id="二、类模板的特化（考试不要求）"><a href="#二、类模板的特化（考试不要求）" class="headerlink" title="二、类模板的特化（考试不要求）"></a>二、类模板的特化（考试不要求）</h5><p>类模板特化分为<strong>全特化</strong>和<strong>部分特化（偏特化）</strong>，优先级规则：<code>全特化 &gt; 部分特化 &gt; 通用模板</code>。</p><h6 id="1-类模板全特化（完全指定所有模板参数）"><a href="#1-类模板全特化（完全指定所有模板参数）" class="headerlink" title="1. 类模板全特化（完全指定所有模板参数）"></a>1. 类模板全特化（完全指定所有模板参数）</h6><p>为<strong>完全确定的模板参数</strong>提供专属实现，用<code>template&lt;&gt;</code>标识。</p><pre><code class="hljs cpp"><span class="hljs-comment">// 通用类模板（默认实现）</span><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T</span>&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Printer</span>&#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(T x)</span> </span>&#123;         cout &lt;&lt; <span class="hljs-string">&quot;Default Print: &quot;</span> &lt;&lt; x &lt;&lt; endl;     &#125;&#125;;<span class="hljs-comment">// 对bool类型的全特化</span><span class="hljs-keyword">template</span>&lt;&gt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Printer</span>&lt;<span class="hljs-type">bool</span>&gt;&#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">(<span class="hljs-type">bool</span> x)</span> </span>&#123;         cout &lt;&lt; (x ? <span class="hljs-string">&quot;Good&quot;</span> : <span class="hljs-string">&quot;Bad&quot;</span>);     &#125;&#125;;<span class="hljs-comment">// 使用示例</span>Printer&lt;<span class="hljs-type">int</span>&gt; p; Printer&lt;<span class="hljs-type">bool</span>&gt; p2;p.<span class="hljs-built_in">print</span>(<span class="hljs-number">5</span>);      <span class="hljs-comment">// 调用通用模板，输出：Default Print: 5</span>p<span class="hljs-number">2.</span><span class="hljs-built_in">print</span>(<span class="hljs-number">5</span>);     <span class="hljs-comment">// 调用bool特化版本，输出：Good（5隐式转换为true）</span></code></pre><h6 id="2-类模板部分特化（仅指定部分-约束模板参数）"><a href="#2-类模板部分特化（仅指定部分-约束模板参数）" class="headerlink" title="2. 类模板部分特化（仅指定部分&#x2F;约束模板参数）"></a>2. 类模板部分特化（仅指定部分&#x2F;约束模板参数）</h6><p>仅对多参数类模板生效，通过约束部分参数生成更具体的模板版本，适用于通用模板无法覆盖的场景。</p><ul><li>通用模板定义：</li></ul><pre><code class="hljs cpp"><span class="hljs-keyword">template</span>&lt;<span class="hljs-keyword">class</span> <span class="hljs-title class_">T1</span>, <span class="hljs-keyword">class</span> <span class="hljs-title class_">T2</span>&gt; <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyClass</span> &#123;&#125;;</code></pre><ul><li><p>常见部分特化场景：</p><table><thead><tr><th>特化类型</th><th>语法</th><th>说明</th></tr></thead><tbody><tr><td>固定第二个参数</td><td><code>template&lt;class T&gt; class MyClass&lt;T, int&gt;</code></td><td>第二个参数固定为<code>int</code>，第一个参数仍为泛型</td></tr><tr><td>两个参数均为同类型指针</td><td><code>template&lt;class T&gt; class MyClass&lt;T*, T*&gt;</code></td><td>两个参数必须是同类型的指针</td></tr><tr><td>两个参数类型完全相同</td><td><code>template&lt;class T&gt; class MyClass&lt;T, T&gt;</code></td><td>两个参数必须是完全相同的类型</td></tr></tbody></table></li><li><p>全特化（完全指定所有参数）：</p></li></ul><pre><code class="hljs cpp"><span class="hljs-keyword">template</span>&lt;&gt; <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyClass</span>&lt;<span class="hljs-type">int</span>, <span class="hljs-type">double</span>&gt; &#123;&#125;;</code></pre><hr><h5 id="三、核心对比与总结"><a href="#三、核心对比与总结" class="headerlink" title="三、核心对比与总结"></a>三、核心对比与总结</h5><table><thead><tr><th>特性</th><th>函数模板</th><th>类模板</th></tr></thead><tbody><tr><td>全特化支持</td><td>✅ 支持，用<code>template&lt;&gt;</code>标识</td><td>✅ 支持，用<code>template&lt;&gt;</code>标识</td></tr><tr><td>部分特化支持</td><td>❌ 不支持，用函数重载替代</td><td>✅ 支持，仅适用于多参数模板</td></tr><tr><td>调用优先级</td><td>特化版本 &gt; 通用模板</td><td>全特化 &gt; 部分特化 &gt; 通用模板</td></tr><tr><td>适用场景</td><td>为特定类型定制函数逻辑</td><td>为特定类型&#x2F;参数约束定制类的完整实现</td></tr></tbody></table><hr><h5 id="四、补充注意事项"><a href="#四、补充注意事项" class="headerlink" title="四、补充注意事项"></a>四、补充注意事项</h5><ol><li>函数模板特化在工程中<strong>优先用函数重载</strong>：重载的可读性、可维护性远高于特化，且符合C++的设计习惯。</li><li>类模板特化的常见用途：为指针类型优化内存操作、为特定类型（如<code>std::string</code>）定制成员函数、为特化版本单独初始化静态成员。</li><li>部分特化仅针对<strong>模板参数的约束</strong>，而非具体类型：例如<code>MyClass&lt;T*, T*&gt;</code>是针对所有指针类型的特化，而非某一个具体指针（如<code>int*</code>）。</li><li>特化必须在<strong>通用模板声明之后</strong>定义，否则编译器无法识别特化关系。</li></ol></blockquote>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/d56d/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/d56d/"/>
    <published>2026-03-31T16:00:00.000Z</published>
    <summary>泛型编程核心：函数模板与类模板</summary>
    <title>类函数与函数模板</title>
    <updated>2026-07-21T09:01:07.741Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="多态" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E5%A4%9A%E6%80%81/"/>
    <category term="虚函数" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E8%99%9A%E5%87%BD%E6%95%B0/"/>
    <content>
      <![CDATA[<h1 id="多态与虚函数"><a href="#多态与虚函数" class="headerlink" title="多态与虚函数"></a>多态与虚函数</h1><blockquote><ul><li><strong>这是一个经典陷阱。C++ 的访问控制检查在</strong>编译期<strong>基于指针的</strong>静态类型**（基类）。只要基类中该虚函数是 <code>public</code>，即使派生类里把它 <code>override</code> 成了 <code>private</code>，通过基类指针调用时编译器仍然允许，运行时动态绑定到派生类的私有版本——<strong>完全可以调用</strong>。</li></ul></blockquote><hr><ul><li>封装——类的抽象和设计&#x2F;可见性</li><li>继承——基类派生派生类&#x2F;代码继承</li><li>多态——函数重载&#x2F;？</li></ul><h2 id="虚函数"><a href="#虚函数" class="headerlink" title="虚函数"></a>虚函数</h2><p><strong>带 virtual 关键字</strong>的<strong>成员函数</strong></p><ul><li><strong>只</strong>用在类定义的<strong>函数声明</strong>中，写函数体不用</li><li>静态成员函数<strong>不能</strong>是虚函数</li><li>基类函数声明,派生类自动虚函数(<strong>同名函数</strong>)</li></ul><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">base</span>&#123;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">int</span> <span class="hljs-title">get</span><span class="hljs-params">()</span></span>;<span class="hljs-comment">//int virtual get(); //二者等价</span>&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">base::get</span><span class="hljs-params">()</span></span>&#123;...&#125;</code></pre><h2 id="多态表现形式"><a href="#多态表现形式" class="headerlink" title="多态表现形式"></a>多态表现形式</h2><h3 id="表现形式1"><a href="#表现形式1" class="headerlink" title="表现形式1"></a>表现形式1</h3><ul><li><p>派生类的<strong>指针</strong>可以赋给<strong>基类指针</strong></p></li><li><p>通过<strong>基类指针</strong>调用基类和派生类中的同名<strong>虚函数</strong>时</p><ul><li><p>若该指针 指向的是一个<strong>基类的对象</strong>，被调用的是<strong>基类的虚函数</strong>（派生类则派生类的虚函数）</p><pre><code class="hljs c++">CBase * r= &amp;ODerived；r.<span class="hljs-built_in">VirtualFunction</span>();<span class="hljs-comment">// 根据 指针/引用指向的对象类型，来决定调用的函数</span></code></pre></li></ul></li></ul><p><img src="https://cdn.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260323220142314.png" alt="image-20260323220142314"></p><h3 id="表现形式2"><a href="#表现形式2" class="headerlink" title="表现形式2"></a>表现形式2</h3><ul><li><p>派生类的<strong>对象</strong>可以赋给<strong>基类引用</strong></p></li><li><p>通过<strong>基类引用</strong>调用基类和派生类中的同名<strong>虚函数</strong>时</p><ul><li><p>若该引用 引用的是一个<strong>基类的对象</strong>，被调用的是<strong>基类的虚函数</strong>（派生类则派生类的虚函数）</p><pre><code class="hljs c++">CBase &amp; r=ODerived；r.<span class="hljs-built_in">VirtualFunction</span>();<span class="hljs-comment">// 根据 指针/引用指向的对象类型，来决定调用的函数</span></code></pre></li></ul></li></ul><p><img src="https://cdn.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260323220205489.png" alt="image-20260323220205489"></p><h3 id="一个小例子"><a href="#一个小例子" class="headerlink" title="一个小例子"></a>一个小例子</h3><p>例子一：</p><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-comment">// 原始多态示例代码</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;A::Print&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span> : <span class="hljs-keyword">public</span> A &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;B::Print&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">D</span> : <span class="hljs-keyword">public</span> A &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;D::Print&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">E</span> : <span class="hljs-keyword">public</span> B &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;E::Print&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-comment">// 修改后的示例代码（派生类 Print 不写 virtual，效果相同）</span><span class="hljs-comment">/*</span><span class="hljs-comment">class A &#123;</span><span class="hljs-comment">public:</span><span class="hljs-comment">    virtual void Print() &#123; cout &lt;&lt; &quot;A::Print&quot; &lt;&lt; endl; &#125;</span><span class="hljs-comment">&#125;;</span><span class="hljs-comment"></span><span class="hljs-comment">class B : public A &#123;</span><span class="hljs-comment">public:</span><span class="hljs-comment">    void Print() &#123; cout &lt;&lt; &quot;B::Print&quot; &lt;&lt; endl; &#125;</span><span class="hljs-comment">&#125;;</span><span class="hljs-comment"></span><span class="hljs-comment">class D : public A &#123;</span><span class="hljs-comment">public:</span><span class="hljs-comment">    void Print() &#123; cout &lt;&lt; &quot;D::Print&quot; &lt;&lt; endl; &#125;</span><span class="hljs-comment">&#125;;</span><span class="hljs-comment"></span><span class="hljs-comment">class E : public B &#123;</span><span class="hljs-comment">public:</span><span class="hljs-comment">    void Print() &#123; cout &lt;&lt; &quot;E::Print&quot; &lt;&lt; endl; &#125;</span><span class="hljs-comment">&#125;;</span><span class="hljs-comment">*/</span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    A a;    B b;    E e;    D d;    A *pa = &amp;a;    B *pb = &amp;b;    D *pd = &amp;d;    E *pe = &amp;e;    pa-&gt;<span class="hljs-built_in">Print</span>();        <span class="hljs-comment">// 输出: A::Print</span>    pa = pb;    pa-&gt;<span class="hljs-built_in">Print</span>();        <span class="hljs-comment">// 输出: B::Print</span>    pa = pd;    pa-&gt;<span class="hljs-built_in">Print</span>();        <span class="hljs-comment">// 输出: D::Print</span>    pa = pe;    pa-&gt;<span class="hljs-built_in">Print</span>();        <span class="hljs-comment">// 输出: E::Print</span>    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>代码说明</p><ol><li><strong>多态核心</strong>：<code>A</code> 类中 <code>Print</code> 声明为 <code>virtual</code>，派生类重写该函数后，通过基类指针 <code>pa</code> 调用时，会根据指针实际指向的对象类型，自动调用对应类的 <code>Print</code> 函数，这就是<strong>运行时多态</strong>。</li><li><strong>virtual 继承特性</strong>：基类函数声明为 <code>virtual</code> 后，所有派生类中同名函数<strong>自动保持虚函数特性</strong>，即使不写 <code>virtual</code> 关键字，多态效果也完全一致</li><li><strong>继承关系</strong>：<code>E</code> 继承自 <code>B</code>，<code>B</code> 和 <code>D</code> 继承自 <code>A</code>，因此 <code>E</code> 也间接继承自 <code>A</code>，可以被 <code>A*</code> 指针指向。</li></ol></blockquote><p>例子二</p><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-comment">// 基类 myclass</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">myclass</span> &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">reset</span><span class="hljs-params">()</span></span>;    <span class="hljs-comment">// virtual 关键字可写在返回值前或后</span>    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">()</span> </span>&#123;        cout &lt;&lt; <span class="hljs-string">&quot;myclass::print\n&quot;</span>;    &#125;&#125;;<span class="hljs-comment">// 基类普通成员函数 reset，内部调用虚函数 print</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">myclass::reset</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-built_in">print</span>(); <span class="hljs-comment">// 等价于 this-&gt;print(); this 是基类指针，会触发多态</span>&#125;<span class="hljs-comment">// 派生类 derived，继承自 myclass</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">derived</span> : <span class="hljs-keyword">public</span> myclass &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-comment">// 重写基类虚函数 print</span>    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">()</span> </span>&#123;        cout &lt;&lt; <span class="hljs-string">&quot;derived::print\n&quot;</span>;    &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    myclass b;    derived d;    b.<span class="hljs-built_in">reset</span>(); <span class="hljs-comment">// 调用 myclass::reset()，内部调用 myclass::print()</span>    d.<span class="hljs-built_in">reset</span>(); <span class="hljs-comment">// 调用 myclass::reset()，内部调用 derived::print()（多态）</span>    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><hr><p>运行结果</p><pre><code class="hljs arduino">myclass::printderived::print</code></pre><blockquote><h3 id="多态的价值"><a href="#多态的价值" class="headerlink" title="多态的价值"></a>多态的价值</h3><table><thead><tr><th align="center">场景</th><th align="center">手动写 <code>A::</code></th><th align="center">多态（virtual）</th></tr></thead><tbody><tr><td align="center"><strong>适用范围</strong></td><td align="center">只在你<strong>明确知道类型</strong>时能用</td><td align="center">哪怕<strong>不知道对象类型</strong>，也能正确调用</td></tr><tr><td align="center"><strong>扩展性</strong></td><td align="center">新增派生类时，要到处改代码</td><td align="center">新增派生类时，<strong>原有代码完全不用改</strong></td></tr><tr><td align="center"><strong>核心价值</strong></td><td align="center">语法糖</td><td align="center">实现<strong>开闭原则</strong>：对扩展开放，对修改关闭</td></tr></tbody></table><p>增强可扩充性</p><p>要改代码少</p></blockquote><h3 id="多态的作用"><a href="#多态的作用" class="headerlink" title="多态的作用"></a>多态的作用</h3><p><strong>多态的实质</strong></p><ul><li><strong>父类定义共同接口，子类不同实现</strong></li><li><strong>通过父类以相同方式</strong>操作不同子类行为</li></ul><h3 id="多态的实现实例"><a href="#多态的实现实例" class="headerlink" title="多态的实现实例"></a>多态的实现实例</h3><h4 id="实例1"><a href="#实例1" class="headerlink" title="实例1"></a>实例1</h4><p>游戏：6只怪兽、每只怪兽可以攻击、被击后的扣生命值、被击后的后摇（每只怪兽可能不同）</p><h5 id="非多态反面案例"><a href="#非多态反面案例" class="headerlink" title="非多态反面案例"></a>非多态反面案例</h5><h6 id="基本思路"><a href="#基本思路" class="headerlink" title="基本思路"></a>基本思路</h6><ul><li>为每个怪兽编写<code>attack</code>，<code>fightback</code>，<code>hurted</code>成员函数</li><li>Attack：<ul><li>被攻击怪兽Hurted</li><li>被攻击怪兽Fightback</li></ul></li><li>Hurted：自身生命值减少</li><li>FightBack：反击并调用被反击对象的Hurted</li></ul><p>传统的实现方式：</p><ul><li>怪兽A：攻击其他5个怪兽的函数、被其他5个怪兽攻击后摇（扣生命值）的5个函数</li><li>怪兽B：……</li><li>……</li></ul><p>若增加一个怪兽，则每个怪兽都要修改——平方型代码量增加，<del>代码KPI轻松完成</del></p><h5 id="多态做法"><a href="#多态做法" class="headerlink" title="多态做法"></a>多态做法</h5><h6 id="基类派生"><a href="#基类派生" class="headerlink" title="基类派生"></a>基类派生</h6><pre><code class="hljs mermaid">graph TD    %% 定义节点样式（可选，模拟原图效果）    classDef baseNode fill:#c6e7ff,stroke:#66afe9,stroke-width:2px;    classDef subNode fill:#ffffff,stroke:#999,stroke-width:1px;    %% 父节点    CCreature[&quot;CCreature&quot;]:::baseNode    %% 子节点    CDragon[&quot;CDragon&quot;]:::subNode    CWolf[&quot;CWolf&quot;]:::subNode    CSoldier[&quot;CSoldier&quot;]:::subNode    CPhonex[&quot;CPhonex&quot;]:::subNode    CAngel[&quot;CAngel&quot;]:::subNode    %% 继承关系（父 -&gt; 子）    CCreature --&gt; CDragon    CCreature --&gt; CWolf    CCreature --&gt; CSoldier    CCreature --&gt; CPhonex    CCreature --&gt; CAngel</code></pre><p>基类：</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">CCreature</span>&#123;<span class="hljs-keyword">protected</span>:    <span class="hljs-type">int</span> m_nLiveValue,m_nPower;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Attack</span><span class="hljs-params">(CCreature *pCreature)</span></span>;    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Hurted</span><span class="hljs-params">(<span class="hljs-type">int</span> nPower)</span></span>;    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">FrightBack</span><span class="hljs-params">(CCreature *pCreature)</span></span>;&#125;;</code></pre><p>派生：</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">CDragon</span> : <span class="hljs-keyword">public</span> CCreature&#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Attack</span><span class="hljs-params">(CCreature *pCreature)</span></span>;    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Hurted</span><span class="hljs-params">(<span class="hljs-type">int</span> nPower)</span></span>;    <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">FrightBack</span><span class="hljs-params">(CCreature *pCreature)</span></span>;&#125;;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CDragon::Attack</span><span class="hljs-params">(CCreature *p)</span></span>&#123;    p-&gt;<span class="hljs-built_in">Hurted</span>(m_nPower);    p-&gt;<span class="hljs-built_in">FightBack</span>(<span class="hljs-keyword">this</span>);&#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CDragon::Hurted</span><span class="hljs-params">(<span class="hljs-type">int</span> nPower)</span></span>&#123;    m_nLifeValue-=nPower;&#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CDragon::FightBack</span><span class="hljs-params">(CCreature *p)</span></span>&#123;    p-&gt;<span class="hljs-built_in">Hurted</span>(m_nPower/<span class="hljs-number">2</span>);&#125;</code></pre><p><strong>于是，新怪兽只需要编写新类，不需要</strong>专门增加传入新怪物的成员函数</p><p>具体使用的时候：</p><pre><code class="hljs c++">CDragon Dragon;CWolf Wolf;CGhost Ghost;CThunderBird Brid;Dragon.<span class="hljs-built_in">Attack</span>(&amp;Wolf);...CGhost::Hurted;</code></pre><p><strong>注意：以上采用传指针的方式实现多态</strong>，使用<strong>引用</strong>传入亦可</p><h4 id="实例2：几何形体处理程序"><a href="#实例2：几何形体处理程序" class="headerlink" title="实例2：几何形体处理程序"></a>实例2：几何形体处理程序</h4><p>需求：输入若干个几何形体的参数，要求按面积排序输出，输出时要指明形状。</p><ul><li><p>输入：第一行是几何形体数目n (≤100)，下面n行每行以字母c开头；c为’R’代表矩形，后跟宽和高；c为’C’代表圆，后跟半径；c为‘T’代表三角形，后跟三条边长度。</p></li><li><p>输出：按面积从小到大输出每个几何形体的种类及面积，格式为“形体名称: 面积”。</p></li><li><p>示例输入：<br>3<br>R 3 5<br>C 9<br>T 3 4 5</p></li><li><p>示例输出：<br>Triangle: 6<br>Rectangle: 15<br>Circle: 254.34</p><p>实现代码：</p></li></ul><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;stdlib.h&gt;</span> <span class="hljs-comment">//快速排序函数</span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;math.h&gt;</span> <span class="hljs-comment">//数学函数</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CShape</span> &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">double</span> <span class="hljs-title">Area</span><span class="hljs-params">( )</span> </span>= <span class="hljs-number">0</span>; <span class="hljs-comment">//纯虚函数</span><span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">PrintInfo</span><span class="hljs-params">( )</span> </span>= <span class="hljs-number">0</span>;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CRectangle</span>: <span class="hljs-keyword">public</span> CShape &#123;<span class="hljs-keyword">public</span>:<span class="hljs-type">int</span> w, h;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">double</span> <span class="hljs-title">Area</span><span class="hljs-params">()</span></span>;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">PrintInfo</span><span class="hljs-params">()</span></span>;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CCircle</span>: <span class="hljs-keyword">public</span> CShape &#123;<span class="hljs-keyword">public</span>:<span class="hljs-type">int</span> r;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">double</span> <span class="hljs-title">Area</span><span class="hljs-params">()</span></span>;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">PrintInfo</span><span class="hljs-params">()</span></span>;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CTriangle</span>: <span class="hljs-keyword">public</span> CShape &#123;<span class="hljs-keyword">public</span>:<span class="hljs-type">int</span> a, b, c;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">double</span> <span class="hljs-title">Area</span><span class="hljs-params">()</span></span>;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">PrintInfo</span><span class="hljs-params">()</span></span>;&#125;;<span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">CRectangle::Area</span><span class="hljs-params">()</span> </span>&#123;<span class="hljs-keyword">return</span> w * h;&#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CRectangle::PrintInfo</span><span class="hljs-params">()</span> </span>&#123;cout &lt;&lt; <span class="hljs-string">&quot;Rectangle:&quot;</span> &lt;&lt; <span class="hljs-built_in">Area</span>() &lt;&lt; endl;&#125;<span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">CCircle::Area</span><span class="hljs-params">()</span> </span>&#123;<span class="hljs-keyword">return</span> <span class="hljs-number">3.14</span> * r * r ;&#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CCircle::PrintInfo</span><span class="hljs-params">()</span> </span>&#123;cout &lt;&lt; <span class="hljs-string">&quot;Circle:&quot;</span> &lt;&lt; <span class="hljs-built_in">Area</span>() &lt;&lt; endl;&#125;<span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">CTriangle::Area</span><span class="hljs-params">()</span> </span>&#123;<span class="hljs-type">double</span> p = (a + b + c) / <span class="hljs-number">2.0</span>;<span class="hljs-keyword">return</span> <span class="hljs-built_in">sqrt</span>(p * (p - a)*(p - b)*(p - c));&#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CTriangle::PrintInfo</span><span class="hljs-params">()</span> </span>&#123;cout &lt;&lt; <span class="hljs-string">&quot;Triangle:&quot;</span> &lt;&lt; <span class="hljs-built_in">Area</span>() &lt;&lt; endl;&#125;CShape * pShapes[<span class="hljs-number">100</span>]; <span class="hljs-comment">//用来存放各种几何形体, 假设不超过100</span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">MyCompare</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">void</span> * s1, <span class="hljs-type">const</span> <span class="hljs-type">void</span> * s2)</span></span>&#123;CShape * * p1;CShape * * p2;p1 = ( CShape * * ) s1;p2 = ( CShape * * ) s2;<span class="hljs-type">double</span> a1 = (*p1)-&gt;<span class="hljs-built_in">Area</span>(); <span class="hljs-comment">//多态调用</span><span class="hljs-type">double</span> a2 = (*p2)-&gt;<span class="hljs-built_in">Area</span>();<span class="hljs-keyword">if</span>( a1 &lt; a2 ) <span class="hljs-keyword">return</span> <span class="hljs-number">-1</span>;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ( a2 &lt; a1 ) <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;<span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;<span class="hljs-type">int</span> i; <span class="hljs-type">int</span> n;CRectangle * pr;CCircle * pc;CTriangle * pt;cin &gt;&gt; n;<span class="hljs-keyword">for</span>( i = <span class="hljs-number">0</span>; i &lt; n; i ++ ) &#123;<span class="hljs-type">char</span> c;cin &gt;&gt; c;<span class="hljs-keyword">switch</span>(c) &#123;<span class="hljs-keyword">case</span> <span class="hljs-string">&#x27;R&#x27;</span>:pr = <span class="hljs-keyword">new</span> <span class="hljs-built_in">CRectangle</span>();cin &gt;&gt; pr-&gt;w &gt;&gt; pr-&gt;h;pShapes[i] = pr;<span class="hljs-keyword">break</span>;<span class="hljs-keyword">case</span> <span class="hljs-string">&#x27;C&#x27;</span>:pc = <span class="hljs-keyword">new</span> <span class="hljs-built_in">CCircle</span>();cin &gt;&gt; pc-&gt;r;pShapes[i] = pc;<span class="hljs-keyword">break</span>;<span class="hljs-keyword">case</span> <span class="hljs-string">&#x27;T&#x27;</span>:pt = <span class="hljs-keyword">new</span> <span class="hljs-built_in">CTriangle</span>();cin &gt;&gt; pt-&gt;a &gt;&gt; pt-&gt;b &gt;&gt; pt-&gt;c;pShapes[i] = pt;<span class="hljs-keyword">break</span>;&#125;&#125;<span class="hljs-built_in">qsort</span>(pShapes, n, <span class="hljs-built_in">sizeof</span>(CShape*), MyCompare);<span class="hljs-keyword">for</span>( i = <span class="hljs-number">0</span>; i &lt;n; i ++ )pShapes[i]-&gt;<span class="hljs-built_in">PrintInfo</span>(); <span class="hljs-comment">//多态调用</span><span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>代码说明</p><ol><li>⚠️<strong>纯虚函数与抽象类</strong>：<code>CShape</code> 包含纯虚函数，是抽象类，仅定义统一接口，不能实例化</li><li><strong>多态调用</strong>：基类指针数组存储派生类对象，调用<code>Area()</code>和<code>PrintInfo()</code>自动匹配对应类的实现</li><li><strong>排序逻辑</strong>：通过<code>qsort</code>+自定义比较函数，利用多态计算面积并排序</li></ol></blockquote><p>优势：添加新的几何形体（如五边形）时，只需从CShape派生出CPentagon类并重写虚函数，再在main的switch中增加一个case即可，其余代码无需修改。</p><blockquote><p>核心技巧：用基类指针数组存放指向各种派生类对象的指针，然后遍历该数组对各个派生类对象做操作，是C++中使用多态的常用做法。</p></blockquote><h4 id="MORE："><a href="#MORE：" class="headerlink" title="MORE："></a>MORE：</h4><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun1</span><span class="hljs-params">()</span> </span>&#123; <span class="hljs-built_in">fun2</span>(); &#125;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Base::fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span>:<span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Derived:fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;Derived d;Base * pBase = &amp; d;pBase-&gt;<span class="hljs-built_in">fun1</span>();<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>输出结果：Derived::fun2()<br>解析：<code>fun1()</code>内部的<code>fun2()</code>等价于<code>this-&gt;fun2()</code>，<code>this</code>是基类指针，触发动态联编，调用派生类虚函数</p></blockquote><hr><h2 id="多态的实现原理"><a href="#多态的实现原理" class="headerlink" title="多态的实现原理"></a>多态的实现原理</h2><h3 id="面向对象编程的三个基本概念"><a href="#面向对象编程的三个基本概念" class="headerlink" title="面向对象编程的三个基本概念"></a>面向对象编程的三个基本概念</h3><ul><li>数据抽象 ↔ 用类进行数据抽象，封装</li><li>继承 ↔ 派生类继承基类成员</li><li>动态绑定 ↔ 多态，<strong>编译器在运行时决定调用基类&#x2F;派生类函数</strong></li></ul><h3 id="动态联编"><a href="#动态联编" class="headerlink" title="动态联编"></a>动态联编</h3><p>一条函数调用语句在编译时无法确定调用哪个函数，<strong>运行到该语句时才确定调用哪个函数</strong>，这种机制叫<strong>动态联编</strong></p><p><strong>为什么需要动态联编？</strong></p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123; <span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Get</span><span class="hljs-params">()</span></span>; &#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span> : <span class="hljs-keyword">public</span> A &#123; <span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Get</span><span class="hljs-params">()</span></span>; &#125;;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">MyFunction</span><span class="hljs-params">( A * pa )</span> </span>&#123;pa-&gt;<span class="hljs-built_in">Get</span>();&#125;</code></pre><blockquote><p>编译时无法确定<code>pa</code>指向A&#x2F;B对象，只能运行时判断调用哪个<code>Get()</code></p></blockquote><h3 id="多态的实现解析"><a href="#多态的实现解析" class="headerlink" title="多态的实现解析"></a>多态的实现解析</h3><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun1</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Base::fun1()&quot;</span> &lt;&lt;endl; <span class="hljs-built_in">fun2</span>(); &#125;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Base::fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span>: <span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun1</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Derived::fun1()&quot;</span> &lt;&lt; endl; <span class="hljs-built_in">fun2</span>(); &#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Derived::fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;Derived d;Base * pBase = &amp; d;pBase -&gt; <span class="hljs-built_in">fun1</span>();<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><pre><code class="hljs plain">Base::fun1()Derived::fun2()</code></pre><p>补充说明：<br>调用次序：<code>Base::fun1() -&gt; Derived::fun2()</code><br><code>fun1()</code>中<code>fun2()</code>等价于<code>this-&gt;fun2()</code>，<code>fun2</code>是虚函数+基类指针，触发动态联编；运行时<code>this</code>指向派生类对象，调用派生类函数。</p><p><strong>稍加修改的例子</strong></p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun1</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Base::fun1()&quot;</span> &lt;&lt;endl; <span class="hljs-built_in">fun2</span>(); &#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Base::fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span>: <span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun1</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Derived::fun1()&quot;</span> &lt;&lt; endl; <span class="hljs-built_in">fun2</span>(); &#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Derived::fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;Derived d;Base * pBase = &amp; d;pBase -&gt; <span class="hljs-built_in">fun1</span>();<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>输出：Derived::fun1() 、Derived::fun2()<br>解析：<code>fun1</code>是虚函数→动态联编；派生类<code>fun1</code>中调用普通函数<code>fun2</code>，直接调用自身版本</p></blockquote><h3 id="虚函数表（多态的核心实现）"><a href="#虚函数表（多态的核心实现）" class="headerlink" title="虚函数表（多态的核心实现）"></a>虚函数表（多态的核心实现）</h3><p><strong>思考例子</strong></p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base1</span> &#123;<span class="hljs-keyword">public</span>: <span class="hljs-type">int</span> i;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Base1:Print&quot;</span> ; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> Base1&#123;<span class="hljs-keyword">public</span>: <span class="hljs-type">int</span> n;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt;<span class="hljs-string">&quot;Derived:Print&quot;</span>&lt;&lt; endl; &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;Derived d;cout &lt;&lt; <span class="hljs-built_in">sizeof</span>( Base1 ) &lt;&lt; <span class="hljs-string">&quot;, &quot;</span>&lt;&lt; <span class="hljs-built_in">sizeof</span>( Derived ) ;<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>输出：8, 12<br>疑问：对象大小多出4字节？这与多态有何关联？</p></blockquote><blockquote><p>咦?</p><p><img src="https://cdn.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260428173451262.png"></p><p>神奇的是对于8字节,会有pad8字节对齐</p></blockquote><p><strong>原理：多出的空间用于存储虚函数表指针</strong></p><ol><li>含虚函数的类&#x2F;派生类，都有<strong>虚函数表</strong>，对象中存储<strong>虚函数表指针</strong>（4&#x2F;8字节）</li><li>虚函数表存储类的所有虚函数地址</li><li>基类指针调用虚函数时，通过对象的虚表指针找到对应函数，实现动态绑定</li></ol><p><strong>调用过程</strong>：<code>Base* pBase = &amp;d; pBase-&gt;Print();</code></p><ul><li>pBase指向Derived对象，虚表指针指向Derived类虚表</li><li>虚表中<code>Print</code>地址为<code>Derived::Print</code></li><li>程序调用派生类函数</li></ul><h3 id="虚函数的访问权限"><a href="#虚函数的访问权限" class="headerlink" title="虚函数的访问权限"></a>虚函数的访问权限</h3><p>访问权限检查是<strong>根据指针&#x2F;引用的类型</strong>，而非运行时指向的对象类型。</p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">private</span>: <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Base::fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span>: <span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Derived::fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;Derived d;Base * pBase = &amp; d;pBase -&gt; <span class="hljs-built_in">fun2</span>(); <span class="hljs-comment">// 编译出错</span><span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>编译出错：基类<code>fun2</code>是私有成员，语法检查直接报错</p></blockquote><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Base::fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span>:<span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">private</span>: <span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">fun2</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Derived::fun2()&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;Derived d;Base*pBase=&amp;d;pBase-&gt;<span class="hljs-built_in">fun2</span>(); <span class="hljs-comment">// 编译通过，运行调用Derived::fun2()</span><span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>编译通过：基类函数公有→语法检查通过；运行动态绑定派生类私有函数</p></blockquote><h3 id="构造函数和析构函数中调用虚函数"><a href="#构造函数和析构函数中调用虚函数" class="headerlink" title="构造函数和析构函数中调用虚函数"></a>构造函数和析构函数中调用虚函数</h3><p>⚠️<strong>规则</strong>：<strong>构造&#x2F;析构函数中</strong>调用虚函数为<strong>静态联编</strong>，<strong>仅调用当前类&#x2F;基类函数</strong>；普通成员函数中才是动态联编。</p><p><strong>例子</strong></p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">myclass</span>&#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">hello</span><span class="hljs-params">()</span></span>&#123; cout&lt;&lt;<span class="hljs-string">&quot;hello from myclass&quot;</span>&lt;&lt;endl; &#125;;<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">bye</span><span class="hljs-params">()</span></span>&#123; cout&lt;&lt;<span class="hljs-string">&quot;bye from myclass&quot;</span>&lt;&lt;endl; &#125;;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">son</span> : <span class="hljs-keyword">public</span> myclass&#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">hello</span><span class="hljs-params">()</span> </span>&#123; cout&lt;&lt;<span class="hljs-string">&quot;hello from son&quot;</span>&lt;&lt;endl; &#125;;<span class="hljs-built_in">son</span>() &#123; <span class="hljs-built_in">hello</span>(); &#125;;~<span class="hljs-built_in">son</span>() &#123; <span class="hljs-built_in">bye</span>(); &#125;;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">grandson</span> : <span class="hljs-keyword">public</span> son&#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">hello</span><span class="hljs-params">()</span> </span>&#123; cout&lt;&lt;<span class="hljs-string">&quot;hello from grandson&quot;</span>&lt;&lt;endl; &#125;;<span class="hljs-built_in">grandson</span>() &#123; cout&lt;&lt;<span class="hljs-string">&quot;constructing grandson&quot;</span>&lt;&lt;endl; &#125;;~<span class="hljs-built_in">grandson</span>() &#123; cout&lt;&lt;<span class="hljs-string">&quot;destructing grandson&quot;</span>&lt;&lt;endl; &#125;;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;grandson gson;son *pson;pson=&amp;gson;pson-&gt;<span class="hljs-built_in">hello</span>();<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p><strong>输出</strong></p><pre><code class="hljs vbnet">hello <span class="hljs-keyword">from</span> sonconstructing grandsonhello <span class="hljs-keyword">from</span> grandsondestructing grandsonbye <span class="hljs-keyword">from</span> <span class="hljs-keyword">myclass</span></code></pre><p><strong>原因</strong></p><ol><li>构造时：先调用基类构造，<strong>派生类未初始化，对象身份为基类，调用基类虚函数</strong></li><li>普通调用：对象构造完成，动态绑定派生类函数</li><li>析构时：<strong>先析构派生类，对象身份回到基类</strong>，调用基类函数</li></ol><h3 id="测一测"><a href="#测一测" class="headerlink" title="测一测"></a>测一测</h3><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Func</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;A::Func&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>:<span class="hljs-keyword">public</span> A &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Func</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;B::Func&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;A a;A * pa = <span class="hljs-keyword">new</span> <span class="hljs-built_in">B</span>();pa-&gt;<span class="hljs-built_in">Func</span>();<span class="hljs-comment">//64位程序用long long</span><span class="hljs-type">long</span> * p1 = (<span class="hljs-type">long</span> * ) &amp; a;<span class="hljs-type">long</span> * p2 = (<span class="hljs-type">long</span> * ) pa;* p2 = * p1;<span class="hljs-comment">//把 A 的 vptr 复制过去，覆盖 B 的 vptr</span>pa-&gt;<span class="hljs-built_in">Func</span>();<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>输出结果：B::Func 、A::Func<br>解析：</p><ol><li>第一次调用：指向B对象→调用B::Func</li><li>赋值操作：将A的虚表指针覆盖B的虚表指针</li><li>第二次调用：通过A的虚表→调用A::Func</li></ol><blockquote><pre><code class="hljs c++"><span class="hljs-type">long</span> * p1 = (<span class="hljs-type">long</span> *) &amp;a;   <span class="hljs-comment">// p1 指向 A 对象的首地址（把它当成 8 字节整数来看）</span><span class="hljs-type">long</span> * p2 = (<span class="hljs-type">long</span> *) pa;   <span class="hljs-comment">// p2 指向 B 对象的首地址（也当成 8 字节整数）</span>* p2 = * p1;               <span class="hljs-comment">// 只复制了这 8 个字节！</span></code></pre><p>和对象赋值<strong>完全不是一回事</strong>,把 A 对象的前 8 个字节（恰好是它的 vptr）复制到 B 对象的前 8 个字节位置，覆盖了 B 的 vptr。</p><p>B 对象的其他部分——如果它有数据成员的话——<strong>完全没被碰</strong>。</p></blockquote></blockquote><hr><h2 id="虚析构函数"><a href="#虚析构函数" class="headerlink" title="虚析构函数"></a>虚析构函数</h2><h3 id="问题背景"><a href="#问题背景" class="headerlink" title="问题背景"></a>问题背景</h3><p>⚠️⚠️<strong>通过基类指针删除派生类对象，仅调用基类析构函数，派生类资源未释放，造成内存泄漏。</strong></p><p><strong>例子</strong></p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">son</span>&#123;<span class="hljs-keyword">public</span>:~<span class="hljs-built_in">son</span>() &#123; cout&lt;&lt;<span class="hljs-string">&quot;bye from son&quot;</span>&lt;&lt;endl; &#125;;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">grandson</span> : <span class="hljs-keyword">public</span> son&#123;<span class="hljs-keyword">public</span>:~<span class="hljs-built_in">grandson</span>()&#123; cout&lt;&lt;<span class="hljs-string">&quot;bye from grandson&quot;</span>&lt;&lt;endl; &#125;;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;son *pson;pson=<span class="hljs-keyword">new</span> grandson;<span class="hljs-keyword">delete</span> pson;<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>输出：bye from son<br>问题：未调用派生类析构函数，资源泄漏</p></blockquote><h3 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h3><p>将<strong>基类析构函数声明为virtual</strong>，派生类析构函数可省略virtual。<br>通过基类指针删除对象时，先调用派生类析构，再调用基类析构。</p><p><strong>例子</strong></p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">son</span> &#123;<span class="hljs-keyword">public</span>:<span class="hljs-keyword">virtual</span> ~<span class="hljs-built_in">son</span>() &#123; cout&lt;&lt;<span class="hljs-string">&quot;bye from son&quot;</span>&lt;&lt;endl; &#125;;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">grandson</span> : <span class="hljs-keyword">public</span> son &#123;<span class="hljs-keyword">public</span>:~<span class="hljs-built_in">grandson</span>()&#123; cout&lt;&lt;<span class="hljs-string">&quot;bye from grandson&quot;</span>&lt;&lt;endl; &#125;;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;son *pson;pson= <span class="hljs-keyword">new</span> grandson;<span class="hljs-keyword">delete</span> pson;<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>输出：<br>bye from grandson<br>bye from son</p></blockquote><p><strong>通用规则</strong>：类定义了虚函数，析构函数必须定义为虚函数。</p><h3 id="构造函数能否声明为virtual？"><a href="#构造函数能否声明为virtual？" class="headerlink" title="构造函数能否声明为virtual？"></a>构造函数能否声明为virtual？</h3><p><strong>不能</strong>。<br>⚠️原因：构造函数负责初始化<strong>虚函数表指针</strong>，而虚函数调用依赖该指针；构造函数执行前指针未初始化，矛盾。</p><hr><h2 id="纯虚函数和抽象类"><a href="#纯虚函数和抽象类" class="headerlink" title="纯虚函数和抽象类"></a>纯虚函数和抽象类</h2><h3 id="纯虚函数"><a href="#纯虚函数" class="headerlink" title="纯虚函数"></a>纯虚函数</h3><p>没有函数体的虚函数，声明格式：<code>virtual 返回值 函数名(参数) = 0;</code></p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123;<span class="hljs-keyword">private</span>: <span class="hljs-type">int</span> a;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">( )</span> </span>= <span class="hljs-number">0</span> ; <span class="hljs-comment">//纯虚函数</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;fun&quot;</span>; &#125;&#125;;</code></pre><h3 id="抽象类"><a href="#抽象类" class="headerlink" title="抽象类"></a>抽象类</h3><p>包含纯虚函数的类为抽象类，特性：</p><ol><li>不能创建抽象类对象，只能作为基类派生</li><li>抽象类指针&#x2F;引用可指向派生类对象</li><li>成员函数可调用纯虚函数；构造&#x2F;析构函数<strong>不能</strong>调用</li><li>派生类必须实现所有纯虚函数，否则仍为抽象类</li></ol><p><strong>示例</strong></p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-keyword">virtual</span> <span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">()</span> </span>= <span class="hljs-number">0</span>; <span class="hljs-comment">//纯虚函数</span><span class="hljs-built_in">A</span>( )&#123; &#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">g</span><span class="hljs-params">( )</span> </span>&#123; <span class="hljs-built_in">f</span>( ) ; &#125; <span class="hljs-comment">//等价this-&gt;f()，合法</span><span class="hljs-comment">//A()&#123; f(); &#125; 错误：构造函数不能调用纯虚函数</span>&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span> : <span class="hljs-keyword">public</span> A&#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">()</span></span>&#123; cout&lt;&lt;<span class="hljs-string">&quot;B:f()&quot;</span>&lt;&lt;endl ; &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;B b;b.<span class="hljs-built_in">g</span>( ); <span class="hljs-comment">//输出B:f()</span><span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>注意：构造函数调用纯虚函数，虚表无实现，程序崩溃</p><blockquote><p>抽象类不可以生成对象, 都包含纯虚函数,<strong>抽象类的纯虚函数可以有函数体</strong>,派生类可以调用抽象类的带函数体的纯虚函数,需要实例化纯虚函数后才可以生成对象,<strong>但是派生类还是要自己实现纯虚函数</strong></p></blockquote></blockquote><hr><h2 id="访问机制对比（隐藏-vs-虚函数）"><a href="#访问机制对比（隐藏-vs-虚函数）" class="headerlink" title="访问机制对比（隐藏 vs 虚函数）"></a>访问机制对比（隐藏 vs 虚函数）</h2><h3 id="隐藏"><a href="#隐藏" class="headerlink" title="隐藏"></a>隐藏</h3><p>由指针&#x2F;引用的<strong>类型</strong>决定调用：</p><ul><li>派生类指针→调用派生类同名函数</li><li>基类指针→调用基类同名函数（即使指向派生类）</li></ul><h3 id="虚函数-1"><a href="#虚函数-1" class="headerlink" title="虚函数"></a>虚函数</h3><p>由指针&#x2F;引用<strong>指向的对象类型</strong>决定调用：</p><ul><li>指向基类→调用基类虚函数</li><li>指向派生类→派生类虚函数</li></ul><hr><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ol><li><strong>虚函数和多态</strong>：基类定义接口，派生类实现；通过基类指针&#x2F;引用实现动态调用</li><li><strong>多态的作用</strong>：提升程序扩展性，新增功能无需修改原有执行代码</li><li><strong>多态的实现</strong>：依赖<strong>虚函数表+虚表指针</strong>，运行时动态查找函数</li><li><strong>访问权限</strong>：语法检查基于指针类型，基类虚函数建议设为public</li><li><strong>纯虚函数与抽象类</strong>：纯虚函数&#x3D;0；抽象类不能实例化，派生类必须实现所有纯虚函数</li><li><strong>虚函数调用</strong>：普通函数→动态联编；构造&#x2F;析构→静态联编</li><li><strong>虚析构函数</strong>：(如果一个类<strong>有任何虚函数</strong>，或者<strong>意图作为多态基类被继承</strong>)含虚函数的类必须定义虚析构，避免内存泄漏；构造函数不能为虚函数</li></ol><hr><h2 id="补充：函数指针与qsort库函数"><a href="#补充：函数指针与qsort库函数" class="headerlink" title="补充：函数指针与qsort库函数"></a>补充：函数指针与qsort库函数</h2><h3 id="函数指针-基本概念"><a href="#函数指针-基本概念" class="headerlink" title="函数指针-基本概念"></a>函数指针-基本概念</h3><p>函数名是函数的入口地址；指向函数的指针称为<strong>函数指针</strong>，可通过指针调用函数。</p><h3 id="⚠️函数指针-定义形式"><a href="#⚠️函数指针-定义形式" class="headerlink" title="⚠️函数指针-定义形式"></a>⚠️函数指针-定义形式</h3><pre><code class="hljs scss">类型名(*指针变量名)(参数类型<span class="hljs-number">1</span>, 参数类型<span class="hljs-number">2</span>, ...);</code></pre><ul><li>类型名：函数返回值类型</li><li>括号内：函数参数类型</li></ul><p>⚠️示例**：<code>int (*pf)(int, char);</code></p><h3 id="函数指针-使用方法"><a href="#函数指针-使用方法" class="headerlink" title="函数指针-使用方法"></a>函数指针-使用方法</h3><ol><li>用函数名给函数指针赋值</li><li><code>指针名(实参)</code>调用函数</li></ol><p><strong>示例</strong></p><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;stdio.h&gt;</span></span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintMin</span><span class="hljs-params">(<span class="hljs-type">int</span> a, <span class="hljs-type">int</span> b)</span></span>&#123;<span class="hljs-keyword">if</span>( a &lt; b ) <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%d&quot;</span>, a);<span class="hljs-keyword">else</span> <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%d&quot;</span>, b);&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;<span class="hljs-type">int</span> x = <span class="hljs-number">4</span>, y = <span class="hljs-number">5</span>;<span class="hljs-built_in">void</span> (* pf)(<span class="hljs-type">int</span>, <span class="hljs-type">int</span>);pf = PrintMin;<span class="hljs-built_in">pf</span>(x, y); <span class="hljs-comment">//输出4</span><span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h3 id="函数指针和qsort库函数"><a href="#函数指针和qsort库函数" class="headerlink" title="函数指针和qsort库函数"></a>函数指针和qsort库函数</h3><p>C快速排序函数，可排序任意类型数组：</p><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">qsort</span><span class="hljs-params">(<span class="hljs-type">void</span> *base, <span class="hljs-type">int</span> nelem, <span class="hljs-type">unsigned</span> <span class="hljs-type">int</span> width,</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-type">int</span> (* pfCompare)(<span class="hljs-type">const</span> <span class="hljs-type">void</span> *, <span class="hljs-type">const</span> <span class="hljs-type">void</span> *))</span></span>;</code></pre><p><strong>参数说明</strong>：</p><ol><li>base：数组首地址</li><li>nelem：元素个数</li><li>width：单个元素字节数</li><li>pfCompare：自定义比较函数指针</li></ol><h3 id="比较函数的要求"><a href="#比较函数的要求" class="headerlink" title="比较函数的要求"></a>比较函数的要求</h3><p>原型：<code>int 函数名(const void * elem1, const void * elem2);</code><br>返回值规则：</p><ol><li>elem1排在前 → 返回负数</li><li>相等 → 返回0</li><li>elem1排在后 → 返回正数</li></ol><h3 id="qsort使用示例"><a href="#qsort使用示例" class="headerlink" title="qsort使用示例"></a>qsort使用示例</h3><p>按数字个位数排序：</p><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;stdio.h&gt;</span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;stdlib.h&gt;</span></span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">MyCompare</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">void</span> * elem1, <span class="hljs-type">const</span> <span class="hljs-type">void</span> * elem2 )</span></span>&#123;<span class="hljs-type">unsigned</span> <span class="hljs-type">int</span> * p1 = (<span class="hljs-type">unsigned</span> <span class="hljs-type">int</span> *) elem1;<span class="hljs-type">unsigned</span> <span class="hljs-type">int</span> * p2 = (<span class="hljs-type">unsigned</span> <span class="hljs-type">int</span> *) elem2;<span class="hljs-keyword">return</span> (*p1 % <span class="hljs-number">10</span>) - (*p2 % <span class="hljs-number">10</span> );&#125;<span class="hljs-meta">#<span class="hljs-keyword">define</span> NUM 5</span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;<span class="hljs-type">unsigned</span> <span class="hljs-type">int</span> an[NUM] = &#123; <span class="hljs-number">8</span>, <span class="hljs-number">123</span>, <span class="hljs-number">11</span>, <span class="hljs-number">10</span>, <span class="hljs-number">4</span> &#125;;<span class="hljs-built_in">qsort</span>(an, NUM, <span class="hljs-built_in">sizeof</span>(<span class="hljs-type">unsigned</span> <span class="hljs-type">int</span>), MyCompare);<span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i &lt; NUM; i ++ )<span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%d &quot;</span>, an[i]); <span class="hljs-comment">//输出10 11 123 4 8</span><span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/88d0/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/88d0/"/>
    <published>2026-03-26T16:00:00.000Z</published>
    <summary>虚函数、多态与运行时动态绑定</summary>
    <title>多态与虚函数</title>
    <updated>2026-07-21T09:00:17.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="文件操作" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C/"/>
    <category term="输入输出" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E8%BE%93%E5%85%A5%E8%BE%93%E5%87%BA/"/>
    <content>
      <![CDATA[<h1 id="输入输出与文件操作"><a href="#输入输出与文件操作" class="headerlink" title="输入输出与文件操作"></a>输入输出与文件操作</h1><h2 id="比较重要的内容"><a href="#比较重要的内容" class="headerlink" title="比较重要的内容"></a>比较重要的内容</h2><pre><code class="hljs c++"><span class="hljs-type">int</span> x;<span class="hljs-keyword">while</span>(cin&gt;&gt;x)&#123;&#125;</code></pre><p>可见<code>istream</code>在其基类内重载了<code>operator bool</code></p><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyCin</span>&#123;    <span class="hljs-type">bool</span> stop;<span class="hljs-keyword">public</span>:    <span class="hljs-comment">// 重要的,初始值不停</span>    <span class="hljs-built_in">MyCin</span>() : <span class="hljs-built_in">stop</span>(<span class="hljs-literal">false</span>) &#123;&#125;    <span class="hljs-comment">// 重载bool</span>    <span class="hljs-function"><span class="hljs-keyword">operator</span> <span class="hljs-title">bool</span><span class="hljs-params">()</span></span>&#123;        <span class="hljs-keyword">return</span> !stop;    &#125;    <span class="hljs-comment">// 传入i引用,重载&gt;&gt;读取这个i</span>    MyCin&amp; <span class="hljs-keyword">operator</span>&gt;&gt;(<span class="hljs-type">int</span> &amp;i)&#123;        <span class="hljs-keyword">if</span>(stop) <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;        cin&gt;&gt;i;        <span class="hljs-keyword">if</span>(i==<span class="hljs-number">100</span>) stop=<span class="hljs-literal">true</span>;        <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;    &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    MyCin m;    <span class="hljs-type">int</span> x;    <span class="hljs-keyword">while</span>(m&gt;&gt;x)&#123;        cout&lt;&lt;x&lt;&lt;endl;    &#125;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p><strong>getline</strong></p><p><code>istream &amp; getline(char* buf,int bufsize,char delim);</code></p><p><code>delim</code>缺省,默认为<code>\n</code>,从输入流中读取(bufsize-1)个字符到缓冲区,或读到delim</p><ul><li>delim不会读入缓冲区,但会被输入流取走</li><li>达到或超出bufsize报错</li></ul><pre><code class="hljs c++"><span class="hljs-comment">// ■ getline读入字符个数超过了bufSize个</span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-type">char</span> buf1[<span class="hljs-number">5</span>], buf2[<span class="hljs-number">5</span>];    <span class="hljs-comment">// 第一次读取</span>    cin.<span class="hljs-built_in">getline</span>(buf1, <span class="hljs-number">5</span>, <span class="hljs-string">&#x27;\n&#x27;</span>);  <span class="hljs-comment">// 输入 &quot;abcdef\n&quot;</span>    <span class="hljs-comment">// 结果: buf1 = &quot;abcd&quot;, 流的状态标志 failbit 被置位</span>    <span class="hljs-comment">// 第二次读取 - 会失败!</span>    cin.<span class="hljs-built_in">getline</span>(buf2, <span class="hljs-number">5</span>, <span class="hljs-string">&#x27;\n&#x27;</span>);    <span class="hljs-comment">// 因为 failbit 已设置, 这次读取立即返回, 不读取任何内容</span>    <span class="hljs-comment">// buf2 内容不变, 可能保持未定义状态</span>    cout &lt;&lt; buf1 &lt;&lt; endl &lt;&lt; buf2 &lt;&lt; endl;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;<span class="hljs-comment">// 输入:</span><span class="hljs-comment">// abcdef</span><span class="hljs-comment">// 输出:</span><span class="hljs-comment">// abcd</span><span class="hljs-comment">// 输入:</span><span class="hljs-comment">// abc</span><span class="hljs-comment">// def</span><span class="hljs-comment">// 输出:</span><span class="hljs-comment">// abc</span><span class="hljs-comment">// def</span></code></pre><pre><code class="hljs c++"><span class="hljs-comment">// ■ 可以用 if(!cin.getline(...)) 判断输入是否结束</span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-type">char</span> name[<span class="hljs-number">10</span>];    cout &lt;&lt; <span class="hljs-string">&quot;请输入姓名: &quot;</span>;    <span class="hljs-keyword">if</span>(!cin.<span class="hljs-built_in">getline</span>(name, <span class="hljs-number">10</span>)) &#123;        cout &lt;&lt; <span class="hljs-string">&quot;读取失败! &quot;</span> &lt;&lt; endl;        cout &lt;&lt; <span class="hljs-string">&quot;可能原因: 输入过长或流出错&quot;</span> &lt;&lt; endl;    &#125; <span class="hljs-keyword">else</span> &#123;        cout &lt;&lt; <span class="hljs-string">&quot;读取成功, 姓名: &quot;</span> &lt;&lt; name &lt;&lt; endl;    &#125;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><pre><code class="hljs c++"><span class="hljs-comment">// 现代</span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;string&gt;</span></span>std::string line;std::<span class="hljs-built_in">getline</span>(cin, line);           <span class="hljs-comment">// 没有长度限制，自动管理内存</span>std::<span class="hljs-built_in">getline</span>(cin, line, <span class="hljs-string">&#x27;,&#x27;</span>);      <span class="hljs-comment">// 自定义分隔符</span></code></pre><blockquote><p><strong>istream 类的成员函数</strong></p><ul><li><code>bool eof();</code> — 判断输入流是否结束</li><li><code>int peek();</code> — 返回下一个字符，但不从流中去掉</li><li><code>istream &amp; putback(char c);</code> — 将字符 <code>c</code> 放回输入流</li><li><code>istream &amp; ignore(int nCount = 1, int delim = EOF);</code> — 从流中删掉最多 <code>nCount</code> 个字符，遇到 <code>EOF</code> 时结束</li></ul><hr><p><strong>getline 读到留在流中的 <code>&#39;\n&#39;</code> 就会返回</strong></p><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-type">int</span> x;    <span class="hljs-type">char</span> buf[<span class="hljs-number">100</span>];    cin &gt;&gt; x;    cin.<span class="hljs-built_in">getline</span>(buf, <span class="hljs-number">90</span>);    cout &lt;&lt; buf &lt;&lt; endl;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p>输入：</p><pre><code class="hljs basic"><span class="hljs-symbol">12 </span>abcd</code></pre><p>输出：</p><pre><code class="hljs ebnf"><span class="hljs-attribute">abcd</span></code></pre><p>（前面有一个空格，因为 <code>&gt;&gt;</code> 留下的空格还在流里）</p><p>输入：</p><pre><code class="hljs">12</code></pre><p>程序立即结束，无输出。（<code>getline</code> 直接读到了 <code>12</code> 后面的 <code>&#39;\n&#39;</code>）</p><blockquote><p><strong>istream 类的成员函数</strong></p><ul><li><code>bool eof();</code> — 判断输入流是否结束</li><li><code>int peek();</code> — 返回下一个字符，但不从流中去掉</li><li><code>istream &amp; putback(char c);</code> — 将字符 <code>c</code> 放回输入流</li><li><code>istream &amp; ignore(int nCount = 1, int delim = EOF);</code> — 从流中删掉最多 <code>nCount</code> 个字符，遇到 <code>EOF</code> 时结束</li></ul><hr><p><strong>getline 读到留在流中的 <code>&#39;\n&#39;</code> 就会返回</strong></p><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-type">int</span> x;    <span class="hljs-type">char</span> buf[<span class="hljs-number">100</span>];    cin &gt;&gt; x;    cin.<span class="hljs-built_in">getline</span>(buf, <span class="hljs-number">90</span>);    cout &lt;&lt; buf &lt;&lt; endl;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p>输入：</p><pre><code class="hljs basic"><span class="hljs-symbol">12 </span>abcd</code></pre><p>输出：</p><pre><code class="hljs ebnf"><span class="hljs-attribute">abcd</span></code></pre><p><strong>（前面有一个空格，因为 <code>&gt;&gt;</code> 留下的空格还在流里）</strong></p><p>输入：</p><pre><code class="hljs">12</code></pre><p>程序立即结束，无输出。（<code>getline</code> 直接读到了 <code>12</code> 后面的 <code>&#39;\n&#39;</code>）</p></blockquote></blockquote><ul><li><p>cin.width():  最大读取n-1个字符</p></li><li><p>cout默认右对齐</p></li><li><p>设置宽度是一次性的</p></li><li><p>流操纵器:</p><ul><li><p><code>cout &lt;&lt; tab</code> 不是把 <code>tab</code> 的”返回值”传给 <code>cout</code>，而是把 <code>tab</code> 这个”函数本身”传给 <code>cout</code>，让 <code>cout</code> 内部再调用它。</p></li><li><pre><code class="language-c++">ostream&amp; tab(ostream&amp; output) {    return output &lt;&lt; &#39;\t&#39;;}//重载内部等价于return (*p)(*this);   // 也就是 tab(cout)ostream&amp; operator&lt;&lt;(ostream&amp; (*p)(ostream&amp;));//                     ^^^^^^^^^^^^^^^^^//                     函数指针：接受ostream&amp;，返回ostream&amp;<pre><code class="hljs applescript">  - `cout &lt;&lt; <span class="hljs-string">&quot;aa&quot;</span> &lt;&lt; <span class="hljs-literal">tab</span> &lt;&lt; <span class="hljs-string">&quot;bb&quot;</span>;`- 默认是总有效位数, fixed是小数点后有效位数, scientific是科学计数法上小数点后有效位数<span class="hljs-comment">## 总览</span>```mermaidgraph LR    Root[C++ 输入输出与文件操作] <span class="hljs-comment">--&gt; S[标准IO流]</span>    Root <span class="hljs-comment">--&gt; M[流操纵算子]</span>    Root <span class="hljs-comment">--&gt; F[文件操作]</span>        %% 标准IO流    S <span class="hljs-comment">--&gt; C1[流类体系]</span>    S <span class="hljs-comment">--&gt; C2[标准流对象]</span>    S <span class="hljs-comment">--&gt; C3[重定向]</span>    C1 <span class="hljs-comment">--&gt; C11[ios -&gt; istream/ostream]</span>    C1 <span class="hljs-comment">--&gt; C12[cin ifstream / cout ofstream]</span>    C2 <span class="hljs-comment">--&gt; C21[cin  cout  cerr  clog]</span>    C3 <span class="hljs-comment">--&gt; C31[freopen 输入/输出重定向]</span>        %% 流操纵算子    M <span class="hljs-comment">--&gt; M1[头文件 iomanip]</span>    M <span class="hljs-comment">--&gt; M2[进制: dec hex oct]</span>    M <span class="hljs-comment">--&gt; M3[精度: fixed setprecision]</span>    M <span class="hljs-comment">--&gt; M4[域宽: setw 单次有效]</span>        %% 文件操作    F <span class="hljs-comment">--&gt; F1[头文件 fstream]</span>    F <span class="hljs-comment">--&gt; F2[打开模式: in out app binary]</span>    F <span class="hljs-comment">--&gt; F3[指针操作: seekg tellg seekp tellp]</span>    F <span class="hljs-comment">--&gt; F4[文本文件: &gt;&gt; &lt;&lt; 读写]</span>    F <span class="hljs-comment">--&gt; F5[二进制文件: read write 读写]</span></code></pre></code></pre></li></ul></li></ul><hr><h2 id="一、C-IO流类体系（基础核心）"><a href="#一、C-IO流类体系（基础核心）" class="headerlink" title="一、C++ IO流类体系（基础核心）"></a>一、C++ IO流类体系（基础核心）</h2><h3 id="1-流类继承关系（根类：ios）"><a href="#1-流类继承关系（根类：ios）" class="headerlink" title="1. 流类继承关系（根类：ios）"></a>1. 流类继承关系（根类：ios）</h3><pre><code class="hljs mermaid">graph TD    ios[&quot;ios（流基类）&quot;]    istream[&quot;istream（输入流类）&quot;]    ifstream[&quot;ifstream（文件输入流类，专用于读文件）&quot;]    ostream[&quot;ostream（输出流类）&quot;]    ofstream[&quot;ofstream（文件输出流类，专用于写文件）&quot;]    iostream[&quot;iostream（输入输出流类，同时继承istream+ostream）&quot;]    fstream[&quot;fstream（文件读写流类，可同时读写文件）&quot;]        ios --&gt; istream    istream --&gt;|&quot;全局对象cin&quot;| ifstream    ios --&gt; ostream    ostream --&gt;|&quot;全局对象cout/cerr/clog&quot;| ofstream    ios --&gt; iostream    iostream --&gt; fstream</code></pre><h3 id="2-标准流对象核心说明"><a href="#2-标准流对象核心说明" class="headerlink" title="2. 标准流对象核心说明"></a>2. 标准流对象核心说明</h3><table><thead><tr><th>对象</th><th>绑定设备</th><th>缓冲机制</th><th>核心用途</th><th>能否重定向</th></tr></thead><tbody><tr><td>cin</td><td>标准输入（键盘）</td><td>有缓冲</td><td>常规数据输入</td><td>可重定向到文件读取</td></tr><tr><td>cout</td><td>标准输出（屏幕）</td><td>有缓冲</td><td>常规数据输出</td><td>可重定向到文件写入</td></tr><tr><td>cerr</td><td>标准错误输出</td><td><strong>无缓冲</strong></td><td>紧急错误信息（程序崩溃也能正常输出）</td><td>不可重定向</td></tr><tr><td>clog</td><td>标准错误输出</td><td><strong>有缓冲</strong></td><td>非紧急运行日志（减少IO次数，性能更高）</td><td>不可重定向</td></tr></tbody></table><hr><h2 id="二、标准IO核心操作"><a href="#二、标准IO核心操作" class="headerlink" title="二、标准IO核心操作"></a>二、标准IO核心操作</h2><h3 id="1-输入-输出重定向"><a href="#1-输入-输出重定向" class="headerlink" title="1. 输入&#x2F;输出重定向"></a>1. 输入&#x2F;输出重定向</h3><h4 id="核心函数：freopen（头文件）"><a href="#核心函数：freopen（头文件）" class="headerlink" title="核心函数：freopen（头文件&lt;iostream&gt;）"></a>核心函数：<code>freopen</code>（头文件<code>&lt;iostream&gt;</code>）</h4><table><thead><tr><th>用法</th><th>核心功能</th></tr></thead><tbody><tr><td><code>freopen(&quot;文件名&quot;, &quot;r&quot;, stdin);</code></td><td>将标准输入cin重定向到指定文件，从文件读取数据</td></tr><tr><td><code>freopen(&quot;文件名&quot;, &quot;w&quot;, stdout);</code></td><td>将标准输出cout重定向到指定文件，向文件写入数据</td></tr></tbody></table><h4 id="最简示例"><a href="#最简示例" class="headerlink" title="最简示例"></a>最简示例</h4><pre><code class="hljs cpp"><span class="hljs-comment">// 输入重定向：从in.txt读取数据</span><span class="hljs-built_in">freopen</span>(<span class="hljs-string">&quot;in.txt&quot;</span>, <span class="hljs-string">&quot;r&quot;</span>, stdin); cin &gt;&gt; x &gt;&gt; y;<span class="hljs-comment">// 输出重定向：向out.txt写入数据</span><span class="hljs-built_in">freopen</span>(<span class="hljs-string">&quot;out.txt&quot;</span>, <span class="hljs-string">&quot;w&quot;</span>, stdout);cout &lt;&lt; x &lt;&lt; <span class="hljs-string">&quot; &quot;</span> &lt;&lt; y;</code></pre><h3 id="2-输入流结束判断"><a href="#2-输入流结束判断" class="headerlink" title="2. 输入流结束判断"></a>2. 输入流结束判断</h3><h4 id="标准写法：while-cin-x"><a href="#标准写法：while-cin-x" class="headerlink" title="标准写法：while(cin &gt;&gt; x)"></a>标准写法：<code>while(cin &gt;&gt; x)</code></h4><ul><li>底层原理：<code>&gt;&gt;</code>运算符返回istream对象，istream类重载了<code>operator bool</code>，流无效&#x2F;结束时返回false</li><li>结束触发条件：<ol><li>键盘输入：<strong>单独一行输入Ctrl+Z</strong>，标记输入流结束</li><li>文件输入：读取到文件末尾（EOF），流自动标记为结束</li></ol></li><li>扩展：可通过重载<code>operator&gt;&gt;</code>和<code>operator bool</code>实现自定义流的结束判断</li></ul><blockquote><h5 id="1-变量引用的本质"><a href="#1-变量引用的本质" class="headerlink" title="1. 变量引用的本质"></a>1. 变量引用的本质</h5><ul><li><strong>地址传递</strong>：<code>int &amp;n</code> 传入的是内存地址。函数获得了修改 <code>n1</code>、<code>n2</code> 的<strong>权限</strong>，但并不具备<strong>预知</strong>未来输入内容的能力。</li><li><strong>初始值陷阱</strong>：在执行 <code>cin &gt;&gt; n</code> 这一行指令之前，<code>n</code> 指向的内存空间里存放的是<strong>旧数据</strong>（上一次循环留下的值或随机值）。</li></ul><h5 id="2-旧版逻辑失效原因：时序错位"><a href="#2-旧版逻辑失效原因：时序错位" class="headerlink" title="2. 旧版逻辑失效原因：时序错位"></a>2. 旧版逻辑失效原因：时序错位</h5><p>C++</p><pre><code class="hljs scss">&gt;<span class="hljs-built_in">if</span>(n != -<span class="hljs-number">1</span>)  <span class="hljs-comment">// 步骤 A：判断旧数据</span>   cin &gt;&gt; n; <span class="hljs-comment">// 步骤 B：覆盖新数据</span></code></pre><ul><li><strong>逻辑断层</strong>：当输入 <code>-1</code> 时，由于步骤 A 使用的是旧值（非 <code>-1</code>），程序会执行步骤 B 将 <code>-1</code> 读入内存。但此时判断已经结束，<code>else</code> 分支里的 <code>stop = true</code> 无法被触发。</li><li><strong>滞后效应</strong>：<code>stop</code> 标志位的更新比输入流的变化<strong>慢了一个周期</strong>。</li></ul><h5 id="3-链式调用的“惯性”与“熔断”"><a href="#3-链式调用的“惯性”与“熔断”" class="headerlink" title="3. 链式调用的“惯性”与“熔断”"></a>3. 链式调用的“惯性”与“熔断”</h5><p>在 <code>while(m &gt;&gt; n1 &gt;&gt; n2)</code> 执行时：</p><ul><li><strong>惯性读取</strong>：读入 <code>n1 = -1</code> 后，因为 <code>stop</code> 仍为 <code>false</code>，程序会顺着指令链继续执行 <code>m &gt;&gt; n2</code>。</li><li><strong>输出溢出</strong>：当这一轮 <code>while</code> 条件执行完毕时，<code>n1</code> 和 <code>n2</code> 都已被新值覆盖，随后被 <code>cout</code> 打印，导致输出了本该拦截的 <code>-1</code> 和随后的数字。</li></ul><h5 id="4-正确的逻辑构造：先做后看"><a href="#4-正确的逻辑构造：先做后看" class="headerlink" title="4. 正确的逻辑构造：先做后看"></a>4. 正确的逻辑构造：先做后看</h5><p>严谨的实现必须确保：<strong>修改动作</strong>发生在<strong>状态判定</strong>之前。</p><ul><li><strong>逻辑顺序</strong>：</li></ul><ol><li><strong>检查熔断</strong>：<code>if(stop) return *this;</code>（若前一步已停止，立即拦截）。</li><li><strong>执行修改</strong>：<code>cin &gt;&gt; n;</code>（更新内存中的值）。</li><li><strong>同步状态</strong>：<code>if(n == -1) stop = true;</code>（根据刚读入的值更新标志）。</li></ol></blockquote><h3 id="3-istream核心成员函数（高频考点）"><a href="#3-istream核心成员函数（高频考点）" class="headerlink" title="3. istream核心成员函数（高频考点）"></a>3. istream核心成员函数（高频考点）</h3><h4 id="（1）getline：按行读取字符串"><a href="#（1）getline：按行读取字符串" class="headerlink" title="（1）getline：按行读取字符串"></a>（1）getline：按行读取字符串</h4><h5 id="函数原型"><a href="#函数原型" class="headerlink" title="函数原型"></a>函数原型</h5><pre><code class="hljs cpp"><span class="hljs-comment">// 读到换行符\n停止</span><span class="hljs-function">istream&amp; <span class="hljs-title">getline</span><span class="hljs-params">(<span class="hljs-type">char</span>* buf, <span class="hljs-type">int</span> bufSize)</span></span>;<span class="hljs-comment">// 读到自定义分隔符delim停止</span><span class="hljs-function">istream&amp; <span class="hljs-title">getline</span><span class="hljs-params">(<span class="hljs-type">char</span>* buf, <span class="hljs-type">int</span> bufSize, <span class="hljs-type">char</span> delim)</span></span>;</code></pre><h5 id="核心规则"><a href="#核心规则" class="headerlink" title="核心规则"></a>核心规则</h5><ul><li>最多读取<code>bufSize-1</code>个字符，<strong>自动在缓冲区末尾添加字符串结束符’\0’</strong></li><li>分隔符<code>\n</code>&#x2F;<code>delim</code>会从流中移除，但<strong>不会存入缓冲区</strong></li><li>若读取字符数超过bufSize，会置位流的<code>failbit</code>，<strong>后续所有读操作全部失效</strong></li></ul><h5 id="错误判断：if-cin-getline-→-读取失败-流结束时返回true"><a href="#错误判断：if-cin-getline-→-读取失败-流结束时返回true" class="headerlink" title="错误判断：if(!cin.getline(...)) → 读取失败&#x2F;流结束时返回true"></a>错误判断：<code>if(!cin.getline(...))</code> → 读取失败&#x2F;流结束时返回true</h5><h4 id="（2）其他常用成员函数"><a href="#（2）其他常用成员函数" class="headerlink" title="（2）其他常用成员函数"></a>（2）其他常用成员函数</h4><table><thead><tr><th>函数</th><th>核心功能</th></tr></thead><tbody><tr><td><code>bool eof();</code></td><td>判断输入流是否到达文件末尾（EOF）</td></tr><tr><td><code>int peek();</code></td><td>返回流中下一个字符，<strong>不从流中移除</strong>（仅“偷窥”）</td></tr><tr><td><code>istream&amp; putback(char c);</code></td><td>将字符c放回输入流的开头</td></tr><tr><td><code>istream&amp; ignore(int n=1, int delim=EOF);</code></td><td>跳过流中最多n个字符，遇到delim提前停止</td></tr></tbody></table><h4 id="（3）getline高频坑点"><a href="#（3）getline高频坑点" class="headerlink" title="（3）getline高频坑点"></a>（3）getline高频坑点</h4><p><code>cin &gt;&gt; x</code> 读取完成后，会在流中残留换行符<code>\n</code>，后续调用<code>getline</code>会直接读取空行，需先用<code>ignore()</code>清除残留换行。</p><hr><h2 id="三、流操纵算子（格式化输入输出）"><a href="#三、流操纵算子（格式化输入输出）" class="headerlink" title="三、流操纵算子（格式化输入输出）"></a>三、流操纵算子（格式化输入输出）</h2><blockquote><p>必须包含头文件：<code>&lt;iomanip&gt;</code></p></blockquote><h3 id="1-整数基数控制"><a href="#1-整数基数控制" class="headerlink" title="1. 整数基数控制"></a>1. 整数基数控制</h3><table><thead><tr><th>算子</th><th>功能</th></tr></thead><tbody><tr><td>dec</td><td>十进制输出（默认格式）</td></tr><tr><td>oct</td><td>八进制输出</td></tr><tr><td>hex</td><td>十六进制输出</td></tr><tr><td>setbase(n)</td><td>指定输出基数（仅支持8&#x2F;10&#x2F;16）</td></tr></tbody></table><h3 id="2-浮点数精度控制（核心考点）"><a href="#2-浮点数精度控制（核心考点）" class="headerlink" title="2. 浮点数精度控制（核心考点）"></a>2. 浮点数精度控制（核心考点）</h3><h4 id="核心工具"><a href="#核心工具" class="headerlink" title="核心工具"></a>核心工具</h4><ul><li>成员函数：<code>cout.precision(n);</code></li><li>流操纵算子：<code>cout &lt;&lt; setprecision(n);</code></li><li>两者功能完全一致，算子支持链式连续输出</li></ul><h4 id="精度含义规则（与输出格式强绑定）"><a href="#精度含义规则（与输出格式强绑定）" class="headerlink" title="精度含义规则（与输出格式强绑定）"></a>精度含义规则（与输出格式强绑定）</h4><table><thead><tr><th>输出格式</th><th>控制算子</th><th>setprecision(n)的含义</th></tr></thead><tbody><tr><td>默认格式（defaultfloat）</td><td>无&#x2F;resetiosflags</td><td>n &#x3D; 总有效数字位数</td></tr><tr><td>定点格式（fixed）</td><td>setiosflags(ios::fixed) &#x2F; fixed</td><td>n &#x3D; 小数点后保留位数</td></tr><tr><td>科学计数格式（scientific）</td><td>setiosflags(ios::scientific) &#x2F; scientific</td><td>n &#x3D; 小数点后保留位数</td></tr></tbody></table><h4 id="核心规则-1"><a href="#核心规则-1" class="headerlink" title="核心规则"></a>核心规则</h4><ul><li>小数截短显示时，<strong>自动执行四舍五入</strong></li><li>格式取消：<code>resetiosflags(ios::fixed/ios::scientific)</code></li></ul><h3 id="3-域宽设置（setw-width）"><a href="#3-域宽设置（setw-width）" class="headerlink" title="3. 域宽设置（setw &#x2F; width）"></a>3. 域宽设置（setw &#x2F; width）</h3><h4 id="核心用法"><a href="#核心用法" class="headerlink" title="核心用法"></a>核心用法</h4><ul><li>成员函数：<code>cin.width(n);</code> &#x2F; <code>cout.width(n);</code></li><li>流操纵算子：<code>cin &gt;&gt; setw(n);</code> &#x2F; <code>cout &lt;&lt; setw(n);</code></li></ul><h4 id="核心规则-2"><a href="#核心规则-2" class="headerlink" title="核心规则"></a>核心规则</h4><ul><li>域宽设置<strong>仅对下一次读写操作有效</strong>，每次读写前必须重新设置</li><li>输入时：最多读取<code>n-1</code>个字符（预留<code>\0</code>的存储位置）</li><li>无参<code>width()</code>：返回当前的域宽值</li></ul><h3 id="4-用户自定义流操纵算子"><a href="#4-用户自定义流操纵算子" class="headerlink" title="4. 用户自定义流操纵算子"></a>4. 用户自定义流操纵算子</h3><h4 id="定义规则"><a href="#定义规则" class="headerlink" title="定义规则"></a>定义规则</h4><p>返回值和参数均为<code>ostream&amp;</code>的函数，示例：</p><pre><code class="hljs cpp"><span class="hljs-comment">// 自定义制表符算子</span><span class="hljs-function">ostream&amp; <span class="hljs-title">tab</span><span class="hljs-params">(ostream&amp; output)</span></span>&#123;    <span class="hljs-keyword">return</span> output &lt;&lt; <span class="hljs-string">&#x27;\t&#x27;</span>;&#125;<span class="hljs-comment">// 使用方式：cout &lt;&lt; &quot;a&quot; &lt;&lt; tab &lt;&lt; &quot;b&quot; &lt;&lt; endl;</span></code></pre><h4 id="底层原理"><a href="#底层原理" class="headerlink" title="底层原理"></a>底层原理</h4><p>ostream重载了<code>&lt;&lt;</code>运算符，支持接收函数指针，会自动调用传入的函数，并将流对象本身作为参数传入。</p><hr><h2 id="四、文件IO操作（核心应用）"><a href="#四、文件IO操作（核心应用）" class="headerlink" title="四、文件IO操作（核心应用）"></a>四、文件IO操作（核心应用）</h2><blockquote><p>必须包含头文件：<code>&lt;fstream&gt;</code></p></blockquote><h3 id="1-文件打开与关闭"><a href="#1-文件打开与关闭" class="headerlink" title="1. 文件打开与关闭"></a>1. 文件打开与关闭</h3><h4 id="（1）两种打开方式"><a href="#（1）两种打开方式" class="headerlink" title="（1）两种打开方式"></a>（1）两种打开方式</h4><table><thead><tr><th>方式</th><th>示例</th></tr></thead><tbody><tr><td>构造对象时直接打开</td><td><code>ofstream outFile(&quot;test.txt&quot;, ios::out|ios::binary);</code></td></tr><tr><td>先创建对象，再用open打开</td><td><code>ofstream fout; fout.open(&quot;test.txt&quot;, ios::out);</code></td></tr></tbody></table><h4 id="（2）常用打开模式"><a href="#（2）常用打开模式" class="headerlink" title="（2）常用打开模式"></a>（2）常用打开模式</h4><table><thead><tr><th>模式</th><th>核心功能</th></tr></thead><tbody><tr><td>ios::in</td><td>只读模式打开（ifstream默认模式）</td></tr><tr><td>ios::out</td><td>只写模式打开，<strong>清空原有内容</strong>（ofstream默认模式）</td></tr><tr><td>ios::app</td><td>追加模式，保留原有内容，始终在文件尾部写入</td></tr><tr><td>ios::ate</td><td>打开后文件指针定位到尾部，可在文件任意位置写入</td></tr><tr><td>ios::binary</td><td>二进制模式打开，不执行换行符自动转换</td></tr></tbody></table><h4 id="（3）打开成功判断"><a href="#（3）打开成功判断" class="headerlink" title="（3）打开成功判断"></a>（3）打开成功判断</h4><pre><code class="hljs cpp"><span class="hljs-keyword">if</span>(!fout)&#123; <span class="hljs-comment">// 流对象返回false，代表打开失败</span>    cerr &lt;&lt; <span class="hljs-string">&quot;文件打开失败！&quot;</span> &lt;&lt; endl;    <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;&#125;</code></pre><h4 id="（4）文件关闭"><a href="#（4）文件关闭" class="headerlink" title="（4）文件关闭"></a>（4）文件关闭</h4><p>文件使用完毕必须显式关闭，释放系统资源：</p><pre><code class="hljs cpp">fin.<span class="hljs-built_in">close</span>();fout.<span class="hljs-built_in">close</span>();</code></pre><h3 id="2-文件读写指针操作"><a href="#2-文件读写指针操作" class="headerlink" title="2. 文件读写指针操作"></a>2. 文件读写指针操作</h3><table><thead><tr><th>指针类型</th><th>适用流</th><th>核心函数</th><th>功能</th></tr></thead><tbody><tr><td>读指针</td><td>ifstream&#x2F;fstream</td><td><code>tellg()</code></td><td>获取读指针当前位置（字节数）</td></tr><tr><td></td><td></td><td><code>seekg(偏移量, 基准位置)</code></td><td>移动读指针到指定位置</td></tr><tr><td>写指针</td><td>ofstream&#x2F;fstream</td><td><code>tellp()</code></td><td>获取写指针当前位置（字节数）</td></tr><tr><td></td><td></td><td><code>seekp(偏移量, 基准位置)</code></td><td>移动写指针到指定位置</td></tr></tbody></table><h4 id="基准位置参数"><a href="#基准位置参数" class="headerlink" title="基准位置参数"></a>基准位置参数</h4><ul><li><code>ios::beg</code>：文件开头（默认基准）</li><li><code>ios::cur</code>：指针当前位置</li><li><code>ios::end</code>：文件尾部</li><li>偏移量支持负数（代表向前移动）</li></ul><h3 id="3-文本文件读写"><a href="#3-文本文件读写" class="headerlink" title="3. 文本文件读写"></a>3. 文本文件读写</h3><ul><li>文本文件流的用法与cin&#x2F;cout完全一致，所有流操纵算子、&gt;&gt;&#x2F;&lt;&lt;运算符均适用</li><li>典型场景：从文本文件读取数据、处理后写入另一个文本文件（如整数排序、文本拷贝）</li></ul><h3 id="4-二进制文件读写（核心考点）"><a href="#4-二进制文件读写（核心考点）" class="headerlink" title="4. 二进制文件读写（核心考点）"></a>4. 二进制文件读写（核心考点）</h3><h4 id="核心函数"><a href="#核心函数" class="headerlink" title="核心函数"></a>核心函数</h4><table><thead><tr><th>函数</th><th>标准用法</th></tr></thead><tbody><tr><td>write（写）</td><td><code>fout.write((const char*)&amp;变量地址, sizeof(变量类型));</code></td></tr><tr><td>read（读）</td><td><code>fin.read((char*)&amp;变量地址, sizeof(变量类型));</code></td></tr></tbody></table><h4 id="辅助函数"><a href="#辅助函数" class="headerlink" title="辅助函数"></a>辅助函数</h4><p><code>gcount()</code>：返回最近一次<code>read</code>操作实际读取的字节数</p><h4 id="核心特性"><a href="#核心特性" class="headerlink" title="核心特性"></a>核心特性</h4><ul><li>直接读写内存中的二进制数据，无格式转换，记事本打开为乱码</li><li>适用于结构体&#x2F;类对象的批量读写，效率高、无精度损失</li><li>必须配合<code>ios::binary</code>模式打开文件</li></ul><h3 id="5-文本文件-vs-二进制文件（高频考点）"><a href="#5-文本文件-vs-二进制文件（高频考点）" class="headerlink" title="5. 文本文件 vs 二进制文件（高频考点）"></a>5. 文本文件 vs 二进制文件（高频考点）</h3><h4 id="换行符系统差异"><a href="#换行符系统差异" class="headerlink" title="换行符系统差异"></a>换行符系统差异</h4><table><thead><tr><th>系统</th><th>换行符</th><th>ASCII码</th></tr></thead><tbody><tr><td>Linux&#x2F;Unix</td><td><code>\n</code></td><td>0x0a</td></tr><tr><td>Windows</td><td><code>\r\n</code></td><td>0x0d 0x0a</td></tr><tr><td>Mac OS</td><td><code>\r</code></td><td>0x0d</td></tr></tbody></table><h4 id="打开模式差异"><a href="#打开模式差异" class="headerlink" title="打开模式差异"></a>打开模式差异</h4><table><thead><tr><th>系统</th><th>文本模式（无ios::binary）</th><th>二进制模式（ios::binary）</th></tr></thead><tbody><tr><td>Linux&#x2F;Unix</td><td>无任何转换，与二进制模式无区别</td><td>无任何转换，按原始字节读写</td></tr><tr><td>Windows</td><td>读：自动将<code>\r\n</code>转为<code>\n</code>（少读1字节）<br>写：自动将<code>\n</code>转为<code>\r\n</code>（多写1字节）</td><td>无任何转换，按原始字节读写</td></tr></tbody></table><hr><h2 id="五、注意点"><a href="#五、注意点" class="headerlink" title="五、注意点"></a>五、注意点</h2><ol><li><strong>getline坑点</strong>：<code>cin &gt;&gt;</code>后残留的<code>\n</code>会导致getline直接读取空行，需用<code>cin.ignore()</code>清除换行符</li><li><strong>setw单次有效</strong>：域宽设置仅对下一次读写生效，每次使用前必须重新设置</li><li><strong>流failbit置位</strong>：getline读取溢出、读取出错会置位failbit，后续所有流操作全部失效，需用<code>cin.clear()</code>重置流状态</li><li><strong>Windows换行转换</strong>：二进制读写必须添加<code>ios::binary</code>，否则会因换行符自动转换导致文件读写异常</li><li><strong>文件关闭要求</strong>：文件打开使用后必须显式调用<code>close()</code>，否则会导致资源泄漏，其他程序无法操作该文件</li><li><strong>cerr不可重定向</strong>：错误信息必须用cerr输出，避免cout重定向后，错误信息无法在屏幕显示</li><li><strong>二进制读写强制转换</strong>：write&#x2F;read的第一个参数必须强制转为<code>char*</code>&#x2F;<code>const char*</code>，否则会编译报错</li></ol>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/a1e2/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/a1e2/"/>
    <published>2026-03-26T16:00:00.000Z</published>
    <summary>C++输入输出流与文件操作</summary>
    <title>输入输出与文件操作</title>
    <updated>2026-07-21T09:01:08.797Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="继承" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%BB%A7%E6%89%BF/"/>
    <category term="派生" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E6%B4%BE%E7%94%9F/"/>
    <content>
      <![CDATA[<h1 id="继承与派生"><a href="#继承与派生" class="headerlink" title="继承与派生"></a>继承与派生</h1><h2 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h2><ul><li><a href="#%E5%9F%BA%E7%B1%BB%E5%92%8C%E6%B4%BE%E7%94%9F%E7%B1%BB">基类和派生类</a><ul><li><a href="#%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5">基本概念</a></li><li><a href="#%E8%8C%83%E5%BC%8F">范式</a></li><li><a href="#%E5%9C%BA%E6%99%AF">场景</a></li><li><a href="#%E4%BE%8B%E5%AD%90">例子</a></li></ul></li><li><a href="#%E6%B4%BE%E7%94%9F%E7%B1%BB%E7%9A%84%E6%88%90%E5%91%98%E7%BB%84%E6%88%90%E5%92%8C%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90">派生类的成员组成和访问权限</a><ul><li><a href="#%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90%E8%AF%B4%E6%98%8E%E7%AC%A6protected">访问权限说明符：protected</a></li><li><a href="#%E4%B8%89%E7%A7%8D%E7%BB%A7%E6%89%BF%E6%96%B9%E5%BC%8F">三种继承方式</a></li></ul></li><li><a href="#%E6%B4%BE%E7%94%9F%E7%B1%BB%E7%9A%84%E6%9E%84%E9%80%A0%E5%92%8C%E6%9E%90%E6%9E%84">派生类的构造和析构</a><ul><li><a href="#%E6%B4%BE%E7%94%9F%E7%B1%BB%E7%9A%84%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0">派生类的构造函数</a></li><li><a href="#%E5%8C%85%E5%90%AB%E6%88%90%E5%91%98%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%B4%BE%E7%94%9F%E7%B1%BB%E7%9A%84%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0">包含成员对象的派生类的构造函数</a></li><li><a href="#public%E7%BB%A7%E6%89%BF%E7%9A%84%E8%B5%8B%E5%80%BC%E5%85%BC%E5%AE%B9%E5%8E%9F%E5%88%99">public继承的赋值兼容原则</a></li></ul></li><li><a href="#%E6%B4%BE%E7%94%9F%E7%B1%BB%E4%B8%8E%E5%9F%BA%E7%B1%BB%E7%9A%84%E6%8C%87%E9%92%88%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2">派生类与基类的指针类型转换</a><ul><li><a href="#%E5%9F%BA%E7%B1%BB%E4%B8%8E%E6%B4%BE%E7%94%9F%E7%B1%BB%E5%BC%BA%E5%88%B6%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2">基类与派生类强制类型转换</a></li><li><a href="#%E7%9B%B4%E6%8E%A5%E5%9F%BA%E7%B1%BB%E4%B8%8E%E9%97%B4%E6%8E%A5%E5%9F%BA%E7%B1%BB">直接基类与间接基类</a></li></ul></li><li><a href="#%E5%A4%9A%E7%BB%A7%E6%89%BF%E8%80%83%E8%AF%95%E4%B8%8D%E8%A6%81%E6%B1%82%E4%B8%8D%E8%BF%87%E6%9C%89%E7%82%B9%E5%8A%A9%E4%BA%8E%E8%BF%9B%E4%B8%80%E6%AD%A5%E7%90%86%E8%A7%A3">多继承（拓展）</a><ul><li><a href="#%E5%A4%9A%E7%BB%A7%E6%89%BF%E7%9A%84%E6%B4%BE%E7%94%9F%E7%B1%BB%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0">多继承的派生类构造函数</a></li><li><a href="#%E5%A4%9A%E7%BB%A7%E6%89%BF%E4%B8%AD%E5%9F%BA%E7%B1%BB%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9A%84%E9%87%8D%E5%A4%8D%E8%B0%83%E7%94%A8">多继承中基类构造函数的重复调用</a></li><li><a href="#%E5%A4%9A%E9%87%8D%E7%BB%A7%E6%89%BF%E7%9A%84%E4%BA%8C%E4%B9%89%E6%80%A7%E9%97%AE%E9%A2%98">多重继承的二义性问题</a></li></ul></li></ul><h2 id="基类和派生类"><a href="#基类和派生类" class="headerlink" title="基类和派生类"></a>基类和派生类</h2><h3 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h3><ul><li><p>定义新类B时<strong>B拥有</strong>某个已有的类<strong>A的全部特点（成员）</strong></p><p>称A-<strong>基类（父类）</strong>，B-<strong>派生类（子类）</strong></p><ul><li><strong>派生类</strong>是<strong>对基类</strong>进行<strong>修改</strong>和<strong>扩充</strong>得到的</li><li>扩充：<strong>添加</strong>新成员</li><li>修改：<strong>重新编写</strong>继承来的成员</li></ul></li><li><p>派生类一经定义，可以独立使用，不依赖于基类</p></li><li><p>内存空间：基类对象大小+派生类对象自己的成员变量大小（基类对象存储位置在新增之前）</p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260321150856082.png" alt="image-20260321150856082"></p></li><li><p>在派生类中访问基类<strong>同名成员</strong>（叫“<strong>隐藏</strong>”或“覆盖”）利用<code>基类::变量名</code>访问，缺省情况下访问的是<strong>派生类的成员</strong></p></li></ul><h3 id="范式"><a href="#范式" class="headerlink" title="范式"></a>范式</h3><pre><code class="hljs c++"><span class="hljs-keyword">class</span> 派生类名 : 派生说明方式符 基类名&#123;    ...&#125;</code></pre><blockquote><p>派生类的各个成员函数不得访问基类中的private成员</p><p>派生说明方式符：public&#x2F;private&#x2F;protected</p></blockquote><h3 id="场景"><a href="#场景" class="headerlink" title="场景"></a>场景</h3><p>学生（基类）→中学生&#x2F;大学生&#x2F;小鞋生&#x2F;研究生</p><ul><li><p>共同属性：姓名、学号、性别、成绩</p></li><li><p>特有：大学专业，研究生导师，中学生竞赛</p></li></ul><h3 id="例子"><a href="#例子" class="headerlink" title="例子"></a>例子</h3><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">CStudent</span>&#123;<span class="hljs-keyword">private</span>:string sName;<span class="hljs-type">int</span> nAge;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">IsThreeGood</span><span class="hljs-params">()</span></span>&#123;&#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">SetName</span><span class="hljs-params">(<span class="hljs-type">const</span> string &amp;name)</span></span>&#123;sName=name;&#125;<span class="hljs-comment">// ...</span>&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CUndergraduateStudent</span> : <span class="hljs-keyword">public</span> CStudent&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> nDepartment;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">IsThreeGood</span><span class="hljs-params">()</span></span>&#123;...&#125; <span class="hljs-comment">//派生类同名函数将隐藏基类函数（不建议）</span>    <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">Membergroup</span><span class="hljs-params">()</span></span>&#123;...&#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CGraduateStudent</span> : <span class="hljs-keyword">public</span> CStudent&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> nDepartment;    <span class="hljs-type">char</span> SupervisorName[<span class="hljs-number">20</span>];<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">CountSalary</span><span class="hljs-params">()</span></span>&#123;...&#125;&#125;</code></pre><blockquote><h3 id="继承与复合的区别："><a href="#继承与复合的区别：" class="headerlink" title="继承与复合的区别："></a>继承与复合的区别：</h3><p>复合：有（B里有A）</p><p>继承：“是”且更多（B是A（及其延伸））</p><h4 id="复合关系避免循环定义"><a href="#复合关系避免循环定义" class="headerlink" title="复合关系避免循环定义"></a>复合关系避免循环定义</h4><p>⚠️ 避免循环定义，<strong>设置对象指针数组</strong></p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260321151339649.png" alt="image-20260321151339649"></p></blockquote><h2 id="派生类的成员组成和访问权限"><a href="#派生类的成员组成和访问权限" class="headerlink" title="派生类的成员组成和访问权限"></a>派生类的成员组成和访问权限</h2><h3 id="访问权限说明符：protected"><a href="#访问权限说明符：protected" class="headerlink" title="访问权限说明符：protected"></a>访问权限说明符：protected</h3><p>protected可访问范围介于<strong>private成员和public成员之间</strong></p><p>⚠️ <strong>派生类的成员和友元函数</strong>可以访问<code>当前对象</code>的来自<code>基类</code>的<strong>保护成员</strong></p><p>（此处有个话术：应该是可以访问<strong>自己&#x2F;自己的亲兄弟（同类对象）<strong>的爸爸</strong>传下来的保护成员</strong>，条件是同一个爸爸的下的同一个类，结果在传下来的同一个类的兄弟或者我的保护成员）</p><p>自己的这个类的子孙的对象也可</p><blockquote><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">protected</span>:    <span class="hljs-type">int</span> x;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">D1</span> : <span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f</span><span class="hljs-params">(D1&amp; other)</span> </span>&#123; other.x = <span class="hljs-number">1</span>; &#125;        <span class="hljs-comment">// ✅ OK：同类对象</span>    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">f2</span><span class="hljs-params">(D1* child)</span> </span>&#123; child-&gt;x = <span class="hljs-number">1</span>; &#125;      <span class="hljs-comment">// ✅ OK：D1 的派生类对象</span>    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">g</span><span class="hljs-params">(Base&amp; b)</span> </span>&#123; <span class="hljs-comment">/* b.x = 1; */</span> &#125;         <span class="hljs-comment">// ❌ ERROR：基类对象</span>&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">D2</span> : <span class="hljs-keyword">public</span> Base &#123;    <span class="hljs-comment">// D2 也是 Base 的儿子</span>&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">D1</span> &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">h</span><span class="hljs-params">(D2&amp; d2)</span> </span>&#123; <span class="hljs-comment">/* d2.x = 1; */</span> &#125;        <span class="hljs-comment">// ❌ ERROR！</span>    <span class="hljs-comment">// D2 和 D1 都是 Base 的派生类，但彼此无关</span>&#125;;</code></pre></blockquote><ul><li><strong>this指针指向的对象</strong></li><li>也可以访问<code>其他同类对象</code>的来自<code>基类</code>的<strong>保护成员</strong></li><li>main函数可以理解为全局函数，<strong>不可以</strong>访问保护成员</li></ul><h4 id="具体可以参见下面这个例子"><a href="#具体可以参见下面这个例子" class="headerlink" title="具体可以参见下面这个例子"></a>具体可以参见下面这个例子</h4><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260323193114346.png" alt="image-20260323193114346"></p><p>尤其是这个👇</p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260323193154033.png" alt="image-20260323193154033"></p><h3 id="三种继承方式"><a href="#三种继承方式" class="headerlink" title="三种继承方式"></a>三种继承方式</h3><p><strong>⚠️ 继承来的私有成员仍都是私有的，且都是派生类直接不可访问的！只能通过基类的public接口或者protected接口访问！</strong>（<del>虽然真的很怪</del>）</p><ul><li><p>公有继承：保持原样</p></li><li><p>私有继承：全部私有（“孙”类访问不了）</p></li><li><p>保护继承：公有变保护，其余不变</p></li></ul><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> secret = <span class="hljs-number">42</span>;<span class="hljs-keyword">protected</span>:    <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">getSecret</span><span class="hljs-params">()</span> </span>&#123; <span class="hljs-keyword">return</span> secret; &#125; <span class="hljs-comment">// 提供给子类的合法通道</span>&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">test</span><span class="hljs-params">()</span> </span>&#123;        <span class="hljs-comment">// secret = 10;       // 错误！编译器报错：不可访问</span>        <span class="hljs-type">int</span> val = <span class="hljs-built_in">getSecret</span>(); <span class="hljs-comment">// 正确！通过受保护接口访问</span>    &#125;&#125;;</code></pre><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260323194827354.png" alt="image-20260323194827354"></p><blockquote><p>一级警报：⚠️⚠️派生类自身的成员函数<strong>不能访问</strong>自己<strong>继承来的私有成员变量</strong>，<strong>但</strong>是派生类<strong>能访问自己私有继承</strong>来的<strong>公有和保护成员</strong>（哭笑不得）</p><p>想访问自己继承来的私有成员变量，要间接，即通过例如：<strong>继承来的基类的public接口或者protected接口</strong>访问！</p></blockquote><h2 id="派生类的构造和析构"><a href="#派生类的构造和析构" class="headerlink" title="派生类的构造和析构"></a>派生类的构造和析构</h2><h3 id="派生类的构造函数"><a href="#派生类的构造函数" class="headerlink" title="派生类的构造函数"></a>派生类的构造函数</h3><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Bug</span>&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> nLegs;    <span class="hljs-type">int</span> nColor;<span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> nType;    <span class="hljs-built_in">Bug</span>(<span class="hljs-type">int</span> legs,<span class="hljs-type">int</span> color);    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintBug</span><span class="hljs-params">()</span></span>&#123;&#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">FlyBug</span>:<span class="hljs-keyword">public</span> Bug&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> nWings;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">FlyBug</span>(<span class="hljs-type">int</span> legs,<span class="hljs-type">int</span> color,<span class="hljs-type">int</span> wings);&#125;;Bug::<span class="hljs-built_in">Bug</span>(<span class="hljs-type">int</span> legs,<span class="hljs-type">int</span> color)&#123;    nLegs=legs;    nColor=color;&#125;<span class="hljs-comment">// 错误！不能自己碰基类继承来的私有成员</span><span class="hljs-comment">// FlyBug::FlyBug(int legs,int color,int wings)&#123;</span><span class="hljs-comment">//nLegs=legs; //error!</span><span class="hljs-comment">//nColor=color; //error!</span><span class="hljs-comment">//nType=1; //ok</span><span class="hljs-comment">//nWings=wings;</span><span class="hljs-comment">//&#125;</span><span class="hljs-comment">//正确如下,调用基类的构造函数</span>FlyBug::<span class="hljs-built_in">FlyBug</span>(<span class="hljs-type">int</span> legs,<span class="hljs-type">int</span> color,<span class="hljs-type">int</span> wings):<span class="hljs-built_in">Bug</span>(legs,color)&#123;    nType=<span class="hljs-number">1</span>; <span class="hljs-comment">//⚠️一定不能放到初始化列表,只能通过赋值或者基类初始化</span>    nWings=wings;<span class="hljs-comment">// 可以放到初始化列表</span>&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    <span class="hljs-function">FlyBug <span class="hljs-title">fb</span><span class="hljs-params">(<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>)</span></span>;    fb.<span class="hljs-built_in">PrintBug</span>();    fb.nType=<span class="hljs-number">1</span>;    fb.nLegs=<span class="hljs-number">2</span>; <span class="hljs-comment">//error!</span>    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p>因此；</p><ul><li>创建<strong>派生类对象</strong>，需要调用<strong>基类的构造函数</strong><ul><li>初始化<strong>从基类继承来的成员</strong></li><li><strong>总是先执行基类的构造函数</strong>（析构时则相反，与封闭类类似，<del>脱白大褂再迎来生命的终结</del>）</li></ul></li><li>调用方式：<ul><li>显示构造（如上例）</li><li>隐式：缺省情况下默认调用基类的默认构造函数</li></ul></li></ul><h3 id="包含成员对象的派生类的构造函数"><a href="#包含成员对象的派生类的构造函数" class="headerlink" title="包含成员对象的派生类的构造函数"></a>包含成员对象的派生类的构造函数</h3><p><img src="https://cdn.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260323200921209.png" alt="image-20260323200921209"></p><p>顺序分别同，自推不难</p><h3 id="⚠️考点：public继承的赋值兼容原则"><a href="#⚠️考点：public继承的赋值兼容原则" class="headerlink" title="⚠️考点：public继承的赋值兼容原则"></a>⚠️考点：public继承的赋值兼容原则</h3><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">base</span>&#123;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">derived</span> : <span class="hljs-keyword">public</span> base&#123;&#125;;base b;derived d;</code></pre><ul><li><p>⚠️ 派生类的对象可以<strong>赋值给基类对象</strong></p><p><code>b=d</code></p></li><li><p>⚠️ 派生类对象可以<strong>初始化基类引用</strong></p></li></ul><p>  <code>base &amp; br=d;</code></p><ul><li>⚠️ 派生类对象<strong>的地址</strong>可以<strong>赋值给基类指针</strong>（更详细参见后文）</li></ul><p>  <code>base *pb=&amp; d;</code></p><blockquote><p>⚠️private&#x2F;protected继承<strong>无</strong>上述操作</p></blockquote><blockquote><p>基类指针<strong>不能</strong>访问基类的私有成员，无论它指向的是基类对象还是派生类对象。</p><p>访问控制是<strong>静态的、基于类定义</strong>的，与指针类型无关：</p><table><thead><tr><th>访问场景</th><th>能否访问基类 <code>private</code></th></tr></thead><tbody><tr><td>外部代码通过 <code>Base*</code></td><td>❌</td></tr><tr><td>外部代码通过 <code>Derived*</code></td><td>❌</td></tr><tr><td>派生类成员函数中通过 <code>Base*</code></td><td>❌</td></tr><tr><td>派生类成员函数中通过 <code>this</code>（<code>Derived*</code>）</td><td>❌</td></tr><tr><td><strong>基类自己的成员函数中</strong></td><td>✅</td></tr></tbody></table><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;    <span class="hljs-type">int</span> private_val;        <span class="hljs-comment">// private</span><span class="hljs-keyword">protected</span>:    <span class="hljs-type">int</span> protected_val;<span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> public_val;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> Base &#123;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    Derived d;    Base* p = &amp;d;        <span class="hljs-comment">// p-&gt;private_val = 1;      // ❌ 编译错误！</span>    <span class="hljs-comment">// p-&gt;protected_val = 1;    // ❌ 外部也不能访问 protected</span>    p-&gt;public_val = <span class="hljs-number">1</span>;          <span class="hljs-comment">// ✅ 只能访问 public</span>&#125;</code></pre><p>即使在派生类内部：</p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">func</span><span class="hljs-params">()</span> </span>&#123;        Base* p = <span class="hljs-keyword">this</span>;        <span class="hljs-comment">// p-&gt;private_val = 1;  // ❌ 仍然错误！</span>        p-&gt;protected_val = <span class="hljs-number">1</span>;   <span class="hljs-comment">// ✅ protected 在派生类内部可以</span>        p-&gt;public_val = <span class="hljs-number">1</span>;      <span class="hljs-comment">// ✅ public 随时可以</span>    &#125;&#125;;</code></pre></blockquote><h2 id="派生类与基类的指针类型转换"><a href="#派生类与基类的指针类型转换" class="headerlink" title="派生类与基类的指针类型转换"></a>派生类与基类的指针类型转换</h2><h3 id="基类与派生类强制类型转换"><a href="#基类与派生类强制类型转换" class="headerlink" title="基类与派生类强制类型转换"></a>基类与派生类强制类型转换</h3><p>⚠️ <strong>公有派生下：</strong></p><p> 派生类对象<strong>的地址</strong>可以<strong>赋值给基类指针</strong></p><p><code>base *pb=&amp; d;</code></p><ul><li><p>*pb指向一个Derived对象，<strong>可以看作一个</strong>Base类的对象，访问它的public成员（对外部来说）</p></li><li><p>即便如此，也<strong>不能通过基类指针访问基类没有，而派生类有的成员</strong></p><blockquote><p>☀️此时，通过 <code>ptrBase</code> 去观察它指向的内存，编译器只会根据 <code>Base</code> 类的模板去匹配内存字段</p></blockquote></li></ul><p><strong>可以强制类型转换</strong></p><pre><code class="hljs c++">Base * ptrBase= &amp; objDerived;Derived *ptrDerived = (Derived*)ptrBase</code></pre><p>（但有点危险）</p><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">protected</span>:    <span class="hljs-type">int</span> n;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">Base</span>(<span class="hljs-type">int</span> i) : <span class="hljs-built_in">n</span>(i) &#123;        cout &lt;&lt; <span class="hljs-string">&quot;Base &quot;</span> &lt;&lt; n &lt;&lt; <span class="hljs-string">&quot; constructed&quot;</span> &lt;&lt; endl;    &#125;    ~<span class="hljs-built_in">Base</span>() &#123;        cout &lt;&lt; <span class="hljs-string">&quot;Base &quot;</span> &lt;&lt; n &lt;&lt; <span class="hljs-string">&quot; destructed&quot;</span> &lt;&lt; endl;    &#125;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;Base:n=&quot;</span> &lt;&lt; n &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> Base &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> v;    <span class="hljs-built_in">Derived</span>(<span class="hljs-type">int</span> i) : <span class="hljs-built_in">Base</span>(i), <span class="hljs-built_in">v</span>(<span class="hljs-number">2</span> * i) &#123;        cout &lt;&lt; <span class="hljs-string">&quot;Derived constructed&quot;</span> &lt;&lt; endl;    &#125;    ~<span class="hljs-built_in">Derived</span>() &#123;        cout &lt;&lt; <span class="hljs-string">&quot;Derived destructed&quot;</span> &lt;&lt; endl;    &#125;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Func</span><span class="hljs-params">()</span> </span>&#123; &#125;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Print</span><span class="hljs-params">()</span> </span>&#123;        cout &lt;&lt; <span class="hljs-string">&quot;Derived:v=&quot;</span> &lt;&lt; v &lt;&lt; endl;        cout &lt;&lt; <span class="hljs-string">&quot;Derived:n=&quot;</span> &lt;&lt; n &lt;&lt; endl;    &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-function">Base <span class="hljs-title">objBase</span><span class="hljs-params">(<span class="hljs-number">5</span>)</span></span>;    <span class="hljs-function">Derived <span class="hljs-title">objDerived</span><span class="hljs-params">(<span class="hljs-number">3</span>)</span></span>;    Base * pBase = &amp;objDerived;        <span class="hljs-comment">// pBase-&gt;Func();          // err; Base类没有Func()成员函数</span>    <span class="hljs-comment">// pBase-&gt;v = 5;           // err; Base类没有v成员变量</span>    pBase-&gt;<span class="hljs-built_in">Print</span>();            <span class="hljs-comment">// 调用基类函数Print()</span>        <span class="hljs-comment">// Derived * pDerived = &amp;objBase; // error</span>    Derived * pDerived = (Derived *)(&amp;objBase); <span class="hljs-comment">// 强制转换，慎用</span>    pDerived-&gt;<span class="hljs-built_in">Print</span>();         <span class="hljs-comment">// 慎用，可能出现不可预期的错误</span>    pDerived-&gt;v = <span class="hljs-number">128</span>;         <span class="hljs-comment">// 往别人的空间里写入数据 -&gt; 可能引起问题</span>        objDerived.<span class="hljs-built_in">Print</span>();    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><ol><li>⚠️ <code>pBase-&gt;Print();</code>调用的是被隐藏的基类的print()函数，而不是派生类重载的那个</li><li>关于扩张（多出来未知）</li></ol><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260323203703816.png" alt="image-20260323203703816"></p></blockquote><h3 id="直接基类与间接基类"><a href="#直接基类与间接基类" class="headerlink" title="直接基类与间接基类"></a>直接基类与间接基类</h3><blockquote><p>类A派生B，类B派生C，…</p></blockquote><ul><li>在声明派生类时，派生类的<strong>首部只要列出它的直接基类</strong><ul><li><del>间接基类</del><strong>不要</strong>在首部列出</li><li>自动会向上继承</li><li>派生类的成员包括：<ul><li>派生类自己定义的成员</li><li>直接基类中定义的成员</li><li>间接基类的全部成员（默认了为根基类）</li></ul></li></ul></li></ul><blockquote><p><strong>关于”自动向上继承”</strong></p><p>C 确实会继承 A 的全部成员（包括间接继承），但<strong>访问权限可能逐层衰减</strong>。如果 B 对 A 是 <code>private</code> 继承，那么 C 中 A 的 <code>public</code> 和 <code>protected</code> 成员会变成 B 的 <code>private</code>，C 就<strong>无法访问</strong>这些从 A 来的成员。不是”全部成员都能用”，而是”全部成员都在对象内存里”。</p><p><strong>关于构造顺序</strong></p><p>虽然声明时只写直接基类 <code>class C : public B</code>，但构造时编译器会自动先构造 A（间接基类），再构造 B（直接基类），最后构造 C。析构顺序严格相反。</p></blockquote><blockquote><h2 id="多继承（考试不要求，不过有点助于进一步理解）"><a href="#多继承（考试不要求，不过有点助于进一步理解）" class="headerlink" title="多继承（考试不要求，不过有点助于进一步理解）"></a>多继承（考试不要求，不过有点助于进一步理解）</h2><p>多继承指一个类可以从多个基类派生，以继承多个基类的成员。</p><pre><code class="hljs cpp"><span class="hljs-comment">// 多继承语法格式</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">derived</span> : access-specifier₁ base₁, access-specifier₂ base₂, ... &#123;    <span class="hljs-comment">// 派生类成员定义</span>&#125;;</code></pre><ul><li><code>access-specifier</code> 可取值为 <code>private</code>、<code>protected</code>、<code>public</code>，用于指定每个基类的继承权限。</li></ul><hr><h3 id="多继承的派生类构造函数"><a href="#多继承的派生类构造函数" class="headerlink" title="多继承的派生类构造函数"></a>多继承的派生类构造函数</h3><h4 id="2-1-构造函数定义示例"><a href="#2-1-构造函数定义示例" class="headerlink" title="2.1 构造函数定义示例"></a>2.1 构造函数定义示例</h4><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">base1</span> &#123;    <span class="hljs-type">int</span> i;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">base1</span>(<span class="hljs-type">int</span> n) &#123; i = n; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">base2</span> &#123;    <span class="hljs-type">int</span> j;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">base2</span>(<span class="hljs-type">int</span> n) &#123; j = n; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">derived</span> : <span class="hljs-keyword">public</span> base1, <span class="hljs-keyword">public</span> base2 &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">derived</span>(<span class="hljs-type">int</span> x);&#125;;<span class="hljs-comment">// 派生类构造函数：在初始化列表中调用基类构造函数</span>derived::<span class="hljs-built_in">derived</span>(<span class="hljs-type">int</span> x) : <span class="hljs-built_in">base1</span>(x), <span class="hljs-built_in">base2</span>(<span class="hljs-number">0</span>) &#123; &#125;</code></pre><h4 id="2-2-构造函数调用顺序"><a href="#2-2-构造函数调用顺序" class="headerlink" title="2.2 构造函数调用顺序"></a>2.2 构造函数调用顺序</h4><ul><li>派生类对象创建时，<strong>先按继承顺序调用基类构造函数</strong>，再调用派生类构造函数。</li><li>若派生类包含成员对象，成员对象的构造函数在基类构造函数调用结束后依次执行，最后调用派生类构造函数。</li><li>完整流程：<ol><li>按继承顺序调用基类构造函数</li><li>依次调用成员对象的构造函数</li><li>调用派生类的构造函数</li></ol></li></ul><hr><h3 id="多继承中基类构造函数的重复调用"><a href="#多继承中基类构造函数的重复调用" class="headerlink" title="多继承中基类构造函数的重复调用"></a>多继承中基类构造函数的重复调用</h3><h4 id="3-1-代码示例"><a href="#3-1-代码示例" class="headerlink" title="3.1 代码示例"></a>3.1 代码示例</h4><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Base</span> &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> val;    <span class="hljs-built_in">Base</span>() &#123; cout &lt;&lt; <span class="hljs-string">&quot;Base Constructor&quot;</span> &lt;&lt; endl; &#125;    ~<span class="hljs-built_in">Base</span>() &#123; cout &lt;&lt; <span class="hljs-string">&quot;Base Destructor&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Base1</span> : <span class="hljs-keyword">public</span> Base &#123; &#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Base2</span> : <span class="hljs-keyword">public</span> Base &#123; &#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Derived</span> : <span class="hljs-keyword">public</span> Base1, <span class="hljs-keyword">public</span> Base2 &#123; &#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    Derived d;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h4 id="3-2-运行结果与问题分析"><a href="#3-2-运行结果与问题分析" class="headerlink" title="3.2 运行结果与问题分析"></a>3.2 运行结果与问题分析</h4><pre><code class="hljs delphi">Base <span class="hljs-function"><span class="hljs-keyword">Constructor</span></span><span class="hljs-function"><span class="hljs-title">Base</span> <span class="hljs-title">Constructor</span></span><span class="hljs-function"><span class="hljs-title">Base</span> <span class="hljs-title">Destructor</span></span><span class="hljs-function"><span class="hljs-title">Base</span> <span class="hljs-title">Destructor</span></span></code></pre><ul><li>问题：<code>Derived</code> 同时继承 <code>Base1</code> 和 <code>Base2</code>，而 <code>Base1</code>、<code>Base2</code> 均继承自 <code>Base</code>，导致 <code>Base</code> 类的构造&#x2F;析构函数被<strong>调用两次</strong>，产生数据冗余与二义性。</li><li>继承关系图：<pre><code class="hljs livescript">    Base   /    <span class="hljs-string">\</span>Base1  Base2   <span class="hljs-string">\</span>    / Derived</code></pre></li></ul><hr><h3 id="多重继承的二义性问题"><a href="#多重继承的二义性问题" class="headerlink" title="多重继承的二义性问题"></a>多重继承的二义性问题</h3><h4 id="4-1-成员名冲突的二义性"><a href="#4-1-成员名冲突的二义性" class="headerlink" title="4.1 成员名冲突的二义性"></a>4.1 成员名冲突的二义性</h4><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">base1</span> &#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> b1;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">set</span><span class="hljs-params">(<span class="hljs-type">int</span> i)</span> </span>&#123; b1 = i; &#125; <span class="hljs-comment">// 私有成员函数</span><span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> i;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">base2</span> &#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> b2;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">set</span><span class="hljs-params">(<span class="hljs-type">int</span> i)</span> </span>&#123; b2 = i; &#125; <span class="hljs-comment">// 公有成员函数</span>    <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">get</span><span class="hljs-params">()</span> </span>&#123; <span class="hljs-keyword">return</span> b2; &#125;    <span class="hljs-type">int</span> i; <span class="hljs-comment">// 与base1的i同名</span>&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">derived</span> : <span class="hljs-keyword">public</span> base1, <span class="hljs-keyword">public</span> base2 &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">()</span> </span>&#123;        <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;%d&quot;</span>, <span class="hljs-built_in">get</span>());        <span class="hljs-comment">// set(5);       // ❌ 二义性：编译器无法确定调用哪个set()</span>        base2::<span class="hljs-built_in">set</span>(<span class="hljs-number">5</span>);   <span class="hljs-comment">// ✅ 正确：指定调用base2的set()</span>        <span class="hljs-comment">// base1::set(5); // ❌ 错误：base1的set()是私有成员，无法访问</span>    &#125;&#125;;</code></pre><h4 id="4-2-外部访问的二义性"><a href="#4-2-外部访问的二义性" class="headerlink" title="4.2 外部访问的二义性"></a>4.2 外部访问的二义性</h4><pre><code class="hljs cpp"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    derived d;    <span class="hljs-comment">// d.set(10);        // ❌ 二义性：存在多个同名set()</span>    <span class="hljs-comment">// d.base1::set(10); // ❌ 错误：base1的set()是私有成员</span>    d.base2::<span class="hljs-built_in">set</span>(<span class="hljs-number">5</span>);     <span class="hljs-comment">// ✅ 正确：指定基类访问</span>    d.base1::i = <span class="hljs-number">5</span>;      <span class="hljs-comment">// ✅ 正确：指定访问base1的i</span>    d.base2::i = <span class="hljs-number">5</span>;      <span class="hljs-comment">// ✅ 正确：指定访问base2的i</span>    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h4 id="4-3-核心规则"><a href="#4-3-核心规则" class="headerlink" title="4.3 核心规则"></a>4.3 核心规则</h4><ul><li>二义性检查在<strong>访问权限检查之前</strong>执行，无法通过访问权限消除二义性：<pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123; <span class="hljs-keyword">public</span>: <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun</span><span class="hljs-params">()</span></span>; &#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span> &#123; <span class="hljs-keyword">private</span>: <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun</span><span class="hljs-params">()</span></span>; &#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">C</span> : <span class="hljs-keyword">public</span> A, <span class="hljs-keyword">public</span> B &#123; &#125;;C obj;obj.<span class="hljs-built_in">fun</span>(); <span class="hljs-comment">// ❌ 仍报二义性错误，即使B的fun()是私有</span></code></pre></li><li>解决方法：使用<strong>作用域解析符 <code>::</code></strong> 明确指定要访问的基类成员。</li></ul></blockquote>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/ed2e/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/ed2e/"/>
    <published>2026-03-22T16:00:00.000Z</published>
    <summary>继承与派生：基类、派生类与访问控制</summary>
    <title>继承与派生</title>
    <updated>2026-07-21T09:00:23.543Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <category term="运算符重载" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E8%BF%90%E7%AE%97%E7%AC%A6%E9%87%8D%E8%BD%BD/"/>
    <content>
      <![CDATA[<h1 id="运算符重载"><a href="#运算符重载" class="headerlink" title="运算符重载"></a>运算符重载</h1><ul><li><p>对<strong>已有</strong>的运算符赋予<strong>多重</strong>含义</p></li><li><p>使得<strong>同一运算符</strong>作用于<strong>不同数据类型</strong>时产生<strong>不同类型</strong>的行为</p></li><li><p><em>实质是函数重载</em>，例如<code>operator+(a,b)</code>和<code>a.operator+(b)</code></p></li><li><p><strong>运算符可以被重载为普通函数和类的成员函数(better)</strong></p></li><li><ul><li><p>重载为普通函数时，参数个数就是实际运算符目数；</p></li><li><p>重载为<strong>成员函数</strong>时，参数个数为<strong>运算符数-1</strong>（由于<code>类名.函数</code>相当于已包含自己，更具体的如，<code>a.operator-(b)</code>）</p><blockquote><p>一个成为<strong>函数作用的对象</strong>，其余成为函数的实参</p></blockquote></li></ul></li><li><p>编译</p><blockquote><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260313220945023.png" alt="image-20260313220945023"></p></blockquote></li><li><p>⚠️ <code>*</code>既可以作为乘法号（两个参数），也可以<strong>作为指针符号一个参数</strong></p></li></ul><h2 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h2><ul><li><a href="#%E8%8C%83%E5%BC%8F">范式</a></li><li><a href="#%E7%BA%A6%E5%AE%9A">约定</a></li><li><a href="#%E6%99%AE%E9%80%9A%E8%BF%90%E7%AE%97%E7%AC%A6%E9%87%8D%E8%BD%BD%E5%AE%9E%E4%BE%8B">普通运算符重载实例</a></li><li><a href="#%E8%BF%90%E7%AE%97%E7%AC%A6%E9%87%8D%E8%BD%BD%E4%B8%BA%E5%8F%8B%E5%85%83">运算符重载为友元</a></li><li><a href="#%E4%B8%8B%E6%A0%87%E8%BF%90%E7%AE%97%E7%AC%A6%E7%9A%84%E9%AB%98%E7%BA%A7%E9%87%8D%E8%BD%BD">下标运算符的高级重载</a><ul><li><a href="#%E7%9B%AE%E6%A0%87-1">目标</a></li><li><a href="#%E5%B8%8C%E6%9C%9B">希望</a></li><li><a href="#%E5%AE%9E%E7%8E%B0-1">实现（可变长度数组的实现</a></li></ul></li><li><a href="#%E8%B5%8B%E5%80%BC%E8%BF%90%E7%AE%97%E7%AC%A6%E7%9A%84%E9%87%8D%E8%BD%BD">赋值运算符的重载</a><ul><li><a href="#%E6%A0%87%E5%87%86%E6%93%8D%E4%BD%9C">标准操作</a></li><li><a href="#%E5%89%8D%E7%BD%AE%E6%B5%85%E6%8B%B7%E8%B4%9D%E5%92%8C%E6%B7%B1%E6%8B%B7%E8%B4%9D">前置：浅拷贝和深拷贝</a></li><li><a href="#%E7%9B%AE%E6%A0%87-2">目标（String类实现）</a></li><li><a href="#%E5%AE%9E%E7%8E%B0-2">实现（String类实现）</a></li></ul></li><li><a href="#%E6%B5%81%E8%BF%90%E7%AE%97%E7%AC%A6%E7%9A%84%E9%87%8D%E8%BD%BD">流运算符的重载</a><ul><li><a href="#%E6%B5%81%E6%8F%92%E5%85%A5%E8%BF%90%E7%AE%97%E7%AC%A6%E9%87%8D%E8%BD%BD">流插入运算符重载</a></li><li><a href="#%E6%B5%81%E6%8F%90%E5%8F%96%E8%BF%90%E7%AE%97%E7%AC%A6%E9%87%8D%E8%BD%BD">流提取运算符重载</a></li></ul></li><li><a href="#%E5%BC%BA%E5%88%B6%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%E8%BF%90%E7%AE%97%E7%AC%A6%E9%87%8D%E8%BD%BD">强制类型转换运算符重载</a></li><li><a href="#%E9%87%8D%E8%BD%BD%E8%87%AA%E5%A2%9E%E8%87%AA%E5%87%8F%E8%BF%90%E7%AE%97%E7%AC%A6">重载自增、自减运算符</a><ul><li><a href="#%E5%AE%9E%E7%8E%B0-3">实现（自增自减）</a></li></ul></li></ul><h2 id="范式"><a href="#范式" class="headerlink" title="范式"></a>范式</h2><pre><code class="hljs c++">返回值类型 <span class="hljs-keyword">operator</span> 运算符 (形参表)&#123;...&#125;</code></pre><p>运算符的操作数称为函数调用的实参，运算的结果就是函数的返回值。</p><blockquote><p>对于强制类型运算符,返回值类型不必写,因为运算符就说明了返回值类型</p></blockquote><h2 id="约定"><a href="#约定" class="headerlink" title="约定"></a>约定</h2><ul><li>重载后的运算符含义<strong>应该符合原有的用法习惯</strong></li><li>尽量<strong>保持原有的特性</strong></li><li>C++规定，运算符重载<strong>不改变运算符优先级</strong></li><li>⚠️并非所有都可重载，<strong>不能被重载</strong>的运算符：<code>.</code> <code>::</code> <code>?:</code> <code>sizeof</code> <code>.*</code> (以及原来不存在的)</li><li>⚠️只能<strong>重载为</strong>成员函数： <code>=</code> <code>()</code> <code>[]</code> <code>-&gt;</code>和<code>强制类型转换运算符</code></li></ul><h2 id="普通运算符重载实例"><a href="#普通运算符重载实例" class="headerlink" title="普通运算符重载实例"></a>普通运算符重载实例</h2><pre><code class="hljs c++"><span class="hljs-comment">// 注意以下暂时将变量置于public以方便访问，正常情况下参见 friend 接口访问</span><span class="hljs-comment">// 此处的+重载为普通函数，但一般情况下还是更推荐重载为成员函数</span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span>&#123;<span class="hljs-keyword">public</span>:    <span class="hljs-type">double</span> real, imag;    <span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r = <span class="hljs-number">0.0</span>, <span class="hljs-type">double</span> i = <span class="hljs-number">0.0</span>) : <span class="hljs-built_in">real</span>(r), <span class="hljs-built_in">imag</span>(i) &#123;&#125;    Complex <span class="hljs-keyword">operator</span>-(<span class="hljs-type">const</span> Complex &amp;c);&#125;;Complex <span class="hljs-keyword">operator</span>+(<span class="hljs-type">const</span> Complex &amp;a, <span class="hljs-type">const</span> Complex &amp;b)&#123;    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Complex</span>(a.real + b.real, a.imag + b.imag);&#125;Complex Complex::<span class="hljs-keyword">operator</span>-(<span class="hljs-type">const</span> Complex &amp;c)&#123;    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Complex</span>(real - c.real, imag - c.imag);&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><span class="hljs-function"></span>&#123;    <span class="hljs-function">Complex <span class="hljs-title">a</span><span class="hljs-params">(<span class="hljs-number">4</span>,<span class="hljs-number">4</span>)</span>, <span class="hljs-title">b</span><span class="hljs-params">(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>)</span>, c</span>;    c = a + b;    cout &lt;&lt; c.real &lt;&lt; <span class="hljs-string">&quot; , &quot;</span> &lt;&lt; c.imag &lt;&lt; endl;    cout &lt;&lt; (a-b).real &lt;&lt; <span class="hljs-string">&quot; , &quot;</span> &lt;&lt; (a-b).imag &lt;&lt; endl;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>实现[]的重载</p><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span>&#123;<span class="hljs-keyword">public</span>:<span class="hljs-type">double</span> real, imag;<span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r = <span class="hljs-number">0.0</span>, <span class="hljs-type">double</span> i = <span class="hljs-number">0.0</span>) : <span class="hljs-built_in">real</span>(r), <span class="hljs-built_in">imag</span>(i) &#123;&#125;<span class="hljs-comment">// 此处用到了引用作为返回值即为return的值（实参）</span>Complex <span class="hljs-keyword">operator</span>-(<span class="hljs-type">const</span> Complex &amp;c);<span class="hljs-type">double</span>&amp; <span class="hljs-keyword">operator</span>[](<span class="hljs-type">int</span> index)             &#123; <span class="hljs-keyword">return</span> index == <span class="hljs-number">0</span> ? real : imag; &#125;<span class="hljs-type">const</span> <span class="hljs-type">double</span>&amp; <span class="hljs-keyword">operator</span>[](<span class="hljs-type">int</span> index) <span class="hljs-type">const</span> &#123; <span class="hljs-keyword">return</span> index == <span class="hljs-number">0</span> ? real : imag; &#125;<span class="hljs-comment">// 此处重载了两次，前者用于非const对象的只读和写入，后者用于const对象的只读（const 只能用于此）--当然也可以传入非const对象只读</span>&#125;;Complex <span class="hljs-keyword">operator</span>+(<span class="hljs-type">const</span> Complex &amp;a, <span class="hljs-type">const</span> Complex &amp;b)&#123;<span class="hljs-keyword">return</span> <span class="hljs-built_in">Complex</span>(a.real + b.real, a.imag + b.imag);&#125;Complex Complex::<span class="hljs-keyword">operator</span>-(<span class="hljs-type">const</span> Complex &amp;c)&#123;<span class="hljs-keyword">return</span> <span class="hljs-built_in">Complex</span>(real - c.real, imag - c.imag);&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><span class="hljs-function"></span>&#123;<span class="hljs-function">Complex <span class="hljs-title">a</span><span class="hljs-params">(<span class="hljs-number">4</span>,<span class="hljs-number">4</span>)</span>, <span class="hljs-title">b</span><span class="hljs-params">(<span class="hljs-number">1</span>,<span class="hljs-number">1</span>)</span>, c</span>;c = a + b;cout &lt;&lt; c[<span class="hljs-number">0</span>] &lt;&lt; <span class="hljs-string">&quot; , &quot;</span> &lt;&lt; c[<span class="hljs-number">1</span>] &lt;&lt; endl;   <span class="hljs-comment">// 使用 [] 访问</span>a[<span class="hljs-number">0</span>] = <span class="hljs-number">10</span>;   <span class="hljs-comment">// 通过 [] 修改实部</span>a[<span class="hljs-number">1</span>] = <span class="hljs-number">20</span>;   <span class="hljs-comment">// 修改虚部</span>cout &lt;&lt; (a-b)[<span class="hljs-number">0</span>] &lt;&lt; <span class="hljs-string">&quot; , &quot;</span> &lt;&lt; (a-b)[<span class="hljs-number">1</span>] &lt;&lt; endl;<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p>此外，<code>[]</code> 是双目运算符，需要两个操作数：<strong>对象本身</strong>（左操作数）和<strong>下标索引</strong>（右操作数），重载为成员函数（只能）仅有<strong>一个参数</strong>，因为第一个操作数被<code>this 指针</code>隐式获取了</p><p>实现二维数组</p><h3 id="方法-1：代理类（实现-a-i-j-语法）"><a href="#方法-1：代理类（实现-a-i-j-语法）" class="headerlink" title="方法 1：代理类（实现 a[i][j] 语法）"></a>方法 1：代理类（实现 <code>a[i][j]</code> 语法）</h3><p><code>operator[]</code> 只能接受一个参数，所以第一次 <code>a[i]</code> 返回一个<strong>代理对象</strong>，再由代理对象的 <code>operator[]</code> 取列：</p><p>cpp</p><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Array2D</span> &#123;    <span class="hljs-type">int</span>* data;    <span class="hljs-type">int</span> rows, cols;<span class="hljs-keyword">public</span>:    <span class="hljs-comment">// 代理类：代表某一行</span>    <span class="hljs-keyword">class</span> <span class="hljs-title class_">RowProxy</span> &#123;        <span class="hljs-type">int</span>* row_start;    <span class="hljs-keyword">public</span>:        <span class="hljs-built_in">RowProxy</span>(<span class="hljs-type">int</span>* p) : <span class="hljs-built_in">row_start</span>(p) &#123;&#125;        <span class="hljs-type">int</span>&amp; <span class="hljs-keyword">operator</span>[](<span class="hljs-type">int</span> j) &#123; <span class="hljs-keyword">return</span> row_start[j]; &#125;    &#125;;    <span class="hljs-built_in">Array2D</span>(<span class="hljs-type">int</span> r, <span class="hljs-type">int</span> c) : <span class="hljs-built_in">rows</span>(r), <span class="hljs-built_in">cols</span>(c) &#123;        data = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[r * c]();  <span class="hljs-comment">// 一维连续内存</span>    &#125;    ~<span class="hljs-built_in">Array2D</span>() &#123; <span class="hljs-keyword">delete</span>[] data; &#125;    RowProxy <span class="hljs-keyword">operator</span>[](<span class="hljs-type">int</span> i) &#123;        <span class="hljs-keyword">return</span> <span class="hljs-built_in">RowProxy</span>(data + i * cols);    &#125;&#125;;<span class="hljs-comment">// 使用</span><span class="hljs-function">Array2D <span class="hljs-title">a</span><span class="hljs-params">(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>)</span></span>;a[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>] = <span class="hljs-number">100</span>;   <span class="hljs-comment">// 先 a[1] 返回 RowProxy，再 [2] 定位元素</span></code></pre><p><strong>好处</strong>：符合直觉的 <code>[][]</code> 写法，且底层是<strong>一维连续内存</strong></p><hr><h3 id="方法-2：直接重载-operator"><a href="#方法-2：直接重载-operator" class="headerlink" title="方法 2：直接重载 operator()"></a>方法 2：直接重载 <code>operator()</code></h3><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Array2D</span> &#123;    <span class="hljs-type">int</span>* data;    <span class="hljs-type">int</span> rows, cols;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">Array2D</span>(<span class="hljs-type">int</span> r, <span class="hljs-type">int</span> c) : <span class="hljs-built_in">rows</span>(r), <span class="hljs-built_in">cols</span>(c) &#123;        data = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[r * c]();    &#125;    ~<span class="hljs-built_in">Array2D</span>() &#123; <span class="hljs-keyword">delete</span>[] data; &#125;    <span class="hljs-function"><span class="hljs-type">int</span>&amp; <span class="hljs-title">operator</span><span class="hljs-params">()</span><span class="hljs-params">(<span class="hljs-type">int</span> i, <span class="hljs-type">int</span> j)</span> </span>&#123;        <span class="hljs-keyword">return</span> data[i * cols + j];    &#125;        <span class="hljs-function"><span class="hljs-type">int</span>&amp; <span class="hljs-title">operator</span><span class="hljs-params">()</span><span class="hljs-params">(<span class="hljs-type">int</span> i, <span class="hljs-type">int</span> j)</span> <span class="hljs-type">const</span> </span>&#123;        <span class="hljs-keyword">return</span> data[i * cols + j];    &#125;&#125;;<span class="hljs-comment">// 使用</span><span class="hljs-function">Array2D <span class="hljs-title">a</span><span class="hljs-params">(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>)</span></span>;<span class="hljs-built_in">a</span>(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>) = <span class="hljs-number">100</span>;   <span class="hljs-comment">// 直接二维索引，无需代理类</span></code></pre><p>方法3:最直接了当的办法</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Array2D</span> &#123;    <span class="hljs-type">int</span>** data;    <span class="hljs-type">int</span> rows, cols;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">Array2D</span>(<span class="hljs-type">int</span> r, <span class="hljs-type">int</span> c) : <span class="hljs-built_in">rows</span>(r), <span class="hljs-built_in">cols</span>(c) &#123;        data = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>*[rows];        <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i &lt; rows; ++i)            data[i] = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[c]();    &#125;    <span class="hljs-type">int</span>* <span class="hljs-keyword">operator</span>[](<span class="hljs-type">int</span> i) &#123; <span class="hljs-keyword">return</span> data[i]; &#125;  <span class="hljs-comment">// 返回 int*，第二次 [j] 用内建指针下标</span>    ~<span class="hljs-built_in">Array2D</span>() &#123;        <span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i &lt; rows; ++i) <span class="hljs-keyword">delete</span>[] data[i];        <span class="hljs-keyword">delete</span>[] data;    &#125;&#125;;<span class="hljs-comment">// 使用</span><span class="hljs-function">Array2D <span class="hljs-title">a</span><span class="hljs-params">(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>)</span></span>;a[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>] = <span class="hljs-number">100</span>;  <span class="hljs-comment">// a[1] 返回 int*，然后 [2] 是原生指针运算</span></code></pre></blockquote><h2 id="运算符重载为友元"><a href="#运算符重载为友元" class="headerlink" title="运算符重载为友元"></a>运算符重载为友元</h2><ul><li><strong>一般情况</strong>下，运算符重载为<strong>成员函数</strong></li><li>重载为成员函数<strong>不能满足需求</strong>，重载为<strong>全局</strong>函数</li><li>重载为全局函数<strong>不能访问类的私有成员</strong>，所以需要<strong>重载为友元</strong></li></ul><blockquote><p>例如：重载为成员函数 <code>c+5 //ok</code> ，<code>5+c //error!</code>，需重载为全局函数，为使其能够访问私有<strong>应声明为友元</strong></p><p>示范：</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span>&#123;<span class="hljs-keyword">private</span>:<span class="hljs-type">double</span> real,imag;<span class="hljs-keyword">public</span>:<span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r,<span class="hljs-type">double</span> i):<span class="hljs-built_in">real</span>(r),<span class="hljs-built_in">imag</span>(i)&#123;&#125;    Complex <span class="hljs-keyword">operator</span>+(<span class="hljs-type">double</span> r);    <span class="hljs-keyword">friend</span> Complex <span class="hljs-keyword">operator</span>+(<span class="hljs-type">double</span> r,<span class="hljs-type">const</span> Complex&amp; c);&#125;;Complex Complex::<span class="hljs-keyword">operator</span>+(<span class="hljs-type">double</span> r)&#123;    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Complex</span>(real+r,img);&#125;<span class="hljs-comment">//解释 c+5</span>Complex <span class="hljs-keyword">operator</span>+(<span class="hljs-type">double</span> r,<span class="hljs-type">const</span> Complex &amp;c)&#123;    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Complex</span>(r+c.real,c.imag);&#125;<span class="hljs-comment">//解释 5+c</span><span class="hljs-comment">// 对于全局函数+，第一个参数为左值，第二个参数为右值</span></code></pre><p>事实上：</p><p>更加简单的写法（但可能略微开销）是：</p><pre><code class="hljs c++"><span class="hljs-comment">//构造函数改为：</span><span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r,<span class="hljs-type">double</span> i=<span class="hljs-number">0</span>):<span class="hljs-built_in">real</span>(r),<span class="hljs-built_in">imag</span>(i)&#123;&#125;<span class="hljs-comment">//采用全局友函数+自动隐式转换的方式</span><span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-title">Complex</span><span class="hljs-params">(<span class="hljs-type">const</span> Complex &amp;c1,<span class="hljs-type">const</span> Complex &amp;c2)</span></span>&#123;<span class="hljs-keyword">return</span> <span class="hljs-built_in">Complex</span>(c<span class="hljs-number">1.</span>real+c<span class="hljs-number">2.</span>real,c<span class="hljs-number">1.</span>imag+c<span class="hljs-number">2.</span>imag);&#125;<span class="hljs-comment">// 这样5→Complex(5)可以实现正常加减</span></code></pre></blockquote><h2 id="下标运算符的高级重载"><a href="#下标运算符的高级重载" class="headerlink" title="下标运算符的高级重载"></a>下标运算符的高级重载</h2><h3 id="目标"><a href="#目标" class="headerlink" title="目标"></a>目标</h3><p><strong>重载为长度可变的整型数组类</strong></p><h3 id="希望"><a href="#希望" class="headerlink" title="希望"></a>希望</h3><ul><li>数组元素<strong>个数可在初始化</strong>该对象时<strong>指定</strong></li><li><strong>可以</strong>往动态数组中<strong>添加元素</strong></li><li>使用该类时<strong>不用操心动态分配、释放</strong>问题</li><li>能够像使用数组那样使用动态数组类对象，如可以<strong>下标访问元素</strong></li></ul><p>⚠️ “[]”是双目运算符，两个操作数，一里一外，“a[i]”等价于<code>a.operator[](i)</code>。按照原有“[]”的特性，“a[i]”可作为左值使用（<strong>等号左侧</strong>，具有<strong>明确的内存地址</strong>），因此应该<strong>返回引用</strong></p><h3 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h3><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CArray</span>&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> size; <span class="hljs-comment">//数组元素个数</span>    <span class="hljs-type">int</span> *ptr; <span class="hljs-comment">//指向动态分配的数组</span><span class="hljs-keyword">public</span>:    <span class="hljs-built_in">CArray</span>(<span class="hljs-type">int</span> s=<span class="hljs-number">0</span>);    <span class="hljs-built_in">CArray</span>(<span class="hljs-type">const</span> CArray &amp;a);    ~<span class="hljs-built_in">CArray</span>();    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">push_back</span><span class="hljs-params">(<span class="hljs-type">int</span> v)</span></span>; <span class="hljs-comment">// 欲实现 a.push_back(...)</span>        <span class="hljs-comment">// 更进一步的优化，应当是提供一个const版本</span>    CArray &amp; <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> CArray &amp;a); <span class="hljs-comment">// 用于数组对象之间的赋值</span>    <span class="hljs-comment">// 优化版本，const关键字防止修改</span>    <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">length</span> <span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>&#123;<span class="hljs-keyword">return</span> size;&#125;         <span class="hljs-comment">//此处返回的是 int &amp; 相当于是对下表的那块地址的引用</span>    <span class="hljs-type">int</span> &amp; <span class="hljs-keyword">operator</span>[](<span class="hljs-type">int</span> i)&#123;        <span class="hljs-comment">// 防越界</span>        <span class="hljs-built_in">assert</span>(i&gt;=<span class="hljs-number">0</span> &amp;&amp; i&lt;size); <span class="hljs-comment">// 条件不成立程序直接终止并报错</span>        <span class="hljs-comment">// 用于支持根据下标访问数组元素，如 a[i]=4 和 n=a[i]的语句</span>        <span class="hljs-keyword">return</span> *(ptr+i); <span class="hljs-comment">// 或者等价地写为 ptr[i]</span>    &#125;&#125;; <span class="hljs-comment">// ！</span>CArray::<span class="hljs-built_in">CArray</span>(<span class="hljs-type">int</span> s):<span class="hljs-built_in">size</span>(s)&#123;    <span class="hljs-keyword">if</span>(s==<span class="hljs-number">0</span>)        ptr=<span class="hljs-literal">NULL</span>;    <span class="hljs-keyword">else</span>        ptr=<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[s];&#125;CArray::<span class="hljs-built_in">CArray</span>(<span class="hljs-type">const</span> CArray &amp;a)&#123;    <span class="hljs-keyword">if</span>(!a.ptr)&#123;        ptr=<span class="hljs-literal">NULL</span>;        size=<span class="hljs-number">0</span>;        <span class="hljs-keyword">return</span>;    &#125;    ptr=<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[a.size];    <span class="hljs-built_in">memcpy</span>(ptr,a.ptr,<span class="hljs-built_in">sizeof</span>(<span class="hljs-type">int</span>)*a.size);    size=a.size;&#125;CArray::~<span class="hljs-built_in">CArray</span>()&#123;    <span class="hljs-keyword">if</span>(ptr) <span class="hljs-keyword">delete</span> []ptr;&#125;CArray &amp; CArray::<span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> CArray &amp; a)&#123;    <span class="hljs-comment">//赋值号作用：“=”左边对象中存放的数组，大小和内容都和右边对象一样</span>    <span class="hljs-comment">// 防自己，防空</span>    <span class="hljs-keyword">if</span>(ptr==a.ptr) <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>; <span class="hljs-comment">// 防止自等</span>    <span class="hljs-keyword">if</span>(a.ptr==<span class="hljs-literal">NULL</span>)&#123;        <span class="hljs-keyword">if</span>(ptr) <span class="hljs-keyword">delete</span> []ptr;        ptr=<span class="hljs-literal">NULL</span>; <span class="hljs-comment">// 清空地址后为悬浮指针，仍然指向原来地址，必须令为NULL保证安全</span>        size=<span class="hljs-number">0</span>;        <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;    &#125;    <span class="hljs-keyword">if</span>(size&lt;a.size)&#123;  <span class="hljs-comment">// 只有不够才多申请，不用担心push，因为size也对已经改了</span>        <span class="hljs-keyword">if</span>(ptr)            <span class="hljs-keyword">delete</span> []ptr;        ptr=<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[a.size];    &#125;    <span class="hljs-built_in">memcpy</span>(ptr,a.ptr,<span class="hljs-built_in">sizeof</span>(<span class="hljs-type">int</span>)*a.size);    size=a.size;    <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;&#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CArray::push_back</span><span class="hljs-params">(<span class="hljs-type">int</span> v)</span></span>&#123;    <span class="hljs-keyword">if</span>(ptr)&#123;        <span class="hljs-type">int</span> *tmpPtr=<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[size<span class="hljs-number">+1</span>]; <span class="hljs-comment">// 重新分配空间</span>        <span class="hljs-built_in">memcpy</span>(tmpPtr,ptr,<span class="hljs-built_in">sizeof</span>(<span class="hljs-type">int</span>)*size); <span class="hljs-comment">// 复制原数组内容</span>        <span class="hljs-keyword">delete</span> []ptr;        ptr=tmpPtr;    &#125;    <span class="hljs-keyword">else</span>        ptr=<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[<span class="hljs-number">1</span>];    ptr[size++]=v; <span class="hljs-comment">// 加入新的数组元素</span>&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    CArray a;    <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i&lt;<span class="hljs-number">5</span>;++i)        a.<span class="hljs-built_in">push_back</span>(i);    CArray a2,a3;    a2=a;    <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i&lt;a<span class="hljs-number">2.l</span>ength();++i)        cout&lt;&lt;a2[i]&lt;&lt;<span class="hljs-string">&quot; &quot;</span>;    cout&lt;&lt;endl;    a[<span class="hljs-number">3</span>]=<span class="hljs-number">100</span>;    <span class="hljs-function">CArray <span class="hljs-title">a4</span><span class="hljs-params">(a)</span></span>;    <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i&lt;a<span class="hljs-number">4.l</span>ength;++i)        cout&lt;&lt;a4[i]&lt;&lt;<span class="hljs-string">&quot; &quot;</span>;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>Tips：注意到push_back函数每次尾部添加一个元素都要重新分配内存并复制原有内容，效率低下，因此可以<strong>采用“翻倍扩容增长策略”</strong></p><pre><code class="hljs c++"><span class="hljs-comment">// 成员变量增加 capacity</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CArray::push_back</span><span class="hljs-params">(<span class="hljs-type">int</span> v)</span></span>&#123;    <span class="hljs-keyword">if</span>(size==capacity)&#123;        <span class="hljs-comment">// 空间爆满再扩容</span>        <span class="hljs-type">int</span> newCapacity=(capacity==<span class="hljs-number">0</span>?)<span class="hljs-number">1</span>:<span class="hljs-number">2</span>*capacity;        <span class="hljs-type">int</span> *tmpPtr=<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[newCapacity];        <span class="hljs-keyword">if</span>(ptr)&#123;            <span class="hljs-built_in">memcpy</span>(tmpPtr，ptr,<span class="hljs-built_in">sizeof</span>(<span class="hljs-type">int</span>)*size);            <span class="hljs-keyword">delete</span> []ptr;        &#125;        ptr=tmpPtr;        capacity=newCapacity;    &#125;    ptr[size++]=v;&#125;</code></pre><p>如此将扩容次数从 n 降到 log(n)</p></blockquote><blockquote><pre><code class="hljs c++"><span class="hljs-type">int</span>* a = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[<span class="hljs-number">5</span>];      <span class="hljs-comment">// a[0] 可能是 0，也可能是 114514，不可预期</span><span class="hljs-type">int</span>* b = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[<span class="hljs-number">5</span>]();    <span class="hljs-comment">// b[0] ~ b[4] 保证全是 0</span></code></pre></blockquote><h2 id="赋值运算符的重载"><a href="#赋值运算符的重载" class="headerlink" title="赋值运算符的重载"></a>赋值运算符的重载</h2><p><strong>赋值运算符“&#x3D;”只能重载为成员函数！</strong>（与该类<strong>强关联</strong>必须重载为成员函数）</p><h3 id="标准操作"><a href="#标准操作" class="headerlink" title="标准操作"></a>标准操作</h3><ul><li>⚠️</li><li>检查自我赋值</li><li>检查是否为空</li><li>释放旧内存→分配新内存→复制数据</li><li>让目标指向新内存</li></ul><p>以下为<code>&lt;string&gt;</code>的可能实现参考，掌握以下则几乎可以掌握“&#x3D;”的重载</p><h3 id="前置：浅拷贝和深拷贝"><a href="#前置：浅拷贝和深拷贝" class="headerlink" title="前置：浅拷贝和深拷贝"></a>前置：浅拷贝和深拷贝</h3><h4 id="浅拷贝（浅复制）"><a href="#浅拷贝（浅复制）" class="headerlink" title="浅拷贝（浅复制）"></a>浅拷贝（浅复制）</h4><p>执行<strong>逐个字节</strong>的复制工作</p><ul><li>对于指针，（拷贝指针的值即地址）将导致<strong>指向同一个地方</strong></li><li>若1对象消亡，但另一指针2仍然指向该地址，对象2消亡释放同一块内存，程序崩溃</li><li>若将1指针改指向”others”，消亡原本对象，2指针成为悬空指针</li></ul><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260315154951918.png" alt="image-20260315154951918"></p><h4 id="深拷贝"><a href="#深拷贝" class="headerlink" title="深拷贝"></a>深拷贝</h4><p>将一个<strong>对象中指针变量指向的内容</strong>→复制到另一个对象中指针成员变量指向的地方</p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260315160722752.png" alt="image-20260315160722752"></p><blockquote><p>🤨</p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260315160532693.png" alt="image-20260315160532693"></p></blockquote><h3 id="目标-1"><a href="#目标-1" class="headerlink" title="目标"></a>目标</h3><p>实现 string 类，长度可变</p><h3 id="实现-1"><a href="#实现-1" class="headerlink" title="实现"></a>实现</h3><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;cstring&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">String</span>&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">char</span> *str;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">String</span>():<span class="hljs-built_in">str</span>(<span class="hljs-literal">NULL</span>)&#123;&#125;    <span class="hljs-comment">//定义转换构造函数（方便强制类型转换）</span>    <span class="hljs-built_in">String</span>(<span class="hljs-type">const</span> <span class="hljs-type">char</span>* s):<span class="hljs-built_in">str</span>(<span class="hljs-literal">NULL</span>)&#123;        <span class="hljs-keyword">if</span>(s)&#123;            str=<span class="hljs-keyword">new</span> <span class="hljs-type">char</span>[<span class="hljs-built_in">strlen</span>(s)<span class="hljs-number">+1</span>];            <span class="hljs-built_in">strcpy</span>(str,s);        &#125;    &#125;    <span class="hljs-comment">//必须补充复制构造函数以使得String s=s2 生效,深拷贝！</span>    <span class="hljs-built_in">String</span>(<span class="hljs-type">const</span> String &amp;s):<span class="hljs-built_in">str</span>(<span class="hljs-literal">NULL</span>)&#123;<span class="hljs-keyword">if</span>(s.str)&#123;            str=<span class="hljs-keyword">new</span> <span class="hljs-type">char</span>[<span class="hljs-built_in">strlen</span>(s.str)<span class="hljs-number">+1</span>];            <span class="hljs-built_in">strcpy</span>(str,s.str);        &#125;    &#125;    <span class="hljs-function"><span class="hljs-type">const</span> <span class="hljs-type">char</span> *<span class="hljs-title">c_str</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>&#123; <span class="hljs-keyword">return</span> str;&#125; <span class="hljs-comment">// 加上前const防止对象内部被轻易修改，加上外const推广范围，使得const String 也可以调用</span>    String &amp; <span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> <span class="hljs-type">char</span>*s);    ~<span class="hljs-built_in">String</span>()&#123; <span class="hljs-keyword">delete</span> []str;&#125; <span class="hljs-comment">// 根据生成来确定，此外，C++ 标准规定 delete 或 delete[] 一个空指针是安全的（不会产生任何效果）无需检查</span>&#125;;<span class="hljs-comment">// 防自己，防空</span><span class="hljs-comment">// 浅拷贝（针对 const char*）</span>String &amp; String::<span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> <span class="hljs-type">char</span> *s)&#123;    <span class="hljs-keyword">if</span>(str==s) <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>; <span class="hljs-comment">// 少发生</span>    <span class="hljs-keyword">delete</span> []str;    <span class="hljs-keyword">if</span>(s)&#123;        str=<span class="hljs-keyword">new</span> <span class="hljs-type">char</span>[<span class="hljs-built_in">strlen</span>(s)<span class="hljs-number">+1</span>];        <span class="hljs-built_in">strcpy</span>(str,s);&#125;    <span class="hljs-keyword">else</span>        str=<span class="hljs-literal">NULL</span>;    <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;&#125;<span class="hljs-comment">// 深拷贝</span>String &amp;String::<span class="hljs-keyword">operator</span>=(<span class="hljs-type">const</span> String &amp;s)&#123;    <span class="hljs-comment">//if(str==s.str) return *this; // 可能出现误判！</span>    <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>==&amp;s) <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>; <span class="hljs-comment">// 直接判断是否为同一个对象，与成员具体的值无关，最可靠！</span>    <span class="hljs-keyword">delete</span> []str;    <span class="hljs-keyword">if</span>(s.str)&#123;        str=<span class="hljs-keyword">new</span> <span class="hljs-type">char</span>[<span class="hljs-built_in">strlen</span>(s.str)<span class="hljs-number">+1</span>];<span class="hljs-built_in">strcpy</span>(str,s.str);    &#125;    <span class="hljs-keyword">else</span>        str=<span class="hljs-literal">NULL</span>;    <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    String s;    s=<span class="hljs-string">&quot;Good Luck&quot;</span>;    cout&lt;&lt;s.<span class="hljs-built_in">c_str</span>()&lt;&lt;endl;    <span class="hljs-comment">// String s2=&quot;hello!&quot;; //在没有转换构造函数之前这句话是错的</span>    s=<span class="hljs-string">&quot;Shenzhou!&quot;</span>;    cout&lt;&lt;s.<span class="hljs-built_in">c_str</span>()&lt;&lt;endl;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><blockquote><p>关于42行误判：</p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260315171404785.png" alt="image-20260315171404785"></p><p>关于 operator 返回值的讨论</p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260315171540412.png" alt="image-20260315171540412"></p><p>🤨 加上 const 使得 const char* 也可以使用</p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260315163549393.png" alt="image-20260315163549393"></p></blockquote><h2 id="流运算符的重载"><a href="#流运算符的重载" class="headerlink" title="流运算符的重载"></a>流运算符的重载</h2><h3 id="流插入运算符重载"><a href="#流插入运算符重载" class="headerlink" title="流插入运算符重载"></a>流插入运算符重载</h3><p><strong><code>&lt;&lt;</code>本没有输出功能，只因被 ostream类重载了多次（cout是ostream类的对象）</strong></p><ul><li><p><code>cout&lt;&lt;object</code>→两个参数</p><pre><code class="hljs c++"><span class="hljs-type">void</span> <span class="hljs-keyword">operator</span>&lt;&lt;(ostream &amp;o,<span class="hljs-type">int</span> n)&#123;<span class="hljs-built_in">output</span>(n);&#125;</code></pre></li><li><p><code>cout&lt;&lt;5&lt;&lt;&quot; hello&quot;</code>→&#96;operator&lt;&lt;(operator&lt;&lt;(cout,5),” hello”)→为了链式调用，必须返回std::ostream类的引用</p><pre><code class="hljs c++">ostream &amp; <span class="hljs-keyword">operator</span>&lt;&lt;(ostream &amp;o,<span class="hljs-type">int</span> n)&#123;<span class="hljs-built_in">output</span>(n);    <span class="hljs-keyword">return</span> o;&#125;</code></pre></li></ul><p>重载为全局函数：</p><pre><code class="hljs c++"><span class="hljs-comment">//实际上操作</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>&#123;<span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> n;&#125;;ostream &amp; <span class="hljs-keyword">operator</span>&lt;&lt;(ostream &amp; o,<span class="hljs-type">const</span> A &amp;a)&#123;    o&lt;&lt;a.n;    <span class="hljs-keyword">return</span> o;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    A a;    a.n=<span class="hljs-number">5</span>;    cout&lt;&lt;a&lt;&lt;<span class="hljs-string">&quot;hello&quot;</span>;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h4 id="重载为成员函数"><a href="#重载为成员函数" class="headerlink" title="重载为成员函数"></a>重载为成员函数</h4><p>标准库实际做的，<strong>但是对于自定义对象⚠️我们不能改变标准库！！！</strong></p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">ostream</span>&#123;ostream &amp; <span class="hljs-keyword">operator</span>&lt;&lt;(<span class="hljs-type">int</span> n)&#123;<span class="hljs-built_in">output</span>(n);<span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;&#125;&#125;;</code></pre><p>调用时则例如相当于<code>(cout.operator&lt;&lt;(n++)).operator&lt;&lt;(n)</code></p><h3 id="流提取运算符重载"><a href="#流提取运算符重载" class="headerlink" title="流提取运算符重载"></a>流提取运算符重载</h3><p><strong>cin 是<code>istream</code>类的对象</strong>，在头文件iostream声明，** istream 将<code>&gt;&gt;</code>重载为成员函数，与cin组合用于输入数据 ** </p><h3 id="实际重载"><a href="#实际重载" class="headerlink" title="实际重载"></a>实际重载</h3><p><strong>由于无法修改 ostream 类和 istream 类</strong>，只能重载为<strong>全局函数</strong>，且<strong>声明为友元</strong></p><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;string&gt;</span></span><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;cstdlib&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span>&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">double</span> real,imag;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r=<span class="hljs-number">0</span>,<span class="hljs-type">double</span> i=<span class="hljs-number">0</span>):<span class="hljs-built_in">real</span>(r),<span class="hljs-built_in">imag</span>(i)&#123;&#125;    <span class="hljs-keyword">friend</span> ostream &amp; <span class="hljs-keyword">operator</span>&lt;&lt;(ostream &amp;os,<span class="hljs-type">const</span> Complex &amp;c);    <span class="hljs-keyword">friend</span> istream &amp; <span class="hljs-keyword">operator</span>&gt;&gt;(istream &amp;is,Complex &amp;c);&#125;;ostream &amp; <span class="hljs-keyword">operator</span> &lt;&lt;(ostream &amp; os,<span class="hljs-type">const</span> Complex &amp; c)&#123;    os&lt;&lt;c.real&lt;&lt;<span class="hljs-string">&quot;+&quot;</span>&lt;&lt;c.imag&lt;&lt;<span class="hljs-string">&quot;i&quot;</span>;    <span class="hljs-keyword">return</span> os;&#125;istream &amp; <span class="hljs-keyword">operator</span> &gt;&gt;(istream &amp;is,Complex &amp;c)&#123;    string s;    is&gt;&gt;s;    <span class="hljs-type">int</span> pos=s.<span class="hljs-built_in">find</span>(<span class="hljs-string">&#x27;+&#x27;</span>,<span class="hljs-number">0</span>); <span class="hljs-comment">// 默认“a+bi”不能有空格</span>    <span class="hljs-comment">// 此处有个小小的坑：‘-’则不可处理</span>        <span class="hljs-comment">// 分离实部和虚部</span>    string sTmp=s.<span class="hljs-built_in">substr</span>(<span class="hljs-number">0</span>,pos);     c.real=<span class="hljs-built_in">atof</span>(sTmp.<span class="hljs-built_in">c_str</span>()); <span class="hljs-comment">// atof 将const char*指针指向内容转换为float</span>    sTmp=s.<span class="hljs-built_in">substr</span>(pos<span class="hljs-number">+1</span>,s.<span class="hljs-built_in">length</span>()-pos<span class="hljs-number">-2</span>);    <span class="hljs-comment">// 前面pos指的是实际位置-1=长度，取pos可；此处pos指的是+号的pos位置，+1即下一个位置，-2减掉加号和i号</span>    c.imag=<span class="hljs-built_in">atof</span>(sTmp.<span class="hljs-built_in">c_str</span>());    <span class="hljs-keyword">return</span> is;        <span class="hljs-comment">//实际上更推荐现成的 std::stod(sTmp)。它直接支持 std::string，且能处理转换失败的异常，不需要手动调用 .c_str()</span>&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    Complex c;    <span class="hljs-type">int</span> n;    cin&gt;&gt;c&gt;&gt;n;    cout&lt;&lt;c&lt;&lt;<span class="hljs-string">&quot;,&quot;</span>&lt;&lt;n;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h3 id="强制类型转换运算符重载"><a href="#强制类型转换运算符重载" class="headerlink" title="强制类型转换运算符重载"></a>强制类型转换运算符重载</h3><p>在c++语言中，<strong>类型的名字（包括类本身的名字）本身也是一种运算符</strong>，即<strong>强制类型转换运算符</strong></p><ul><li><p>⚠️ <strong>不需要指定返回值类型</strong>，因为运算符就代表返回值类型</p></li><li><p><strong>单</strong>目运算符</p></li><li><p><strong>只</strong>能重载<strong>为成员函数</strong></p></li><li><p>经过适当重载后等价为 <code>对象.operator 类型名()</code></p></li></ul><h4 id="实现（以double重载为例）"><a href="#实现（以double重载为例）" class="headerlink" title="实现（以double重载为例）"></a>实现（以<code>double</code>重载为例）</h4><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span>&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">double</span> real,imag;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r=<span class="hljs-number">0</span>,<span class="hljs-type">double</span> i=<span class="hljs-number">0</span>):<span class="hljs-built_in">real</span>(r),<span class="hljs-built_in">imag</span>(i)&#123;&#125;    <span class="hljs-comment">// ☀️</span>    <span class="hljs-function"><span class="hljs-keyword">operator</span> <span class="hljs-title">double</span><span class="hljs-params">()</span></span>&#123; <span class="hljs-keyword">return</span> real;&#125; <span class="hljs-comment">// 不需要指定返回类型！</span>&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    <span class="hljs-function">Complex <span class="hljs-title">c</span><span class="hljs-params">(<span class="hljs-number">1.2</span>,<span class="hljs-number">3.4</span>)</span></span>;    cout&lt;&lt;(<span class="hljs-type">double</span>)c&lt;&lt;endl;    <span class="hljs-type">double</span> n=<span class="hljs-number">2</span>+c; <span class="hljs-comment">// 等价于 double n=2+c.operator()</span>    cout&lt;&lt;n;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p>🌊有了对 double 运算符的重载，本该出现 double 类型的变量或常量的地方，出现的<strong>Complex类型对象会被自动调用operator double成员函数，然后取其返回值使用</strong></p><h3 id="重载自增、自减运算符"><a href="#重载自增、自减运算符" class="headerlink" title="重载自增、自减运算符"></a>重载自增、自减运算符</h3><p>⚠️ 此处重载应有<strong>前置和后置之分</strong>，前置为返回操作后的值，后置返回操作前的值（再操作），因此：</p><p>C++规定，⚠️ 在重载<strong>自增、自减运算符</strong>时，允许<strong>多编写一个没用的 int 类型形参</strong>→</p><ul><li>处理<strong>前置</strong>表达式，调用<strong>参数个数正常</strong>的重载函数</li><li>⚠️处理<strong>后置</strong>表达式，调用多出一个参数的重载函数</li></ul><h4 id="实现-2"><a href="#实现-2" class="headerlink" title="实现"></a>实现</h4><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CDemo</span>&#123;<span class="hljs-keyword">private</span>:<span class="hljs-type">int</span> n;<span class="hljs-keyword">public</span>:<span class="hljs-built_in">CDemo</span>(<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>):<span class="hljs-built_in">n</span>(i)&#123;&#125;CDemo&amp; <span class="hljs-keyword">operator</span>++(); <span class="hljs-comment">// 前置形式</span>CDemo <span class="hljs-keyword">operator</span>++(<span class="hljs-type">int</span>); <span class="hljs-comment">// 后置形式</span><span class="hljs-function"><span class="hljs-keyword">operator</span> <span class="hljs-title">int</span><span class="hljs-params">()</span></span>&#123; <span class="hljs-keyword">return</span> n;&#125;<span class="hljs-keyword">friend</span> CDemo <span class="hljs-keyword">operator</span>--(CDemo &amp;);<span class="hljs-keyword">friend</span> CDemo <span class="hljs-keyword">operator</span>--(CDemo &amp;,<span class="hljs-type">int</span>);&#125;;<span class="hljs-comment">// 此处 int 是约定不用接变量；其余则是类内声明只需类型，不一定接变量</span><span class="hljs-comment">// 采用CDemo&amp;可以避免一次临时对象的拷贝，且支持 ++++a 这种连续操作</span>CDemo&amp; CDemo::<span class="hljs-keyword">operator</span>++()&#123; <span class="hljs-comment">//返回自身引用</span><span class="hljs-comment">// 前置 ++</span>    n++;    <span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>;&#125;<span class="hljs-comment">// 注意以下需要先存放原来，操作后返回</span>CDemo CDemo::<span class="hljs-keyword">operator</span>++(<span class="hljs-type">int</span> k)&#123; <span class="hljs-comment">//返回一个临时变量</span>    <span class="hljs-comment">// 后置++</span>    <span class="hljs-function">CDemo <span class="hljs-title">tmp</span><span class="hljs-params">(*<span class="hljs-keyword">this</span>)</span></span>; <span class="hljs-comment">//记录修改前的对象</span>    n++;    <span class="hljs-keyword">return</span> tmp;&#125;CDemo <span class="hljs-keyword">operator</span>--(CDemo &amp; c)&#123;    c.n--;    <span class="hljs-keyword">return</span> c;&#125;CDemo <span class="hljs-keyword">operator</span>--(CDemo &amp; c,<span class="hljs-type">int</span> k)&#123;    <span class="hljs-function">CDemo <span class="hljs-title">tmp</span><span class="hljs-params">(c)</span></span>;    c.n--;    <span class="hljs-keyword">return</span> tmp;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    ...&#125;<span class="hljs-comment">// 此处--重载为全局函数为示范，重载为成员函数更佳</span></code></pre><p>对比底层可以发现，<strong>后置效率更低</strong></p>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/55fa/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/55fa/"/>
    <published>2026-03-12T16:00:00.000Z</published>
    <summary>运算符重载：赋予运算符多重语义</summary>
    <title>运算符重载</title>
    <updated>2026-07-21T09:00:26.345Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <content>
      <![CDATA[<h1 id="类和对象进阶"><a href="#类和对象进阶" class="headerlink" title="类和对象进阶"></a>类和对象进阶</h1><h2 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h2><ul><li>🚀<a href="#%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E5%A4%8D%E5%88%B6%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E6%9E%90%E6%9E%84%E5%87%BD%E6%95%B0">构造函数&amp;复制构造函数&amp;析构函数</a><ul><li><a href="#%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0">构造函数</a><ul><li><a href="#%E5%9F%BA%E6%9C%AC%E8%8C%83%E5%BC%8F">基本范式</a></li><li><a href="#%E9%9A%90%E5%BC%8F%E8%BD%AC%E6%8D%A2">隐式转换</a></li></ul></li><li><a href="#%E5%A4%8D%E5%88%B6%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0">复制构造函数</a><ul><li><a href="#%E8%8C%83%E5%BC%8F-1">范式</a></li><li><a href="#%E9%87%8D%E7%82%B9%E8%A2%AB%E8%B0%83%E7%94%A8%E7%9A%84%E4%B8%89%E7%A7%8D%E6%83%85%E5%86%B5">重点：被调用的三种情况</a><ul><li><a href="#1%E5%BD%93%E7%94%A8%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%8E%BB%E5%88%9D%E5%A7%8B%E5%8C%96%E5%90%8C%E7%B1%BB%E7%9A%84%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1">1.当用一个对象去初始化同类的另一个对象</a></li><li><a href="#2%E7%B1%BBa%E7%9A%84%E5%AF%B9%E8%B1%A1%E4%BD%9C%E4%B8%BA%E6%9F%90%E4%B8%AA%E5%87%BD%E6%95%B0%E7%9A%84%E5%8F%82%E6%95%B0">2.类A的对象作为某个函数的参数</a></li><li><a href="#3%E7%B1%BBa%E7%9A%84%E5%AF%B9%E8%B1%A1%E4%BD%9C%E4%B8%BA%E6%9F%90%E4%B8%AA%E5%87%BD%E6%95%B0%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC">3.类A的对象作为某个函数的返回值</a></li></ul></li></ul></li><li><a href="#%E6%9E%90%E6%9E%84%E5%87%BD%E6%95%B0">析构函数</a><ul><li><a href="#%E8%8C%83%E5%BC%8F-2">范式</a></li><li><a href="#%E4%BD%9C%E7%94%A8%E6%83%85%E5%86%B5">作用情况</a></li><li><a href="#%E9%87%8D%E7%82%B9%E7%94%9F%E5%AD%98%E5%91%A8%E6%9C%9F">重点：生存周期</a></li><li><a href="#%E9%9D%99%E6%80%81%E6%88%90%E5%91%98static-%E5%85%B3%E9%94%AE%E5%AD%97">静态成员(static 关键字)</a><ul><li><a href="#%E8%8C%83%E5%BC%8F-3">范式</a></li><li><a href="#%E5%85%B6%E4%BB%96%E6%B3%A8%E6%84%8F%E7%82%B9">其他注意点</a></li><li><a href="#%E5%AE%9E%E6%88%98%E8%8C%83%E4%BE%8B">实战范例</a></li></ul></li></ul></li></ul></li><li>🚀<a href="#this%E6%8C%87%E9%92%88">this指针</a></li><li>🚀<a href="#%E5%B0%81%E9%97%AD%E7%B1%BB">封闭类</a><ul><li><p><a href="#%E6%88%90%E5%91%98%E5%AF%B9%E8%B1%A1">成员对象</a></p></li><li><p><a href="#%E5%B0%81%E9%97%AD%E7%B1%BB%E5%9F%BA%E6%9C%AC%E5%AE%9A%E4%B9%89">封闭类基本定义</a></p><ul><li><a href="#%E7%BB%8F%E5%85%B8%E7%9A%84%E4%BE%8B%E5%AD%90">经典的例子</a></li></ul></li><li><p><a href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E5%88%97%E8%A1%A8">初始化列表</a></p></li><li><p><a href="#%E5%B0%81%E9%97%AD%E7%B1%BB%E4%B8%AD%E6%9E%84%E9%80%A0%E5%92%8C%E6%9E%90%E6%9E%84%E5%87%BD%E6%95%B0%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F">封闭类中构造和析构函数执行顺序</a></p></li><li><p><a href="#%E5%8F%8B%E5%85%83">友元</a></p><ul><li><a href="#%E5%8F%8B%E5%85%83%E5%87%BD%E6%95%B0">友元函数</a></li><li><a href="#%E5%8F%8B%E5%85%83%E7%B1%BB">友元类</a></li></ul><p>**备注：**此处有重要考点：即构造函数、复制构造函数调用顺序（通常 print 测试）</p></li></ul></li></ul><h2 id="构造函数-复制构造函数-析构函数"><a href="#构造函数-复制构造函数-析构函数" class="headerlink" title="构造函数&amp;复制构造函数&amp;析构函数"></a>构造函数&amp;复制构造函数&amp;析构函数</h2><p>⚠️ Tips：</p><ul><li><strong>不定义任何构造函数</strong>（包括<strong>复制构造函数</strong>）的情况下，类会自动生成</li></ul><h3 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h3><ul><li><p><strong>函数名与类名相同</strong></p></li><li><p>类生成<strong>必须调用</strong>（<strong>未设计</strong>情况下<strong>自动生成无参构造函数</strong>，<strong>否则不生成</strong>，不一定需要自己写）</p></li><li><p>可以重载（即：一个类可有多个构造函数，编译器自动选择<strong>可行且唯一</strong>的）</p></li><li><p>无返回值 （⚠️ void也不能写！）</p></li><li><p><strong>不分配</strong>空间，<strong>只初始</strong>化空间</p></li><li><p>对象<strong>一旦生成后</strong>，<strong>不能</strong>在其上执行构造函数</p></li><li><p>⚠️private 的构造函数不能用于初始化</p></li><li><p>⚠️无参构造函数，又称为<strong>默认构造函数</strong>（不管是自动生成的，还是人为创立的）</p></li></ul><h4 id="基本范式"><a href="#基本范式" class="headerlink" title="基本范式"></a>基本范式</h4><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span>&#123;<span class="hljs-keyword">private</span>:<span class="hljs-type">double</span> real,imag;<span class="hljs-keyword">public</span>:    <span class="hljs-comment">// ☀️</span><span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r,<span class="hljs-type">double</span> i=<span class="hljs-number">0</span>);    <span class="hljs-comment">// 若不写，则自动生成无参构造函数</span>    <span class="hljs-comment">// 此时并未自动生成无参构造函数！</span>    <span class="hljs-built_in">Complex</span>(Comlpex c1,Complex c2);    <span class="hljs-comment">//构造函数可重载，但是⚠️这个接受双参数，不是*复制*构造函数！（加了 &amp; 也不是）</span>        <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">set</span><span class="hljs-params">(<span class="hljs-type">double</span> r,<span class="hljs-type">double</span> i)</span></span>&#123;&#125;    <span class="hljs-comment">//不是构造函数！</span>&#125;;Complex::<span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r,<span class="hljs-type">double</span> i)&#123; <span class="hljs-comment">//这里默认初始值不能再写的否则报错</span> real=r; imag=i;    <span class="hljs-comment">// 第二个参数默认为0</span>&#125;Complex::<span class="hljs-built_in">Complex</span>(Complex c1,Complex c2)&#123;    real=c<span class="hljs-number">1.</span>real+c<span class="hljs-number">2.</span>real;    imag=c<span class="hljs-number">1.</span>imag+c<span class="hljs-number">2.</span>imag;&#125;Complex c1; <span class="hljs-comment">// error！</span>Complex *pc = <span class="hljs-keyword">new</span> Complex; <span class="hljs-comment">// error! 未定义也因为定义其他而不会自动生成无参构造函数</span><span class="hljs-function">Complex <span class="hljs-title">c2</span><span class="hljs-params">(<span class="hljs-number">2</span>)</span></span>; <span class="hljs-comment">// ok</span><span class="hljs-function">Complex <span class="hljs-title">c3</span><span class="hljs-params">(<span class="hljs-number">2</span>,<span class="hljs-number">4</span>)</span></span>; <span class="hljs-comment">// ok</span>Complex *pc2 = <span class="hljs-keyword">new</span> <span class="hljs-built_in">Complex</span>(<span class="hljs-number">3</span>,<span class="hljs-number">4</span>) <span class="hljs-comment">// ok</span>Complex <span class="hljs-built_in">c4</span>(c2,c3); <span class="hljs-comment">// ok!</span></code></pre><h4 id="隐式转换"><a href="#隐式转换" class="headerlink" title="隐式转换"></a>隐式转换</h4><blockquote><p>在有合适的构造函数的情况下,且运行时需要就会自动进行隐式转换</p></blockquote><pre><code class="hljs C++">Complex c1 = <span class="hljs-number">7</span><span class="hljs-comment">//隐式转换 Complex(7) 时调用一次输出，复制构造函数调用（但是不输出）</span><span class="hljs-comment">// 实质：7→隐式构造Complex(7)→调用自动生成的默认复制构造函数来初始化c1</span>Complex c2=<span class="hljs-built_in">Comlpex</span>(<span class="hljs-number">7</span>)<span class="hljs-comment">//生成 Complex(7) 时调用一次普通构造函数输出，然后初始化调用复制构造函数（但是不输出）</span>    <span class="hljs-comment">// 所以两次都会 &quot;Constuctor called&quot;，结果相同</span>   Complex c2=c1<span class="hljs-comment">// 不调用带参数的构造函数，不输出</span></code></pre><p>破案：编译器优化～</p><p>🤨比较奇怪的现象：(有点类似于复制省略)</p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260312204107122.png" alt="image-2026031220410712"></p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260312205156893.png" alt="image-20260312205156893"></p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260312205216895.png" alt="image-20260312205216895"></p><h4 id="类型转换构造函数"><a href="#类型转换构造函数" class="headerlink" title="类型转换构造函数"></a>类型转换构造函数</h4><p><strong>只有一个参数</strong>，参数类型可为多样，能够起到强制类型转换的作用（把数字隐式转换为一个临时对象）</p><p>原因如下：</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span>&#123;<span class="hljs-keyword">public</span>:<span class="hljs-type">double</span> real,imag;<span class="hljs-built_in">Complex</span>(<span class="hljs-type">int</span> i)&#123;...&#125; <span class="hljs-comment">//类型转换构造函数</span><span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r,<span class="hljs-type">double</span> i)&#123;...&#125;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;<span class="hljs-function">Complex <span class="hljs-title">c1</span><span class="hljs-params">(<span class="hljs-number">7</span>,<span class="hljs-number">8</span>)</span></span>;Complex c2=<span class="hljs-number">12</span>; <span class="hljs-comment">// 是初始化语句！不是赋值！</span>c1=<span class="hljs-number">9</span>; <span class="hljs-comment">// 9 将被自动创建为一个临时的 Complex 对象 Complex(9)</span>cout&lt;&lt;c<span class="hljs-number">1.</span>real&lt;&lt;<span class="hljs-string">&quot;,&quot;</span>&lt;&lt;c<span class="hljs-number">1.</span>imag&lt;&lt;endl;<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p>🤨 <code>Complex c2=12; // 是初始化语句！不是赋值！</code>会调用复制构造函数吗？</p><blockquote><p>可以采用explicit关键字防止隐式转换（不过vscode好像直接宰了）</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span>&#123;<span class="hljs-keyword">public</span>:<span class="hljs-type">double</span> real,imag;<span class="hljs-function"><span class="hljs-keyword">explicit</span> <span class="hljs-title">Complex</span><span class="hljs-params">(<span class="hljs-type">int</span> i)</span></span>&#123;...&#125; <span class="hljs-comment">//类型转换构造函数</span><span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r,<span class="hljs-type">double</span> i)&#123;...&#125;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;<span class="hljs-function">Complex <span class="hljs-title">c1</span><span class="hljs-params">(<span class="hljs-number">7</span>,<span class="hljs-number">8</span>)</span></span>;Complex c2=<span class="hljs-built_in">Complex</span>(<span class="hljs-number">12</span>); <span class="hljs-comment">// c1=9; //error!</span>    c1=<span class="hljs-built_in">Complex</span>(<span class="hljs-number">9</span>);cout&lt;&lt;c<span class="hljs-number">1.</span>real&lt;&lt;<span class="hljs-string">&quot;,&quot;</span>&lt;&lt;c<span class="hljs-number">1.</span>imag&lt;&lt;endl;<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260312210504664.png" alt="image-20260312210504664"></p></blockquote><blockquote><p>强制复制消除,不调用复制构造函数(优化掉)</p></blockquote><h3 id="复制构造函数"><a href="#复制构造函数" class="headerlink" title="复制构造函数"></a>复制构造函数</h3><p><u>属于构造函数的一种</u>，也称为<strong>拷贝构造函数</strong>，<strong>只有一个参数</strong>，参数类型为<strong>本类的引用</strong></p><ul><li><strong>不编写</strong>则编译器会<strong>自动生成-默认复制构造函数</strong>。（如果<strong>自己编写</strong>了，<strong>默认复制构造函数就不存在了</strong>，而且可以发现自己写的不一定要“复制“）</li></ul><h4 id="范式"><a href="#范式" class="headerlink" title="范式"></a>范式</h4><pre><code class="hljs C++"><span class="hljs-comment">// 第一种</span><span class="hljs-built_in">Complex</span>(<span class="hljs-type">const</span> Complex &amp; a)&#123;&#125;<span class="hljs-comment">// 第二种</span><span class="hljs-built_in">Complex</span>(Complex &amp; a)&#123;&#125;<span class="hljs-comment">// 或者先声明再Complex::Complex()&#123;&#125;亦可</span></code></pre><p><strong>注意⚠️：</strong></p><ul><li><p><strong>const版本接收范围更广一些，可以接收const Complex &amp;a 和Complex &amp;a</strong>，而<strong>无const</strong>版本<strong>只</strong>能接收<strong>后者</strong>（因可实现修改，无法保证const传入不被修改）</p></li><li><p><strong>禁止以本类的对象作为唯一参数</strong>，即</p><p>⚠️<code>Complex(Complex c){} \\  ❌error!</code> 因为调用时将生成一份，这一份又要生成一份，这一份又要生成一份…死循环</p></li></ul><blockquote><p>理论上，复制构造函数可以重载并调用最佳匹配，但是一般不建议<br>传统上：</p><pre><code class="hljs C++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">class</span> <span class="hljs-title class_">MyClass</span> &#123;<span class="hljs-keyword">public</span>: <span class="hljs-built_in">MyClass</span>() = <span class="hljs-keyword">default</span>; <span class="hljs-built_in">MyClass</span>(MyClass&amp;)      &#123; std::cout &lt;&lt; <span class="hljs-string">&quot;non-const lvalue\n&quot;</span>; &#125; <span class="hljs-built_in">MyClass</span>(<span class="hljs-type">const</span> MyClass&amp;)&#123; std::cout &lt;&lt; <span class="hljs-string">&quot;const lvalue\n&quot;</span>; &#125;&#125;;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123; MyClass a; <span class="hljs-type">const</span> MyClass b; MyClass c = a;  <span class="hljs-comment">// 非 const 左值 -&gt; 调用 non-const lvalue</span> MyClass d = b;  <span class="hljs-comment">// const 左值 -&gt; 调用 const lvalue</span> MyClass e = <span class="hljs-built_in">MyClass</span>(); <span class="hljs-comment">// 临时对象（右值） -&gt; 调用 const lvalue（C++98/11 都如此,编译器优化可能会产生拷贝消除而不输出）</span>&#125;</code></pre><p>输出:</p><pre><code class="hljs txt">non-const lvalueconst lvalueconst lvalue</code></pre><p>此外，自己编写的复制构造函数并<strong>不一定要做复制操作</strong>，但习惯上还是保持类似于复制操作为佳</p></blockquote><h4 id="重点：被调用的三种情况"><a href="#重点：被调用的三种情况" class="headerlink" title="重点：被调用的三种情况"></a>重点：被调用的三种情况</h4><h5 id="1-当用一个对象去初始化同类的另一个对象"><a href="#1-当用一个对象去初始化同类的另一个对象" class="headerlink" title="1.当用一个对象去初始化同类的另一个对象"></a>1.当用一个对象去初始化同类的另一个对象</h5><pre><code class="hljs c++"><span class="hljs-function">Complex <span class="hljs-title">c2</span><span class="hljs-params">(c1)</span></span>; <span class="hljs-comment">// copy constructor called</span>Complex c2=c1; <span class="hljs-comment">// copy constructor called</span>c1=c2; <span class="hljs-comment">// ❌empty output! 仅仅只是赋值，并未调用复制构造函数！</span></code></pre><p><strong>⚠️：对象间用等号赋值不</strong>导致调用复制构造函数</p><h5 id="2-类A的对象作为某个函数的参数"><a href="#2-类A的对象作为某个函数的参数" class="headerlink" title="2.类A的对象作为某个函数的参数"></a>2.类A的对象作为某个函数的参数</h5><p>函数被调用时，将调用复制构造函数</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>&#123;<span class="hljs-keyword">public</span>:<span class="hljs-built_in">A</span>()&#123;&#125;;    <span class="hljs-comment">// ☀️</span><span class="hljs-built_in">A</span>(<span class="hljs-type">const</span> A &amp;)&#123; cout&lt;&lt;<span class="hljs-string">&quot;copy constructor called!&quot;</span>&lt;&lt;endl;&#125;    <span class="hljs-comment">//也可以A(const A &amp;a)&#123; cout&lt;&lt;&quot;copy constructor called!&quot;&lt;&lt;endl;&#125;</span>&#125;;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Func</span><span class="hljs-params">(A a)</span></span>&#123;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;A a;<span class="hljs-built_in">Func</span>(a);<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;<span class="hljs-comment">// 会发现此处的形参不一定等于实参，取决于复制构造函数怎么写</span></code></pre><h5 id="3-类A的对象作为某个函数的返回值"><a href="#3-类A的对象作为某个函数的返回值" class="headerlink" title="3.类A的对象作为某个函数的返回值"></a>3.类A的对象作为某个函数的返回值</h5><p>函数返回时，复制构造函数被调用</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>&#123;<span class="hljs-keyword">public</span>:<span class="hljs-type">int</span> v;<span class="hljs-built_in">A</span>(<span class="hljs-type">int</span> n) &#123; v = n; &#125;;<span class="hljs-built_in">A</span>(<span class="hljs-type">const</span> A&amp;a) &#123;         v = a.v;        cout &lt;&lt; <span class="hljs-string">&quot;Copy constructor called&quot;</span> &lt;&lt;endl;&#125; &#125;;<span class="hljs-comment">// ☀️</span><span class="hljs-function">A <span class="hljs-title">Func</span><span class="hljs-params">()</span> </span>&#123; <span class="hljs-function">A <span class="hljs-title">b</span><span class="hljs-params">(<span class="hljs-number">4</span>)</span></span>; <span class="hljs-keyword">return</span> b; &#125;<span class="hljs-comment">// 生成Func()调用复制构造函数，其实参来源于b</span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><span class="hljs-function"></span>&#123;     cout &lt;&lt; <span class="hljs-built_in">Func</span>().v &lt;&lt; endl;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; &#125;<span class="hljs-comment">// 此处临时对象在经过现代编译器优化后可能结果有所不同--拷贝消除（但我们默认会调用复制构造函数）</span></code></pre><blockquote><p>编译器优化不大同于移动构造函数和复制构造函数</p></blockquote><h3 id="析构函数"><a href="#析构函数" class="headerlink" title="析构函数"></a>析构函数</h3><ul><li><p>函数名即<code>~类名</code></p></li><li><p>一个类最多一个</p></li><li><p>默认自动生成，定义后则不自动生成（<strong>缺省析构函数什么也不做</strong>，最多确认基类的析构函数被调用）</p></li><li><p><strong>对象消亡时自动被调用</strong></p></li><li><p>⚠️<strong>动态分配的构造函数要手动写析构函数</strong></p></li></ul><h4 id="范式-1"><a href="#范式-1" class="headerlink" title="范式"></a>范式</h4><p><code>~类名(){}</code></p><p>或</p><p><code>~类名(); //声明</code></p><p><code>类名::~类名(){} //定义 </code> </p><h4 id="作用情况"><a href="#作用情况" class="headerlink" title="作用情况"></a>作用情况</h4><ol><li><p>delete 触发消亡→析构</p></li><li><p><strong>作用范围结束</strong>触发消亡→析构</p></li></ol><p>  （如：main 函数结束变量消亡、局部范围（如函数和{}）结束局部变量消亡）</p><ol start="3"><li><p>作为<strong>函数形参</strong>→函数结尾消亡</p><p>  （注：引用和指针形参不属于对象，消亡对实参对象无影响）</p><blockquote><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">foo</span><span class="hljs-params">(MyClass obj)</span> </span>&#123; &#125;      <span class="hljs-comment">// obj 是独立对象，函数结束 obj 析构</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">bar</span><span class="hljs-params">(MyClass&amp; ref)</span> </span>&#123; &#125;     <span class="hljs-comment">// ref 只是实参的别名，函数结束&quot;别名&quot;消失</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">baz</span><span class="hljs-params">(MyClass* ptr)</span> </span>&#123; &#125;     <span class="hljs-comment">// ptr 存的是地址，函数结束&quot;地址变量&quot;消失</span></code></pre></blockquote></li><li><p>作为函数返回值→return的东西消亡</p></li></ol><h4 id="重点：生存周期"><a href="#重点：生存周期" class="headerlink" title="重点：生存周期"></a>重点：生存周期</h4><p>经典范例1：</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Demo</span> &#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> id;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">Demo</span>(<span class="hljs-type">int</span> i) &#123;        id = i;        <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;id=%d, Construct\n&quot;</span>, id);    &#125;    ~<span class="hljs-built_in">Demo</span>() &#123;        <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;id=%d, Destruct\n&quot;</span>, id);    &#125;&#125;;<span class="hljs-function">Demo <span class="hljs-title">d1</span><span class="hljs-params">(<span class="hljs-number">1</span>)</span></span>;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-function"><span class="hljs-type">static</span> Demo <span class="hljs-title">d2</span><span class="hljs-params">(<span class="hljs-number">2</span>)</span></span>;    <span class="hljs-function">Demo <span class="hljs-title">d3</span><span class="hljs-params">(<span class="hljs-number">3</span>)</span></span>;    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;fun \n&quot;</span>);&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-function">Demo <span class="hljs-title">d4</span><span class="hljs-params">(<span class="hljs-number">4</span>)</span></span>;    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;main \n&quot;</span>);    &#123;        <span class="hljs-function">Demo <span class="hljs-title">d5</span><span class="hljs-params">(<span class="hljs-number">5</span>)</span></span>;    &#125;    <span class="hljs-built_in">fun</span>();    <span class="hljs-built_in">printf</span>(<span class="hljs-string">&quot;endmain \n&quot;</span>);    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p>output:</p><pre><code class="hljs text">id=1, Constructid=4, Constructmainid=5, Constructid=5, Destructid=2, Constructid=3, Constructfunid=3, Destructendmainid=4, Destructid=2, Destructid=1, Destruct</code></pre><p>经典范例2：</p><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CMyclass</span> &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">CMyclass</span>() &#123;&#125;;    <span class="hljs-built_in">CMyclass</span>(CMyclass &amp;c) &#123;        cout &lt;&lt; <span class="hljs-string">&quot;copy constructor&quot;</span> &lt;&lt; endl;    &#125;    ~<span class="hljs-built_in">CMyclass</span>() &#123;        cout &lt;&lt; <span class="hljs-string">&quot;destructor&quot;</span> &lt;&lt; endl;    &#125;&#125;;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">fun</span><span class="hljs-params">(CMyclass obj_)</span> </span>&#123;    cout &lt;&lt; <span class="hljs-string">&quot;fun&quot;</span> &lt;&lt; endl;&#125;CMyclass c;<span class="hljs-function">CMyclass <span class="hljs-title">Test</span><span class="hljs-params">()</span> </span>&#123;    cout &lt;&lt; <span class="hljs-string">&quot;test&quot;</span> &lt;&lt; endl;    <span class="hljs-keyword">return</span> c;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    CMyclass c1;    <span class="hljs-built_in">fun</span>(c1);    <span class="hljs-built_in">Test</span>();    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><p>output:</p><pre><code class="hljs text">copy constructorfundestructor //参数消亡testcopy constructordestructor // 返回值临时对象消亡destructor // 局部变量消亡destructor // 全局变量消亡</code></pre><h4 id="静态成员-static-关键字"><a href="#静态成员-static-关键字" class="headerlink" title="静态成员(static 关键字)"></a>静态成员(static 关键字)</h4><p>⚠️ <strong>本质</strong>上属于<strong>全局变量</strong>，写进类里是为了<strong>形式上为一个整体</strong>，易于维护和理解</p><ul><li>静态成员变量<strong>只有一份</strong>，为<strong>同类的所有对象共享</strong>⚠️</li><li><strong>静态成员变量必须在类定义外面专门定义一下</strong>，<code>T 类名::变量名</code>（可选择进一步直接赋值）</li><li>静态成员函数<strong>不具体作用在某个对象上</strong></li><li><code>sizeof()</code><strong>计算不包含静态成员</strong>⚠️</li><li><strong>静态</strong>成员函数<strong>不能调用this指针</strong>（因为静态成员不具体作用于某个对象）</li></ul><h5 id="范式-2"><a href="#范式-2" class="headerlink" title="范式"></a>范式</h5><p><code>类名：：成员名</code> <strong>不需对象即可访问</strong></p><p>（甚至可以在还未有对象生成时访问一个类的静态成员；普通访问方式也适用，但无意义）</p><h5 id="其他注意点🔥🔥"><a href="#其他注意点🔥🔥" class="headerlink" title="其他注意点🔥🔥"></a>其他注意点🔥🔥</h5><blockquote><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">staticFunc</span><span class="hljs-params">(Foo&amp; obj)</span> </span>&#123;    obj.val++;        <span class="hljs-comment">// ✅ 现在知道是哪个对象了</span>    obj.<span class="hljs-built_in">nonStatic</span>();  <span class="hljs-comment">// ✅ 可以调用</span>&#125;</code></pre><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span> &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-type">static</span> <span class="hljs-type">int</span> s_val;    <span class="hljs-type">int</span> val;    <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">staticFunc</span><span class="hljs-params">()</span> </span>&#123;        s_val++;      <span class="hljs-comment">// ✅ 可以访问静态成员</span>        <span class="hljs-comment">// val++;     // ❌ 编译错误！不知道 val 属于哪个对象</span>        <span class="hljs-comment">// nonStatic(); // ❌ 同样错误</span>    &#125;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">nonStatic</span><span class="hljs-params">()</span> </span>&#123;        val++;        <span class="hljs-comment">// ✅ 编译器隐式做了 this-&gt;val++</span>    &#125;&#125;;</code></pre></blockquote><ul><li><p><strong>静态</strong>成员<strong>不具体作用于某个对象</strong>，因此：</p><ul><li>静态<strong>成员函数内部</strong>不能访问 <strong>非静态成员变量和函数</strong> （因为它搞不清非静态成员是谁）</li></ul></li><li><p><strong>静态</strong>成员函数的<strong>真实参数个数</strong>就是<strong>程序写的个数</strong>（普通成员函数还要加上this指针）</p></li></ul><h5 id="实战范例"><a href="#实战范例" class="headerlink" title="实战范例"></a>实战范例</h5><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CRectangle</span>&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">int</span> w, h;    <span class="hljs-type">static</span> <span class="hljs-type">int</span> totalArea;      <span class="hljs-comment">// 矩形总面积（静态成员变量声明）</span>    <span class="hljs-type">static</span> <span class="hljs-type">int</span> totalNumber;    <span class="hljs-comment">// 矩形总数（静态成员变量声明）</span><span class="hljs-keyword">public</span>:    <span class="hljs-built_in">CRectangle</span>(<span class="hljs-type">int</span> w_, <span class="hljs-type">int</span> h_);         <span class="hljs-built_in">CRectangle</span>(<span class="hljs-type">const</span> CRectangle &amp; other);      ~<span class="hljs-built_in">CRectangle</span>();          <span class="hljs-function"><span class="hljs-type">static</span> <span class="hljs-type">void</span> <span class="hljs-title">PrintTotal</span><span class="hljs-params">()</span></span>;               &#125;;<span class="hljs-comment">// 静态成员变量定义并初始化（必须在类外进行，否则链接错误——静态成员不类外定义→未分配内存找不到）</span><span class="hljs-type">int</span> CRectangle::totalNumber = <span class="hljs-number">0</span>;<span class="hljs-type">int</span> CRectangle::totalArea = <span class="hljs-number">0</span>;CRectangle::<span class="hljs-built_in">CRectangle</span>(<span class="hljs-type">int</span> w_, <span class="hljs-type">int</span> h_)&#123;    w = w_;    h = h_;    totalNumber++;          <span class="hljs-comment">// 新对象产生，总数加1</span>    totalArea += w * h;      <span class="hljs-comment">// 新对象产生，总面积增加</span>&#125;<span class="hljs-comment">// 复制构造函数实现（要记得！确保程序正确）</span>CRectangle::<span class="hljs-built_in">CRectangle</span>(<span class="hljs-type">const</span> CRectangle &amp; other)&#123;    w = other.w;    h = other.h;    totalNumber++;          <span class="hljs-comment">// 复制产生新对象，总数加1</span>    totalArea += w * h;      <span class="hljs-comment">// 新对象面积加入总面积</span>&#125;CRectangle::~<span class="hljs-built_in">CRectangle</span>()&#123;    totalNumber--;           <span class="hljs-comment">// 对象消亡，总数减1</span>    totalArea -= w * h;      <span class="hljs-comment">// 对象消亡，总面积减少</span>&#125;<span class="hljs-comment">// 静态成员函数实现：输出当前总数和总面积</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CRectangle::PrintTotal</span><span class="hljs-params">()</span></span><span class="hljs-function"></span>&#123;    cout &lt;&lt; totalNumber &lt;&lt; <span class="hljs-string">&quot;, &quot;</span> &lt;&lt; totalArea &lt;&lt; endl;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span><span class="hljs-function"></span>&#123;    <span class="hljs-function">CRectangle <span class="hljs-title">r1</span><span class="hljs-params">(<span class="hljs-number">3</span>, <span class="hljs-number">3</span>)</span>, <span class="hljs-title">r2</span><span class="hljs-params">(<span class="hljs-number">2</span>, <span class="hljs-number">2</span>)</span></span>;    <span class="hljs-comment">// cout &lt;&lt; CRectangle::totalNumber; // 错误：totalNumber 是私有的，不能直接访问</span>    CRectangle::<span class="hljs-built_in">PrintTotal</span>();  <span class="hljs-comment">// 通过类名调用静态函数</span>    r<span class="hljs-number">1.</span><span class="hljs-built_in">PrintTotal</span>();           <span class="hljs-comment">// 通过对象调用静态函数（效果相同）</span>    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h2 id="this指针"><a href="#this指针" class="headerlink" title="this指针"></a>this指针</h2><p>核心作用：<strong>指向成员函数所作用的对象</strong>，即<strong>指向当前对象自己</strong>的指针</p><p>（<strong>非静态</strong>成员函数中可以使用 this 来代表 指向调用该成员函数的当前对象的指针）</p><blockquote><p>官方的，<strong>非静态</strong>成员函数中可以使用 this 来代表 指向该函数作用的对象的指针（作用的对象其实也就是当前的对象）</p></blockquote><p><strong>最最最重要的用途：</strong></p><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-keyword">class</span> <span class="hljs-title">Complex</span><span class="hljs-params">()</span></span>&#123;<span class="hljs-keyword">public</span>:<span class="hljs-type">double</span> real,imag;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">()</span></span>&#123;cout&lt;&lt;real&lt;&lt;<span class="hljs-string">&quot;,&quot;</span>&lt;&lt;imag;&#125;<span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r,<span class="hljs-type">double</span> i):<span class="hljs-built_in">real</span>(r),<span class="hljs-built_in">imag</span>(i)&#123;&#125;<span class="hljs-function">Complex <span class="hljs-title">AddOne</span><span class="hljs-params">()</span></span>&#123;real++; <span class="hljs-comment">// 底层：this-&gt;real++;</span><span class="hljs-built_in">print</span>(); <span class="hljs-comment">// 底层：this-&gt;print();</span><span class="hljs-keyword">return</span> *<span class="hljs-keyword">this</span>; <span class="hljs-comment">//⚠️⚠️⚠️操作自己的唯一方式</span>&#125;&#125;;</code></pre><blockquote><p>C 和 C++ 的类比</p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260312223740691.png" alt="image-20260312223740691"></p><p>一些神奇的思考</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123;    <span class="hljs-type">int</span> i;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Hello</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; <span class="hljs-string">&quot;hello&quot;</span> &lt;&lt; endl; &#125;&#125;; <span class="hljs-comment">// void Hello( A * this ) &#123; cout &lt;&lt; &quot;hello&quot; &lt;&lt; endl; &#125;</span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    A * p = <span class="hljs-literal">NULL</span>;    p-&gt;<span class="hljs-built_in">Hello</span>(); <span class="hljs-comment">// 底层转换为 Hello(p);</span>&#125; <span class="hljs-comment">//输出：hello</span><span class="hljs-comment">// 此刻不涉及指针的具体内容（Null），传入后无所谓</span><span class="hljs-comment">// 注：此做法可能会产生未定义行为</span></code></pre><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123;    <span class="hljs-type">int</span> i;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Hello</span><span class="hljs-params">()</span> </span>&#123; cout &lt;&lt; i &lt;&lt; <span class="hljs-string">&quot;hello&quot;</span> &lt;&lt; endl; &#125;&#125;;<span class="hljs-comment">// void Hello( A * this ) &#123; cout &lt;&lt; this-&gt;i &lt;&lt; &quot;hello&quot; &lt;&lt; endl; &#125;</span><span class="hljs-comment">// this若为NULL，则出错</span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    A * p = <span class="hljs-literal">NULL</span>;    p-&gt;<span class="hljs-built_in">Hello</span>(); <span class="hljs-comment">// Hello(p);</span>&#125;<span class="hljs-comment">// 此时 this 为 Null ，但是要求访问 i ，错误！</span></code></pre></blockquote><p>**备注：**此处又为重要考点：即封闭类，为垒土成山的基石</p><h2 id="封闭类"><a href="#封闭类" class="headerlink" title="封闭类"></a>封闭类</h2><h3 id="成员对象"><a href="#成员对象" class="headerlink" title="成员对象"></a>成员对象</h3><p>一个类A的对象a作为另一个类B的成员变量，则a为B的成员对象</p><p>（可以说a这个B的成员变量是一个成员对象，也可以说a这个A的对象是B的成员对象）</p><h3 id="封闭类基本定义"><a href="#封闭类基本定义" class="headerlink" title="封闭类基本定义"></a>封闭类基本定义</h3><p>包含<strong>成员对象</strong>的类，即称为<strong>封闭类</strong></p><h4 id="经典的例子"><a href="#经典的例子" class="headerlink" title="经典的例子"></a>经典的例子</h4><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">CTyre</span>&#123;<span class="hljs-keyword">private</span>:<span class="hljs-type">int</span> radius;<span class="hljs-type">int</span> width;<span class="hljs-keyword">public</span>:<span class="hljs-built_in">Ctyre</span>(<span class="hljs-type">int</span> r,<span class="hljs-type">int</span> w):<span class="hljs-built_in">radius</span>(r),<span class="hljs-built_in">width</span>(w)&#123;&#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CEngine</span>&#123;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CCar</span>&#123;<span class="hljs-keyword">private</span>:     <span class="hljs-type">int</span> price;    Ctyre tyre;    CEngine engine;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">CCar</span>(<span class="hljs-type">int</span> p,<span class="hljs-type">int</span> tr,<span class="hljs-type">int</span> tw);&#125;;CCar::<span class="hljs-built_in">CCar</span>(<span class="hljs-type">int</span> p,<span class="hljs-type">int</span> tr,<span class="hljs-type">int</span> tw):<span class="hljs-built_in">price</span>(p),<span class="hljs-built_in">tyre</span>(tr,tw)&#123;&#125;<span class="hljs-comment">// CEngine 调用默认构造函数初始化</span><span class="hljs-comment">// CTyre 无默认构造函数，必须初始化列表赋值！（否则编译器不知道如何初始化）</span><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;    <span class="hljs-function">CCar <span class="hljs-title">car</span><span class="hljs-params">(<span class="hljs-number">20000</span>,<span class="hljs-number">17</span>,<span class="hljs-number">225</span>)</span></span>;    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h3 id="初始化列表"><a href="#初始化列表" class="headerlink" title="初始化列表"></a>初始化列表</h3><pre><code class="hljs c++">类名::构造函数名(‘类型 参数’表)：成员变量<span class="hljs-number">1</span>(参数表),成员变量<span class="hljs-number">2</span>(参数表),...&#123;...&#125;</code></pre><p>初始化列表中的成员变量，既可以是成员对象，也可以是基本类型的成员变量</p><ul><li><p>对于<strong>成员对象</strong>，“参数表”中放的就是<strong>成员对象构造函数的参数</strong></p></li><li><p>对于基本类型的成员变量，“参数表”中即初始值</p></li><li><p>关键是要<strong>让编译器弄明白成员对象如何初始化</strong>，否则编译出错</p></li><li><p>⚠️参数可以是<strong>复杂表达式</strong>（全局函数、字符串拼接、复杂算数表达式…）</p></li></ul><p>⚠️：初始化列表和{…}内赋值似乎作用相同，然而以下情况<strong>必须使用初始化列表</strong>！</p><ol><li><p>const 成员**：必须在创建时初始化（<strong>因为不能赋值</strong>）</p></li><li><p>⚠️引用成员**：必须在<strong>定义时绑定对象</strong>！</p></li><li><p>🔥没有默认构造函数的类类型成员**：未初始化不可赋值！</p></li></ol><pre><code class="hljs c++"><span class="hljs-comment">// 参见如下示例</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">Member</span>&#123;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">Member</span>(<span class="hljs-type">int</span> x)&#123;&#125;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">MyClass</span>&#123;    <span class="hljs-type">const</span> <span class="hljs-type">int</span> c;    <span class="hljs-type">int</span>&amp; ref;    Member m;    <span class="hljs-built_in">MyClass</span>(<span class="hljs-type">int</span> &amp; r):<span class="hljs-built_in">c</span>(<span class="hljs-number">100</span>),<span class="hljs-built_in">ref</span>(r),<span class="hljs-built_in">m</span>(<span class="hljs-number">200</span>)&#123;        <span class="hljs-comment">// c=100; // error! 常量不可赋值！</span>        <span class="hljs-comment">// ref=&amp;r; //error! 引用必定在初始化绑定！</span>        <span class="hljs-comment">//  m=Member(200); // error! //未初始化，不可赋值！</span>    &#125;&#125;;</code></pre><h3 id="封闭类中构造和析构函数执行顺序"><a href="#封闭类中构造和析构函数执行顺序" class="headerlink" title="封闭类中构造和析构函数执行顺序"></a>封闭类中构造和析构函数执行顺序</h3><p>⚠️ <strong>先拼组件，再合装为成品&#x2F;先拆成组件，组件再拆成碎片</strong></p><p>（只需记住上面👆这点即可）</p><p>构造：</p><ul><li>先执行成员对象构造函数</li><li>再执行封闭类自己的构造函数</li></ul><p>析构：</p><ul><li><p>先执行封闭类的析构函数</p></li><li><p>然后再执行成员对象的析构函数</p><p>⚠️ 对象成员的构造函数调用次序取决于对象成员在<strong>类中的说明次序</strong>，<strong>与在初始化列表出现次序无关</strong></p><blockquote><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span> &#123;    <span class="hljs-type">int</span> x;    <span class="hljs-type">int</span> y;<span class="hljs-keyword">public</span>:    <span class="hljs-built_in">A</span>() : <span class="hljs-built_in">y</span>(<span class="hljs-number">1</span>), <span class="hljs-built_in">x</span>(y) &#123; &#125;  <span class="hljs-comment">// 初始化列表先写 y，但 x 先构造</span>&#125;;</code></pre><p>实际构造顺序：</p><ol><li><code>x</code> 先构造（类中先声明）</li><li><code>y</code> 后构造（类中后声明）</li></ol><p>所以 <code>x(y)</code> 用的是<strong>未初始化的 <code>y</code></strong>，结果是<strong>未定义行为</strong>。</p><p>编译器通常会给你<strong>警告</strong>（warning），但不会报错，因为语法上是合法的。C++ 标准明确规定：初始化列表的顺序<strong>不影响</strong>实际构造顺序</p></blockquote></li></ul><h3 id="友元"><a href="#友元" class="headerlink" title="友元"></a>友元</h3><ul><li>一言以蔽之，<strong>方便访问别类的私有成员</strong>（但此处<strong>不具有对称性</strong>，即<del>你认为我是你的朋友，但我不一定</del>）</li><li>友元关系<strong>不能传递</strong>！<strong>不能继承</strong>！（参见继承章节）</li></ul><h4 id="友元函数"><a href="#友元函数" class="headerlink" title="友元函数"></a>友元函数</h4><p><strong>一个类的友元函数可以访问这个类的私有成员</strong></p><pre><code class="hljs c++"><span class="hljs-comment">// 一般的</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">total_func</span><span class="hljs-params">()</span></span>&#123;&#125;<span class="hljs-keyword">class</span> <span class="hljs-title class_">B</span>&#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">function</span><span class="hljs-params">()</span></span>;&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>&#123;    <span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-type">void</span> <span class="hljs-title">total_func</span><span class="hljs-params">()</span></span>;<span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-type">void</span> <span class="hljs-title">B::function</span><span class="hljs-params">()</span></span>; &#125;;</code></pre><p>请参看如下具体示例：</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">CCar</span>; <span class="hljs-comment">//声明下用</span><span class="hljs-comment">// 此处因为产生了互相套用的情况，因此要提前声明，只调整顺序无效；友元关系只是声明不造成循环嵌套</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">CDriver</span>&#123;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ModifyCar</span><span class="hljs-params">( CCar * pCar)</span></span>; <span class="hljs-comment">//改装汽车</span>&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CCar</span>&#123;<span class="hljs-keyword">private</span>:<span class="hljs-type">int</span> price;<span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-type">int</span> <span class="hljs-title">MostExpensiveCar</span><span class="hljs-params">( CCar cars[],<span class="hljs-type">int</span> total)</span></span>; <span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-type">void</span> <span class="hljs-title">CDriver::ModifyCar</span><span class="hljs-params">(CCar *pCar)</span></span>;&#125;; <span class="hljs-comment">//// 声明友元</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">CDriver::ModifyCar</span><span class="hljs-params">(CCar *pCar)</span></span>&#123;    pCar-&gt;price+=<span class="hljs-number">1000</span>; <span class="hljs-comment">// 友元成员函数可以使之改装后增值</span>&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">MostExpensiveCar</span><span class="hljs-params">(CCar cars[],<span class="hljs-type">int</span> total)</span></span>&#123;    <span class="hljs-type">int</span> tmpMax=<span class="hljs-number">-1</span>;    <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> i=<span class="hljs-number">0</span>;i&lt;total;i++)&#123;        <span class="hljs-keyword">if</span>(cars[i].price&gt;tmpMax) tmpMax=cars[i].price; <span class="hljs-comment">// 友元函数可以访问私有成员变量</span>    &#125;    <span class="hljs-keyword">return</span> tmpMax;&#125;</code></pre><h4 id="友元类"><a href="#友元类" class="headerlink" title="友元类"></a>友元类</h4><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">CCar</span>&#123;<span class="hljs-keyword">private</span>:<span class="hljs-type">int</span> price;<span class="hljs-keyword">friend</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">CDriver</span>; <span class="hljs-comment">// 声明CDriver为友元类</span>    <span class="hljs-comment">// ⚠️ 此处本就是声明 CDriver是一个类，故前面无需再次声明</span>&#125;;<span class="hljs-keyword">class</span> <span class="hljs-title class_">CDriver</span>&#123;<span class="hljs-keyword">public</span>:CCar myCar;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">ModifyCar</span><span class="hljs-params">()</span></span>&#123; <span class="hljs-comment">//改装汽车</span>myCar.price += <span class="hljs-number">1000</span>;         <span class="hljs-comment">//因CDriver是CCar的友元类, 故此处可以访问其私有成员</span>&#125; &#125;;</code></pre><p>⚠️ <del>你以为我是你的朋友，但我可不一定这么看</del></p>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/9c61/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/9c61/"/>
    <published>2026-03-11T16:00:00.000Z</published>
    <summary>构造函数、复制构造与析构函数</summary>
    <title>类和对象进阶</title>
    <updated>2026-07-21T09:00:21.960Z</updated>
  </entry>
  <entry>
    <author>
      <name>flowwalker之码艺Blog</name>
    </author>
    <category term="程序设计笔记--c++OOP" scheme="https://flowwalker.github.io/coding-notes-blog/categories/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E7%AC%94%E8%AE%B0-c-OOP/"/>
    <category term="OOP" scheme="https://flowwalker.github.io/coding-notes-blog/tags/OOP/"/>
    <category term="c++" scheme="https://flowwalker.github.io/coding-notes-blog/tags/c/"/>
    <category term="程设" scheme="https://flowwalker.github.io/coding-notes-blog/tags/%E7%A8%8B%E8%AE%BE/"/>
    <content>
      <![CDATA[<h1 id="类和对象初步"><a href="#类和对象初步" class="headerlink" title="类和对象初步"></a>类和对象初步</h1><h2 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h2><ul><li><a href="#%E8%A1%A5%E5%85%85%E7%9F%A5%E8%AF%86">🚀补充知识</a><ul><li><a href="#%E5%BC%95%E7%94%A8">引用&amp;</a><ul><li><a href="#%E5%9F%BA%E6%9C%AC%E5%AE%9A%E4%B9%89">基本定义</a></li><li><a href="#%E5%BC%95%E7%94%A8%E4%BD%9C%E4%B8%BA%E5%87%BD%E6%95%B0%E8%BF%94%E5%9B%9E%E5%80%BC">引用作为函数返回值</a></li><li><a href="#%E5%B8%B8%E5%BC%95%E7%94%A8">常引用</a></li></ul></li><li><a href="#const-%E5%85%B3%E9%94%AE%E5%AD%97%E9%81%BF%E5%85%8D%E8%AF%AF%E6%94%B9">const 关键字（避免误改）</a><ul><li><a href="#%E5%9F%BA%E6%9C%AC%E5%86%85%E5%AE%B9">基本内容</a></li><li><a href="#%E5%B8%B8%E9%87%8F%E6%96%B9%E6%B3%95%E5%B8%B8%E9%87%8F%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0">常量方法（常量成员函数）</a></li><li><a href="#%E5%B8%B8%E9%87%8F%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%E7%9A%84%E9%87%8D%E8%BD%BD">常量成员函数的重载</a></li><li><a href="#mutable-%E5%85%B3%E9%94%AE%E5%AD%97">mutable 关键字</a></li><li><a href="#%E5%8A%A0%E5%BF%AB%E9%80%9F%E5%BA%A6%E4%B8%8E%E9%81%BF%E5%85%8D%E6%94%B9%E5%8F%98">加快速度与避免改变</a></li></ul></li><li><a href="#%E5%8A%A8%E6%80%81%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86">动态内存管理</a><ul><li><a href="#new-%E5%85%B3%E9%94%AE%E5%AD%97">new 关键字</a></li></ul></li><li><a href="#%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD">函数重载</a></li><li><a href="#%E5%87%BD%E6%95%B0%E7%9A%84%E7%BC%BA%E7%9C%81%E5%80%BC">函数的缺省值</a></li></ul></li><li>🚀<a href="#%E7%B1%BB%E7%9A%84%E5%AE%9A%E4%B9%89%E5%92%8C%E4%BD%BF%E7%94%A8">类的定义和使用</a><ul><li><a href="#%E5%AE%9A%E4%B9%89%E7%B1%BB">定义类</a></li><li><a href="#%E5%AE%9A%E4%B9%89%E5%AF%B9%E8%B1%A1">定义对象</a><ul><li><a href="#%E5%AF%B9%E8%B1%A1%E5%8D%A0%E7%94%A8%E7%9A%84%E7%A9%BA%E9%97%B4">对象占用的空间</a></li></ul></li></ul></li><li>🚀<a href="#%E8%AE%BF%E9%97%AE%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%88%90%E5%91%98">访问对象的成员</a></li><li>🚀<a href="#%E7%B1%BB%E6%88%90%E5%91%98%E7%9A%84%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90private-%E9%9A%90%E8%97%8F%E6%9C%BA%E5%88%B6">类成员的访问权限（private 隐藏机制）</a></li><li>🚀<a href="#%E5%86%85%E8%81%94%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0">内联成员函数</a></li></ul><h2 id="补充知识"><a href="#补充知识" class="headerlink" title="补充知识"></a>补充知识</h2><h3 id="引用"><a href="#引用" class="headerlink" title="引用&amp;"></a>引用&amp;</h3><h4 id="基本定义"><a href="#基本定义" class="headerlink" title="基本定义"></a>基本定义</h4><p><code> 类型名 &amp; 引用名=变量名</code>，引用名相当于变量名的一个别名</p><ul><li><p>定义时<strong>必须初始化成某个引用变量</strong></p></li><li><p>只能引用<strong>变量</strong>，<strong>不能引用常量、const变量和表达式</strong>和⚠️迭代器(右值不允许绑定)</p><blockquote><p>特殊的，对于const 引用（<code>const 类型名 &amp;</code>）</p><ul><li>定义时仍然必须初始化</li><li><strong>但是可以绑定到变量、常量、const变量或表达式</strong>（此时将延长表达式值的周期）也可以引用迭代器</li></ul></blockquote></li><li><p>初始化后便<strong>一直引用该变量</strong>，不会引用其他变量</p><pre><code class="hljs c++"><span class="hljs-type">int</span> a = <span class="hljs-number">10</span>;<span class="hljs-type">int</span> b = <span class="hljs-number">20</span>;<span class="hljs-type">int</span> &amp;ref = a; <span class="hljs-comment">// ref is now an alias for a</span>ref = b;      <span class="hljs-comment">// This does NOT make ref refer to b! 仅仅只是将b的值赋给了a</span></code></pre></li><li><p>引用某个引用的引用也成为<strong>该原变量的别名</strong></p></li></ul><blockquote><p><code>int* &amp; ref=p;</code>合法</p></blockquote><h4 id="引用作为函数返回值"><a href="#引用作为函数返回值" class="headerlink" title="引用作为函数返回值"></a>引用作为函数返回值</h4><p><strong>！！！注意⚠️：此时可以对返回值赋值</strong></p><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span><span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">using</span> <span class="hljs-keyword">namespace</span> std;<span class="hljs-type">int</span> n=<span class="hljs-number">4</span>;<span class="hljs-function"><span class="hljs-type">int</span> &amp; <span class="hljs-title">setvalue</span><span class="hljs-params">()</span></span>&#123; <span class="hljs-keyword">return</span> n;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span>&#123;<span class="hljs-built_in">setvalue</span>()=<span class="hljs-number">40</span>; <span class="hljs-comment">// 对返回值进行赋值→对n赋值</span>cout&lt;&lt;n&lt;&lt;endl;<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;<span class="hljs-comment">//程序输出40</span></code></pre><h4 id="常引用"><a href="#常引用" class="headerlink" title="常引用"></a>常引用</h4><ul><li><p><strong>不可通过常引用修改值</strong>（<u>修改本值可以</u>）</p></li><li><p>与引用<strong>属于不同类型</strong></p><p><code>初始化：常引用=引用 or 普通变量（正确，反之则错）</code></p><pre><code class="hljs c++"><span class="hljs-type">int</span> n=<span class="hljs-number">100</span>;<span class="hljs-type">const</span> <span class="hljs-type">int</span> &amp; r=n;r=<span class="hljs-number">200</span>; <span class="hljs-comment">// error!</span>n=<span class="hljs-number">200</span>; <span class="hljs-comment">// accepted</span></code></pre></li></ul><h3 id="const-关键字（避免误改）"><a href="#const-关键字（避免误改）" class="headerlink" title="const 关键字（避免误改）"></a>const 关键字（避免误改）</h3><h4 id="基本内容"><a href="#基本内容" class="headerlink" title="基本内容"></a>基本内容</h4><ul><li><p>常量</p></li><li><p>常量指针</p><ul><li><p><strong>不可</strong>通过<strong>常量指针更改值</strong></p></li><li><p><strong>可以改变常量指针指向</strong></p><pre><code class="hljs c++"><span class="hljs-type">int</span> r=<span class="hljs-number">4</span>,rr=<span class="hljs-number">8</span>;<span class="hljs-type">const</span> <span class="hljs-type">int</span> * p = &amp;r;*p=<span class="hljs-number">6</span>; <span class="hljs-comment">// error!</span>r=<span class="hljs-number">4</span>; <span class="hljs-comment">// ok</span>p=&amp;rr <span class="hljs-comment">// ok</span></code></pre></li><li><p>可把<strong>非常量指针</strong>赋给<strong>常量指针</strong>（<strong>反之不行</strong>，因为常量指针能保证不修改非常量指针指向的那个值，反之不行，<strong>除非强制类型转换</strong>）</p>  <pre><code class="hljs c++"><span class="hljs-type">const</span> <span class="hljs-type">int</span> *p1;<span class="hljs-type">int</span> *p2;p1=p2; <span class="hljs-comment">// ok</span>p2=p1; <span class="hljs-comment">// error! </span><span class="hljs-comment">// p2 现在允许修改原本被限制的内容，这可能导致通过 p1 指向的 const 对象被意外修改，违反 const 语义</span>p2=(<span class="hljs-type">int</span>*)p1 <span class="hljs-comment">// ok</span><span class="hljs-comment">// 去掉了 const 限定，原本const的对象可以被p2修改，但修改的合法性取决于原对象是否真的是常量：</span><span class="hljs-comment">// - 原对象本是非常量 → 安全</span><span class="hljs-comment">// - 原对象本是常量 → 未定义行为 （正常语法下，普通指针绝不允许绑定常量）</span></code></pre></li></ul></li><li><p>使用常量指针、常量引用、常量对象避免修改</p><pre><code class="hljs c++"><span class="hljs-comment">// 常量指针</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">PrintMy</span><span class="hljs-params">(<span class="hljs-type">const</span> <span class="hljs-type">char</span>*p)</span></span>&#123;<span class="hljs-built_in">strcpy</span>(p,<span class="hljs-string">&quot;this&quot;</span>); <span class="hljs-comment">// error!</span>cout&lt;&lt;p; <span class="hljs-comment">//ok</span>&#125;</code></pre><pre><code class="hljs c++"><span class="hljs-comment">// 常量引用</span><span class="hljs-type">int</span> n;<span class="hljs-type">const</span> <span class="hljs-type">int</span> &amp; r=n;r=<span class="hljs-number">5</span>; <span class="hljs-comment">// error!</span>n=<span class="hljs-number">3</span>; <span class="hljs-comment">// ok</span></code></pre><p><strong>常量对象</strong>只能使用<strong>构造函数、析构函数</strong>和<strong>带const关键字的函数</strong></p><pre><code class="hljs c++"><span class="hljs-comment">// 常量对象</span><span class="hljs-function"><span class="hljs-keyword">class</span> <span class="hljs-title">Sample</span><span class="hljs-params">()</span></span>&#123;<span class="hljs-keyword">private</span>:<span class="hljs-type">int</span> value;<span class="hljs-keyword">public</span>:<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">GetValue</span><span class="hljs-params">()</span></span>&#123;&#125;&#125;;<span class="hljs-type">const</span> Sample obj; <span class="hljs-comment">//常量对象</span>obj.<span class="hljs-built_in">GetValue</span>(); <span class="hljs-comment">// error!</span></code></pre></li></ul><h4 id="常量方法（常量成员函数）"><a href="#常量方法（常量成员函数）" class="headerlink" title="常量方法（常量成员函数）"></a>常量方法（常量成员函数）</h4><p>即在类的<strong>成员函数说明后面加 const 关键字</strong></p><ul><li>不能改<strong>非静态</strong>属性的值（<u>可以访问非静态，</u>常量本就不能改，<strong>静态变量可以修改</strong>）</li><li>不能调用同类的非常量成员函数（<strong>静态成员除外</strong>）</li><li><strong>定义和声明</strong>时<strong>都应</strong>使用 const 关键字</li></ul><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Sample</span> &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> value;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">GetValue</span><span class="hljs-params">()</span> <span class="hljs-type">const</span></span>;   <span class="hljs-comment">// 常量成员函数</span>    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">func</span><span class="hljs-params">()</span> </span>&#123; &#125;          <span class="hljs-comment">// 非静态、非const成员函数</span>&#125;;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Sample::GetValue</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>&#123;    <span class="hljs-comment">// value = 0;   // 错误：常量成员函数不能修改成员变量</span>    <span class="hljs-comment">// func();      // 错误：常量成员函数不能调用非const成员函数</span>&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-type">const</span> Sample o;        <span class="hljs-comment">// 定义常量对象，使用默认构造函数</span>    o.<span class="hljs-built_in">GetValue</span>();          <span class="hljs-comment">// 常量对象只能调用常量成员函数</span>    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;             &#125;</code></pre><blockquote><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Foo</span> &#123;<span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> data = <span class="hljs-number">42</span>;    <span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">get_val</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>&#123;          <span class="hljs-comment">// ✅ 按值返回，没问题</span>        <span class="hljs-keyword">return</span> data;    &#125;        <span class="hljs-function"><span class="hljs-type">const</span> <span class="hljs-type">int</span>&amp; <span class="hljs-title">get_ref</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>&#123;   <span class="hljs-comment">// ✅ const 引用，没问题</span>        <span class="hljs-keyword">return</span> data;    &#125;        <span class="hljs-comment">// int&amp; get_ref() const &#123;       // ❌ 编译错误！</span>    <span class="hljs-comment">//     return data;             // 在 const 函数中 data 被视为 const int</span>    <span class="hljs-comment">// &#125;                            // const int 不能绑定到 int&amp;</span>&#125;;</code></pre></blockquote><h4 id="常量成员函数的重载"><a href="#常量成员函数的重载" class="headerlink" title="常量成员函数的重载"></a>常量成员函数的重载</h4><p>两个函数名字、参数表均相同。但<strong>一者带有 const 关键字</strong>，<strong>另一者无</strong>，算<strong>重载</strong></p><p><strong>编译器将自动选择合适的</strong></p><h4 id="mutable-关键字"><a href="#mutable-关键字" class="headerlink" title="mutable 关键字"></a>mutable 关键字</h4><p>可以在 const 成员函数中修改 带mutable关键字的成员变量</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">CTest</span> &#123;<span class="hljs-keyword">private</span>:    <span class="hljs-keyword">mutable</span> <span class="hljs-type">int</span> m_n1; <span class="hljs-comment">// 使用mutable关键字</span>    <span class="hljs-type">bool</span> m_b2;<span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">bool</span> <span class="hljs-title">GetData</span><span class="hljs-params">()</span> <span class="hljs-type">const</span></span><span class="hljs-function">    </span>&#123;        m_n1++;        <span class="hljs-keyword">return</span> m_b2;    &#125;&#125;;</code></pre><h4 id="加快速度与避免改变"><a href="#加快速度与避免改变" class="headerlink" title="加快速度与避免改变"></a>加快速度与避免改变</h4><ul><li><p>为了防止生成形参导致的复制会引发复制构造函数的调用，开销较大</p><p>可以考虑将 <code>T</code>→<code>T&amp;</code>→<code>const T&amp;</code>（const 确保实参不改变）</p></li></ul><blockquote><p>以下是一段有关 const 函数调用说明</p><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span>&#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">double</span> real,imag;    <span class="hljs-keyword">mutable</span> <span class="hljs-type">int</span> access;    <span class="hljs-comment">// 用于打破 const</span><span class="hljs-keyword">public</span>:    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">setreal</span><span class="hljs-params">(<span class="hljs-type">double</span> r)</span></span>&#123;        real=r;    &#125;    <span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">getreal</span><span class="hljs-params">()</span> <span class="hljs-type">const</span></span>&#123;        access++; <span class="hljs-comment">// ok for &quot;mutable&quot;</span>        <span class="hljs-comment">//imag++; // error!</span>    &#125;&#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Func</span><span class="hljs-params">(<span class="hljs-type">const</span> Complex &amp;c)</span></span>&#123;    <span class="hljs-comment">//c.real=1.0; // error!</span>    <span class="hljs-comment">//c.setreal(20.0); //error!</span>    <span class="hljs-type">double</span> val=c.<span class="hljs-built_in">getreal</span>(); <span class="hljs-comment">// ok</span>    <span class="hljs-comment">// const 函数内部只能调用 const 的成员函数</span>&#125;</code></pre><p>比较奇葩的改变方式：该变全局c来促使const的东西也变了</p><pre><code class="hljs c++"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">&lt;iostream&gt;</span></span><span class="hljs-keyword">class</span> <span class="hljs-title class_">Complex</span> &#123;<span class="hljs-keyword">private</span>:    <span class="hljs-type">double</span> real;    <span class="hljs-type">double</span> imag;<span class="hljs-keyword">public</span>:    <span class="hljs-comment">// Constructor (构造函数)</span>    <span class="hljs-built_in">Complex</span>(<span class="hljs-type">double</span> r = <span class="hljs-number">0</span>, <span class="hljs-type">double</span> i = <span class="hljs-number">0</span>) : <span class="hljs-built_in">real</span>(r), <span class="hljs-built_in">imag</span>(i) &#123;&#125;    <span class="hljs-comment">// Non-const member function (非常成员函数)</span>    <span class="hljs-comment">// This can modify private members</span>    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">setReal</span><span class="hljs-params">(<span class="hljs-type">double</span> r)</span> </span>&#123;        real = r;    &#125;    <span class="hljs-comment">// Const member function (常成员函数)</span>    <span class="hljs-comment">// This allows read-only access for the print statement</span>    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">print</span><span class="hljs-params">()</span> <span class="hljs-type">const</span> </span>&#123;        std::cout &lt;&lt; <span class="hljs-string">&quot;(&quot;</span> &lt;&lt; real &lt;&lt; <span class="hljs-string">&quot;, &quot;</span> &lt;&lt; imag &lt;&lt; <span class="hljs-string">&quot;)&quot;</span> &lt;&lt; std::endl;    &#125;&#125;;<span class="hljs-comment">// Global Instance (全局变量)</span><span class="hljs-function">Complex <span class="hljs-title">global_obj</span><span class="hljs-params">(<span class="hljs-number">1.0</span>, <span class="hljs-number">1.0</span>)</span></span>;<span class="hljs-comment">// Function using a const reference</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Function</span><span class="hljs-params">(<span class="hljs-type">const</span> Complex &amp; c)</span> </span>&#123;    std::cout &lt;&lt; <span class="hljs-string">&quot;Value of c before global change: &quot;</span>;    c.<span class="hljs-built_in">print</span>();    <span class="hljs-comment">// Aliasing </span>    <span class="hljs-comment">// Even though &#x27;c&#x27; is const, the memory it points to is NOT immutable</span>    <span class="hljs-comment">// if there is another non-const pointer/reference to it.</span>    global_obj.<span class="hljs-built_in">setReal</span>(<span class="hljs-number">100.0</span>);     std::cout &lt;&lt; <span class="hljs-string">&quot;Value of c after global change: &quot;</span>;    c.<span class="hljs-built_in">print</span>(); &#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    <span class="hljs-comment">// Passing the global object to the function</span>    <span class="hljs-comment">// Inside Function(), &#x27;c&#x27; will be an alias for &#x27;global_obj&#x27;</span>    <span class="hljs-built_in">Function</span>(global_obj);    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre></blockquote><h3 id="动态内存管理"><a href="#动态内存管理" class="headerlink" title="动态内存管理"></a>动态内存管理</h3><p><strong>谁new谁到结尾delete，一一对应，不可缺少</strong>(有new才delete)</p><h4 id="new-关键字"><a href="#new-关键字" class="headerlink" title="new 关键字"></a>new 关键字</h4><ul><li><p>变量：<code>p= new T</code></p></li><li><p>数组：<code>p=new T[N]</code></p></li></ul><p>其中 T 是任意类型名，N可以是整型表达式</p><p><strong>注意⚠️：分配后调用时编译器不会检查是否越界，应自我约束</strong></p><p>*<em>注意⚠️：一定要用 delete 释放内存！且 delete <em>必须</em>指向new出来的</em>所有<em>空间</em>*</p><pre><code class="hljs c++"><span class="hljs-type">int</span> *p=<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>;<span class="hljs-type">int</span> *pp=<span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[<span class="hljs-number">20</span>];*p=<span class="hljs-number">5</span>;<span class="hljs-keyword">delete</span> p;p[<span class="hljs-number">0</span>]=<span class="hljs-number">1</span>;<span class="hljs-comment">// delete pp; // 不报错，但是只是释放了第一个元素！</span><span class="hljs-keyword">delete</span> []pp; <span class="hljs-comment">// 正确！</span></code></pre><blockquote><pre><code class="hljs c++"><span class="hljs-type">int</span> rows = <span class="hljs-number">3</span>, cols = <span class="hljs-number">4</span>;<span class="hljs-comment">// 分配</span><span class="hljs-type">int</span>** p = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>*[rows];        <span class="hljs-comment">// 外层：指针数组</span><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i &lt; rows; ++i) &#123;    p[i] = <span class="hljs-keyword">new</span> <span class="hljs-type">int</span>[cols];        <span class="hljs-comment">// 内层：每行一个 int 数组</span>&#125;<span class="hljs-comment">// 释放（顺序必须反过来）</span><span class="hljs-keyword">for</span> (<span class="hljs-type">int</span> i = <span class="hljs-number">0</span>; i &lt; rows; ++i) &#123;    <span class="hljs-keyword">delete</span>[] p[i];               <span class="hljs-comment">// 先释放每一行的 int[]</span>&#125;<span class="hljs-keyword">delete</span>[] p;                      <span class="hljs-comment">// 最后释放外层的 int*[]</span></code></pre><pre><code class="hljs c++"><span class="hljs-type">int</span>* inner = <span class="hljs-keyword">new</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">10</span>);<span class="hljs-type">int</span>** p = &amp;inner;<span class="hljs-comment">// 这没有动态分配二级内存，只需要：</span><span class="hljs-keyword">delete</span> inner;   <span class="hljs-comment">// 或 delete *p;</span><span class="hljs-comment">// p 本身是栈上的，不需要 delete</span></code></pre></blockquote><h3 id="函数重载"><a href="#函数重载" class="headerlink" title="函数重载"></a>函数重载</h3><p>函数重载，即多个函数<strong>名字相同</strong>，然而<strong>参数个数</strong>或<strong>参数类型不</strong>相同</p><p><strong>注意⚠️：如果出现歧义，则编译报错！</strong></p><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">max</span><span class="hljs-params">(<span class="hljs-type">int</span> a, <span class="hljs-type">int</span> b)</span> </span>&#123;<span class="hljs-keyword">return</span> (a &gt; b) ? a : b;&#125;<span class="hljs-function"><span class="hljs-type">double</span> <span class="hljs-title">max</span><span class="hljs-params">(<span class="hljs-type">double</span> a, <span class="hljs-type">double</span> b)</span> </span>&#123;<span class="hljs-keyword">return</span> (a &gt; b) ? a : b;&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">max</span><span class="hljs-params">(<span class="hljs-type">int</span> a, <span class="hljs-type">int</span> b, <span class="hljs-type">int</span> c)</span> </span>&#123;<span class="hljs-keyword">return</span> <span class="hljs-built_in">max</span>(<span class="hljs-built_in">max</span>(a, b), c);&#125;<span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">()</span> </span>&#123;    cout&lt;&lt;<span class="hljs-built_in">max</span>(<span class="hljs-number">3</span>, <span class="hljs-number">5</span>)&lt;&lt;endl;  <span class="hljs-comment">// 调用 A</span>    cout&lt;&lt;<span class="hljs-built_in">max</span>(<span class="hljs-number">3.7</span>, <span class="hljs-number">2.9</span>)&lt;&lt;endl; <span class="hljs-comment">// 调用 B</span>    cout&lt;&lt;<span class="hljs-built_in">max</span>(<span class="hljs-number">3</span>, <span class="hljs-number">5</span>, <span class="hljs-number">7</span>)&lt;&lt;endl;  <span class="hljs-comment">// 调用 C</span>    cout &lt;&lt; <span class="hljs-built_in">max</span>(<span class="hljs-number">3</span>, <span class="hljs-number">5.3</span>) &lt;&lt; endl;<span class="hljs-comment">// error! 二义性报错！</span>    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;&#125;</code></pre><h3 id="函数的缺省值"><a href="#函数的缺省值" class="headerlink" title="函数的缺省值"></a>函数的缺省值</h3><p>定义函数的时候可以让<strong>最右边</strong>的<strong>连续若干参数</strong>有缺省值，调用函数的时候，若不写参数则默认为缺省值</p><ul><li>提高可扩展性</li><li>方便添加新参数与修改</li></ul><p><strong>注意⚠️：只能最右边开始</strong></p><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260311180335159.png" alt="image-20260311180335159"></p><h2 id="类的定义和使用"><a href="#类的定义和使用" class="headerlink" title="类的定义和使用"></a>类的定义和使用</h2><h3 id="定义类"><a href="#定义类" class="headerlink" title="定义类"></a>定义类</h3><pre><code class="hljs c++"><span class="hljs-keyword">class</span> 类名&#123;访问范围说明符:<span class="hljs-comment">// 可选private,public,protected，可出现多次</span>    <span class="hljs-comment">// private：指定私有成员，只有该类的成员函数可以访问</span>    <span class="hljs-comment">// public： 任何地方皆可访问</span>    <span class="hljs-comment">// protected：参见“继承”章节</span>成员变量 <span class="hljs-number">1</span>成员变量 <span class="hljs-number">2</span>...成员函数声明 <span class="hljs-number">1</span>声明函数声明 <span class="hljs-number">2</span>    函数()&#123;&#125;    <span class="hljs-comment">// 函数类内声明+类外定义 或者 类内直接定义（此时默认为内联函数）</span>访问范围说明符:更多成员变量更多成员函数声明...    <span class="hljs-comment">// class在缺省情况下访问范围为 private ,struct 在默认情况下访问范围为 public</span>&#125;; <span class="hljs-comment">// ⚠️class 定义必须以英文分号 ; 结尾</span>返回值类型 类名::函数名()&#123;    语句组&#125;</code></pre><ul><li><p><strong>注意⚠️：<strong>类定义以</strong>分号</strong>结尾</p></li><li><p><strong>注意⚠️：<code>A::</code>说明后面的函数是类A的成员函数，而非普通函数</strong></p></li><li><p><strong>一个类</strong>的成员函数<strong>可以互相调用</strong></p></li><li><p><strong>类的成员函数</strong>也<strong>可以重载</strong>，<strong>可以设定参数默认值</strong>（<strong>任何有定义的表达式皆可</strong>，如:</p><pre><code class="hljs c++"><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">Max</span><span class="hljs-params">( <span class="hljs-type">int</span> m, <span class="hljs-type">int</span> n)</span></span>;<span class="hljs-type">int</span> a, b;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">Function2</span> <span class="hljs-params">( <span class="hljs-type">int</span> x,<span class="hljs-type">int</span> y= Max(a, b), <span class="hljs-type">int</span> z=a*b)</span> </span>&#123;...&#125;</code></pre><p>）</p></li><li><p>没写private,<strong>一定一定要写上!!!</strong></p></li></ul><h3 id="定义对象"><a href="#定义对象" class="headerlink" title="定义对象"></a>定义对象</h3><pre><code class="hljs c++"><span class="hljs-comment">// 定义对象</span>类名 对象名;</code></pre><h4 id="对象占用的空间"><a href="#对象占用的空间" class="headerlink" title="对象占用的空间"></a>对象占用的空间</h4><ul><li><p>一般来说，一个对象占用的内存空间大小 &#x3D; <strong>其成员变量的体积之和</strong>，可采用<code>sizeof(类名)</code>查看</p><blockquote></blockquote><table><thead><tr><th><strong>Data Type</strong></th><th><strong>Memory Size (Bytes)</strong></th><th><strong>Typical Range &#x2F; Note</strong></th></tr></thead><tbody><tr><td><code>char</code></td><td>1</td><td>Stores a single character (单个字符)</td></tr><tr><td><code>bool</code></td><td>1</td><td>Represents <code>true</code> or <code>false</code></td></tr><tr><td><code>int</code></td><td>4</td><td>Standard integer (标准整数)</td></tr><tr><td><code>long</code></td><td>4 or 8</td><td>Depends on the system (取决于系统架构)</td></tr><tr><td><code>long long</code></td><td>8</td><td>Large integer (大整数)</td></tr><tr><td><code>double</code></td><td>8</td><td>Double-precision floating point (双精度浮点数)</td></tr><tr><td><code>float</code></td><td>4</td><td>单精度浮点数</td></tr><tr><td>指针</td><td>4 or 8</td><td>固定不变(32位系统为4,64位系统为8),现在大部分为8</td></tr></tbody></table></li><li><p>每个对象各有自己的一份存储空间，互不影响</p></li><li><p>成员函数<strong>内存只有一份</strong>，但可以作用于不同函数</p></li></ul><h2 id="访问对象的成员"><a href="#访问对象的成员" class="headerlink" title="访问对象的成员"></a>访问对象的成员</h2><pre><code class="hljs c++"><span class="hljs-keyword">class</span> <span class="hljs-title class_">CRectangle</span>&#123;    <span class="hljs-keyword">public</span>:    <span class="hljs-type">int</span> w,h;    <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">init</span><span class="hljs-params">(<span class="hljs-type">int</span> ww,<span class="hljs-type">int</span> hh)</span></span><span class="hljs-function">        </span>&#123;            w=ww;            hh=h;        &#125;&#125;;CRectangle r1,r2;<span class="hljs-comment">// 方法一：对象名.成员名</span>r<span class="hljs-number">1.</span>w=<span class="hljs-number">5</span>;r<span class="hljs-number">1.</span><span class="hljs-built_in">init</span>(<span class="hljs-number">3</span>,<span class="hljs-number">4</span>);<span class="hljs-comment">// 方法二：指针-&gt;成员名</span>CRectangle *p1 = &amp;r1;CRectangle *p2 = &amp;r2;p1-&gt;w=<span class="hljs-number">6</span>;p2-&gt;<span class="hljs-built_in">init</span>(<span class="hljs-number">3</span>,<span class="hljs-number">4</span>)<span class="hljs-comment">// 方法三：引用名.成员名</span>CRectangle &amp;rr = r2;rr.w =<span class="hljs-number">5</span>;rr.<span class="hljs-built_in">init</span>(<span class="hljs-number">5</span>,<span class="hljs-number">4</span>); <span class="hljs-comment">// rr的值变了，r2的值也变了</span></code></pre><h2 id="类成员的访问权限（private-隐藏机制）"><a href="#类成员的访问权限（private-隐藏机制）" class="headerlink" title="类成员的访问权限（private 隐藏机制）"></a>类成员的访问权限（private 隐藏机制）</h2><ul><li><p>class 缺省情况下为 private ，struct 默认为 public</p></li><li><p><strong>注意⚠️：</strong></p><p>类成员函数内部能够访问 :</p><ol><li><strong>当前</strong>对象的<strong>全部</strong>属性（变量和函数）</li><li>⚠️<strong>同类其他对象</strong>的<strong>全部属性</strong></li></ol></li><li><p><strong>类</strong>成员函数<strong>以外</strong>的地方，只能够访问该类对象的<strong>公有成员</strong>，<strong>也不能cout私有成员</strong>（类似于被屏蔽的感觉）</p></li></ul><blockquote><p>设置私有成员的好处：</p><ol><li>若未来成员变量的类型等属性修改后，<strong>只需要更改成员函数即可</strong>，否则得把所有直接访问成员变量的语句修改</li><li>避免对对象的不正确操作</li></ol></blockquote><h2 id="内联成员函数"><a href="#内联成员函数" class="headerlink" title="内联成员函数"></a>内联成员函数</h2><p>在每个调用点直接插入函数，增大函数体的体积，但是减少函数调用开销，加快程序速度</p><pre><code class="hljs c++"><span class="hljs-comment">// 以下两种方法等价</span><span class="hljs-keyword">class</span> <span class="hljs-title class_">A</span>&#123;<span class="hljs-comment">//内写内联</span><span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">func1</span><span class="hljs-params">()</span></span>&#123;&#125;;<span class="hljs-comment">//声明内联</span><span class="hljs-function"><span class="hljs-keyword">inline</span> <span class="hljs-type">void</span> <span class="hljs-title">func2</span> <span class="hljs-params">()</span></span>;&#125;<span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">A::func2</span> <span class="hljs-params">()</span></span>&#123;&#125;;</code></pre><p><img src="https://gcore.jsdelivr.net/gh/flowwalker/PicGo-based-image-host@main/image-20260312232500958.png"></p><blockquote><p>inline 对于编译器只是建议而非命令 编译器可能忽略内联请求（对于过长的函数） 也可能自动内联未标记为 inline 的短小函数（即使在类外部定义）</p></blockquote>]]>
    </content>
    <id>https://flowwalker.github.io/coding-notes-blog/posts/53f3/</id>
    <link href="https://flowwalker.github.io/coding-notes-blog/posts/53f3/"/>
    <published>2026-03-10T16:00:00.000Z</published>
    <summary>类与对象基础：引用、const、动态内存</summary>
    <title>类和对象初步</title>
    <updated>2026-07-21T09:00:20.427Z</updated>
  </entry>
</feed>
