<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Cpp面试 on Mao's Blog</title><link>https://Mist2233.github.io/series/cpp%E9%9D%A2%E8%AF%95/</link><description>Recent content in Cpp面试 on Mao's Blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 12 Mar 2026 22:01:25 +0800</lastBuildDate><atom:link href="https://Mist2233.github.io/series/cpp%E9%9D%A2%E8%AF%95/index.xml" rel="self" type="application/rss+xml"/><item><title>Cpp八股面试题</title><link>https://Mist2233.github.io/posts/cpp%E5%85%AB%E8%82%A1%E9%9D%A2%E8%AF%95%E9%A2%98/</link><pubDate>Thu, 12 Mar 2026 22:01:25 +0800</pubDate><guid>https://Mist2233.github.io/posts/cpp%E5%85%AB%E8%82%A1%E9%9D%A2%E8%AF%95%E9%A2%98/</guid><description>&lt;h2 id="智能指针相关"&gt;智能指针相关&lt;/h2&gt;
&lt;p&gt;Cpp 智能指针是什么？请简单介绍一下。&lt;/p&gt;
&lt;!-- - 我回答的是智能指针就是将裸指针包装成一个符合 RAII 原则的类，使得其在析构时资源能够自动释放。 --&gt;
&lt;!-- - 我还提到了三种智能指针：unique_ptr, shared_ptr 和 weak_ptr，并指出 unique_ptr 表示只有一个指针指向对应的资源，shared_ptr 表示有多个指针指向同一份资源，但是我表示我忘记了 weak_ptr 是什么…… --&gt;
&lt;div class="callout callout-note"&gt;
&lt;p class="callout-header"&gt;参考回答&lt;/p&gt;
&lt;div class="callout-body"&gt;&lt;p&gt;智能指针是一个封装了原始指针的类模板，它的主要作用就是通过 RAII 原则，在指针对象析构时自动释放资源，从而避免“忘记手动 &lt;code&gt;delete&lt;/code&gt;”导致的资源泄漏，或者调用野指针的问题。&lt;/p&gt;
&lt;p&gt;所谓的 RAII，指的就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;构造时：接过原始指针，这代表着接管了原始指针的资源。&lt;/li&gt;
&lt;li&gt;析构时：在析构函数里自动释放资源。&lt;/li&gt;
&lt;li&gt;它将原本需要人工管理的“内存申请与释放”，变成了编译器自动管理的“局部变量生命周期”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C++11 及以后，主要提供了三种智能指针，代表三种管理资源的逻辑：
&lt;strong&gt;(1) &lt;code&gt;std::unique_ptr&lt;/code&gt; —— “独占权”&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;所有权&lt;/strong&gt;：同一时间只能有一个 &lt;code&gt;unique_ptr&lt;/code&gt; 指向该资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能&lt;/strong&gt;：&lt;strong&gt;零开销（Zero Overhead）&lt;/strong&gt;。它的执行效率和原始指针几乎一模一样。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限制&lt;/strong&gt;：不能拷贝，只能移动（&lt;code&gt;std::move&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：最常用的指针。适用于明确知道“谁是主人”的场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;(2) &lt;code&gt;std::shared_ptr&lt;/code&gt; —— “共享权”&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;所有权&lt;/strong&gt;：多个指针可以指向同一个资源。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;机制&lt;/strong&gt;：正如我们刚才聊的，它通过&lt;strong&gt;控制块&lt;/strong&gt;里的&lt;strong&gt;引用计数&lt;/strong&gt;来工作。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;性能&lt;/strong&gt;：有一定开销（需要原子操作增减计数，需要额外堆内存存控制块）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：资源需要被多个模块共享，且无法确定谁最后退出的场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;(3) &lt;code&gt;std::weak_ptr&lt;/code&gt; —— “观察者”&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;所有权&lt;/strong&gt;：&lt;strong&gt;不拥有所有权&lt;/strong&gt;。它只是一个旁观者。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;机制&lt;/strong&gt;：指向 &lt;code&gt;shared_ptr&lt;/code&gt; 管理的对象，但不增加强引用计数。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;场景&lt;/strong&gt;：解决 &lt;code&gt;shared_ptr&lt;/code&gt; 的&lt;strong&gt;循环引用&lt;/strong&gt;问题，或者作为缓存监控（防悬空）。&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;你提到了 &lt;code&gt;shared_ptr&lt;/code&gt;，请问它是线程安全的吗？&lt;/p&gt;
&lt;!-- - 我回答的是 `shared_ptr` 的计数是线程安全的，因为它是原子操作；而其本身不是线程安全的，也就是说，多个线程持有的 `shared_ptr` 对数据的读写可能产生一些冲突，或者说数据竞争。 --&gt;
&lt;!-- - 面试官随后问我 `shared_ptr` 的计数是怎么保证线程安全的，我说就是使用 Cpp 中定义的一些接口，用定义好的原子操作实现的。不过这里我可能解释得不是特别清楚。 --&gt;
&lt;div class="callout callout-note"&gt;
&lt;p class="callout-header"&gt;参考回答&lt;/p&gt;</description></item><item><title>SFINAE原则</title><link>https://Mist2233.github.io/posts/sfinae%E5%8E%9F%E5%88%99/</link><pubDate>Tue, 02 Dec 2025 09:12:51 +0800</pubDate><guid>https://Mist2233.github.io/posts/sfinae%E5%8E%9F%E5%88%99/</guid><description>&lt;h2 id="sfinae-substitution-failure-is-not-an-error"&gt;SFINAE (Substitution Failure Is Not An Error)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 我们之前聊过模板。在 C++ 模板编程中，有一个非常著名的缩写词叫 &lt;strong&gt;SFINAE&lt;/strong&gt; (读作 &amp;ldquo;sfi-nay&amp;rdquo;)。&lt;/p&gt;
&lt;p&gt;请问，你知道 SFINAE 代表什么意思吗？或者你能简单描述一下，当编译器在实例化模板时，如果遇到了一个&lt;strong&gt;无效的类型替换&lt;/strong&gt;，它会怎么做？是直接报错停止编译，还是会尝试别的方案？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不好意思，我第一次听说“模板元编程”这个概念，也是第一次听说 SFINAE 这个名词，请你直接解释吧。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;没关系！这正是我们今天学习的意义所在。模板元编程是 C++ 的深水区，SFINAE 是进入这个世界的敲门砖。&lt;/p&gt;
&lt;p&gt;我们把这个复杂的概念拆解成最简单的逻辑。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="什么是-sfinae"&gt;什么是 SFINAE？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;SFINAE&lt;/strong&gt; 代表 &lt;strong&gt;&amp;ldquo;Substitution Failure Is Not An Error&amp;rdquo;&lt;/strong&gt;。
中文直译：&lt;strong&gt;“替换失败不是错误”&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这听起来像是一句哲学名言，但在 C++ 编译器眼中，它是一条非常具体的&lt;strong&gt;生存法则&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="场景重现编译器的选秀大会"&gt;场景重现：编译器的选秀大会&lt;/h3&gt;
&lt;p&gt;假设你写了两个同名的函数模板 &lt;code&gt;foo&lt;/code&gt;（这叫重载）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 选手 A：这个模板要求 T 必须有一个叫 inner_type 的内部类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;inner_type&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Selected A&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 选手 B：这个模板对 T 没有任何要求
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;template&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Selected B&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;现在，你在 &lt;code&gt;main&lt;/code&gt; 函数里调用了 &lt;code&gt;foo(10)&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>命名空间</title><link>https://Mist2233.github.io/posts/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4/</link><pubDate>Wed, 26 Nov 2025 08:38:45 +0800</pubDate><guid>https://Mist2233.github.io/posts/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4/</guid><description>&lt;h2 id="命名空间-namespace"&gt;命名空间 namespace&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 中，我们经常看到 &lt;code&gt;std::cout&lt;/code&gt;、&lt;code&gt;std::vector&lt;/code&gt; 这样的写法，这里的 &lt;code&gt;std&lt;/code&gt; 就是一个&lt;strong&gt;命名空间&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;请问，&lt;strong&gt;命名空间 (namespace)&lt;/strong&gt; 的主要作用是什么？它解决了 C++（以及很多其他编程语言）中一个什么样的痛点？&lt;/p&gt;
&lt;p&gt;此外，我们在 &lt;code&gt;.cpp&lt;/code&gt; 文件中经常会看到 &lt;code&gt;using namespace std;&lt;/code&gt; 这样的写法。请问，在&lt;strong&gt;头文件 (&lt;code&gt;.h&lt;/code&gt;)&lt;/strong&gt; 中使用 &lt;code&gt;using namespace std;&lt;/code&gt; 是一个好的习惯吗？为什么？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我认为，命名空间类似一个集合，里面包含着特定的“工具”，也就是函数。我们把一些常用的、标准的工具打包起来，就变成了一个命名空间。&lt;/li&gt;
&lt;li&gt;同时，命名空间也是一个前缀。它解决的痛点是：如何区分不同位置的同名函数？通过命名空间就可以。比如说，&lt;code&gt;A&lt;/code&gt; 和 &lt;code&gt;B&lt;/code&gt; 两个命名空间都有一个函数叫做 &lt;code&gt;test&lt;/code&gt;，那么我们可以通过 &lt;code&gt;A::test&lt;/code&gt; 和 &lt;code&gt;B::test&lt;/code&gt; 来分别调用这两个不同的函数，而不会导致混淆。&lt;/li&gt;
&lt;li&gt;你提到的最后一点：在头文件中使用 &lt;code&gt;using namespace std;&lt;/code&gt;。这绝对不是一个好习惯！简单来说，它会导致命名空间污染的问题。即：我在头文件里使用 &lt;code&gt;using namespace std;&lt;/code&gt;，在所有导入该头文件的文件中，命名空间都会被默认设置为 &lt;code&gt;std&lt;/code&gt;。一旦我们自己定义的函数和 &lt;code&gt;std&lt;/code&gt; 中的某个函数重名，在调用时会导致混乱，通常会调用 &lt;code&gt;std&lt;/code&gt; 中的那个函数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我只是凭自己理解作答，如果不正确，请你指出。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;你的回答&lt;strong&gt;极其出色&lt;/strong&gt;！虽然你说是一个月没学，但你的 C++ 感觉依然非常敏锐。&lt;/p&gt;
&lt;p&gt;我们来逐点分析你的回答：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;命名空间的定义&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;“命名空间类似一个集合&amp;hellip; 也是一个前缀。”&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;这个比喻非常形象！命名空间本质上就是一个&lt;strong&gt;逻辑上的作用域&lt;/strong&gt;。它把一组相关的标识符（函数、类、变量等）包裹起来，像是一个&lt;strong&gt;虚拟的文件夹&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;解决的痛点&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;“解决的痛点是：如何区分不同位置的同名函数？”&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;完全正确！这就是&lt;strong&gt;命名冲突 (Name Collision)&lt;/strong&gt; 问题。在大型项目中，成千上万的代码、引入几十个第三方库，如果没有命名空间，大家为了给函数起个不重名的名字（比如 &lt;code&gt;LibA_test&lt;/code&gt;, &lt;code&gt;MyProj_test&lt;/code&gt;），头都要炸了。命名空间优雅地解决了这个问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;头文件中的 &lt;code&gt;using namespace std;&lt;/code&gt;&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>C++类型转换符</title><link>https://Mist2233.github.io/posts/c++%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%E7%AC%A6/</link><pubDate>Tue, 21 Oct 2025 08:28:49 +0800</pubDate><guid>https://Mist2233.github.io/posts/c++%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2%E7%AC%A6/</guid><description>&lt;p&gt;&lt;strong&gt;我们开始今天的 C++ 八股环节！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;今天，我们来聊一个在面试中经常被用来考察你对 C++ 基础和面向对象理解的话题：&lt;strong&gt;&lt;code&gt;static_cast&lt;/code&gt;, &lt;code&gt;dynamic_cast&lt;/code&gt;, &lt;code&gt;const_cast&lt;/code&gt;, &lt;code&gt;reinterpret_cast&lt;/code&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这四个是 C++ 的标准类型转换操作符。相比于 C 风格的强制转换（如 &lt;code&gt;(int)x&lt;/code&gt;），它们更安全、意图也更明确。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="static_cast-转换符"&gt;&lt;code&gt;static_cast&lt;/code&gt; 转换符&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;模拟面试开始&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 中，我们有四种“具名”的类型转换符，统称为 &lt;code&gt;static_cast&lt;/code&gt; 系列。我们先来聊聊最常用的一个：&lt;strong&gt;&lt;code&gt;static_cast&lt;/code&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;请问，&lt;code&gt;static_cast&lt;/code&gt; 主要用于什么样的转换场景？它和 C 风格的强制转换 &lt;code&gt;(new_type)expression&lt;/code&gt; 相比，有什么主要的&lt;strong&gt;优势&lt;/strong&gt;？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;static_cast&lt;/code&gt; 是 C++ 中最基础和最简单的类型转换，主要有以下的应用场景：
&lt;ul&gt;
&lt;li&gt;相关类型之间的转换，如数值类型之间、枚举类型和整数之间、&lt;code&gt;void*&lt;/code&gt; 类型和其他指针类型之间。&lt;/li&gt;
&lt;li&gt;有继承关系的类指针/引用转换（不涉及多态的情况）。这里，将派生类指针或引用，转为基类的指针或引用（也就是上行转换）是安全的；反之，将基类的指针或者引用，转为派生类的指针或者引用（也就是下行转换）是不安全的。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;和 &lt;code&gt;(new_type)expression&lt;/code&gt; 相比，&lt;code&gt;static_cast&lt;/code&gt; 的转换意图更明确（从命名就可以看出），以及转换过程更安全（会检查变量类型之间是否可以安全转换）&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (总结与补充):&lt;/strong&gt; 你说的完全正确。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;static_cast&lt;/code&gt; 是 C++ 中最基础、最常用的“良性”转换。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;主要应用场景：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;相关类型之间的转换&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数值类型转换&lt;/strong&gt;：在各种数值类型之间进行转换，比如 &lt;code&gt;int&lt;/code&gt; -&amp;gt; &lt;code&gt;double&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt; -&amp;gt; &lt;code&gt;int&lt;/code&gt;。
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// i = 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;枚举与整数转换&lt;/strong&gt;：在枚举类型和整数类型之间进行转换。
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Color&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;RED&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;c_val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RED&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;em&gt;void&lt;/em&gt; 指针转换&lt;/em&gt;*：将 &lt;code&gt;void*&lt;/code&gt; 指针转换为具体的类型指针。
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;有继承关系的类指针/引用转换 (不涉及多态)&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>default和delete</title><link>https://Mist2233.github.io/posts/default%E5%92%8Cdelete/</link><pubDate>Thu, 16 Oct 2025 09:05:16 +0800</pubDate><guid>https://Mist2233.github.io/posts/default%E5%92%8Cdelete/</guid><description>&lt;h2 id="default-关键字强制生成默认构造函数"&gt;&lt;code&gt;default&lt;/code&gt; 关键字强制生成默认构造函数&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;模拟面试开始&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 我们知道，如果一个类我们不给它定义任何构造函数，编译器会自动为我们生成一个&lt;strong&gt;默认构造函数&lt;/strong&gt;。类似的，编译器也可能会为我们生成拷贝构造函数、拷贝赋值运算符等。&lt;/p&gt;
&lt;p&gt;在 C++11 之后，如果我们想&lt;strong&gt;显式地&lt;/strong&gt;告诉编译器：“请为我生成一个默认的、最普通的版本”，我们可以使用 &lt;code&gt;default&lt;/code&gt; 关键字。&lt;/p&gt;
&lt;p&gt;请看下面这个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 显式地要求编译器生成默认构造函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;// 用户自定义了别的构造函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;我的问题是：&lt;/strong&gt;
在这个例子中，&lt;code&gt;MyClass() = default;&lt;/code&gt; 这一行代码，有什么&lt;strong&gt;实际意义&lt;/strong&gt;？&lt;/p&gt;
&lt;p&gt;换句话说，如果我们&lt;strong&gt;删掉&lt;/strong&gt; &lt;code&gt;MyClass() = default;&lt;/code&gt; 这一行，会发生什么变化？这个类还能通过 &lt;code&gt;MyClass obj;&lt;/code&gt; 这种方式创建对象吗？为什么？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当用户自己定义了一种构造函数时，编译器就&lt;strong&gt;不会自动生成&lt;/strong&gt;默认的无参数的构造函数。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MyClass() = default;&lt;/code&gt; 确保无参数的构造函数存在。&lt;/li&gt;
&lt;li&gt;如果删去这一行，那么 &lt;code&gt;MyClass&lt;/code&gt; 这个类就无法通过 &lt;code&gt;MyClass obj;&lt;/code&gt; 这种方式创建对象，因为编译器检测不到对应的构造函数。&lt;/li&gt;
&lt;li&gt;而增加上这一行，可以使得程序可以在无参数的情况下创建新的对象，等到对其内容有要求时，再做修改。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (总结与肯定):&lt;/strong&gt; 你说的没错。这个问题的核心在于 C++ 的一条规则：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;一旦用户为类定义了任何一种构造函数（无论带不带参数），编译器就会“罢工”，不再自动生成默认（无参）构造函数。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;&lt;strong&gt;所以，在你给出的例子中：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;因为你已经定义了一个 &lt;code&gt;MyClass(int val)&lt;/code&gt;，编译器就不会再自动生成 &lt;code&gt;MyClass()&lt;/code&gt; 了。&lt;/li&gt;
&lt;li&gt;如果我们&lt;strong&gt;删掉&lt;/strong&gt; &lt;code&gt;MyClass() = default;&lt;/code&gt; 这一行，那么 &lt;code&gt;MyClass&lt;/code&gt; 类就&lt;strong&gt;没有&lt;/strong&gt;无参构造函数。此时，&lt;code&gt;MyClass obj;&lt;/code&gt; 这样的代码就会&lt;strong&gt;编译失败&lt;/strong&gt;，因为它找不到匹配的构造函数。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;= default&lt;/code&gt; 的作用：&lt;/strong&gt;
&lt;code&gt;MyClass() = default;&lt;/code&gt; 这一行，就是你（程序员）在向编译器明确地&lt;strong&gt;下指令&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>虚析构函数</title><link>https://Mist2233.github.io/posts/%E8%99%9A%E6%9E%90%E6%9E%84%E5%87%BD%E6%95%B0/</link><pubDate>Mon, 13 Oct 2025 23:10:06 +0800</pubDate><guid>https://Mist2233.github.io/posts/%E8%99%9A%E6%9E%90%E6%9E%84%E5%87%BD%E6%95%B0/</guid><description>&lt;h2 id="不使用虚析构函数可能导致资源泄漏"&gt;不使用虚析构函数，可能导致资源泄漏&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 我们知道，析构函数是在对象生命周期结束时，用于清理资源的特殊成员函数。在 C++ 的继承体系中，我们有时需要把基类的析构函数声明为&lt;strong&gt;虚函数 (virtual)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;请看下面这段代码，它可能会导致一个非常严重的问题：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Base Created&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 注意：析构函数不是虚函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Base Destroyed&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Derived&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Derived Created&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Derived Destroyed&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Derived&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 基类指针指向派生类对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 问题就出在这里！
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;我的问题是：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;你预测一下，上面这段代码的&lt;strong&gt;输出&lt;/strong&gt;会是什么？&lt;/li&gt;
&lt;li&gt;这个输出结果揭示了什么样的&lt;strong&gt;严重问题&lt;/strong&gt;？&lt;/li&gt;
&lt;li&gt;这个问题的&lt;strong&gt;根本原因&lt;/strong&gt;是什么？（即，&lt;code&gt;delete p;&lt;/code&gt; 这行代码，编译器是如何决定调用哪个析构函数的？）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;回答：&lt;/p&gt;</description></item><item><title>Const关键字</title><link>https://Mist2233.github.io/posts/const%E5%85%B3%E9%94%AE%E5%AD%97/</link><pubDate>Thu, 09 Oct 2025 13:09:59 +0800</pubDate><guid>https://Mist2233.github.io/posts/const%E5%85%B3%E9%94%AE%E5%AD%97/</guid><description>&lt;h2 id="const-修饰变量"&gt;&lt;code&gt;const&lt;/code&gt; 修饰变量&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 看到你的简历上写着熟悉 C++，那我们来聊聊 &lt;code&gt;const&lt;/code&gt; 关键字吧。它在 C++ 中有很多用途。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我的第一个问题是：&lt;/strong&gt; 当 &lt;code&gt;const&lt;/code&gt; 用于修饰一个&lt;strong&gt;变量&lt;/strong&gt;时，它意味着什么？它和 C 语言中的 &lt;code&gt;#define&lt;/code&gt; 宏定义常量相比，有什么主要的优势？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 方式一
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;MAX_SIZE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 方式二
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define MAX_SIZE 100&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;const&lt;/code&gt; 关键字修饰变量，表示这个变量是一个常量，不能被修改。&lt;/li&gt;
&lt;li&gt;和 &lt;code&gt;#define&lt;/code&gt; 宏定义常量相比，&lt;code&gt;const&lt;/code&gt; 变量更加有下面的优势：
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;类型检查&lt;/strong&gt;：&lt;code&gt;const&lt;/code&gt; 是有类型的变量，编译器会进行类型检查，而 &lt;code&gt;#define&lt;/code&gt; 是纯文本变量，没有类型概念，容易引发隐性错误——编译通过但运行出错。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;作用域控制&lt;/strong&gt;：&lt;code&gt;const&lt;/code&gt; 类型的变量可以定义在局部作用域中，而 &lt;code&gt;#define&lt;/code&gt; 是全局替换，容易产生命名冲突&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调试支持&lt;/strong&gt;：&lt;code&gt;const&lt;/code&gt; 变量可以在调试器中查看它的值和地址，而 &lt;code&gt;#define&lt;/code&gt; 变量在预处理阶段就被替换到，调试器无法识别。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;取地址操作&lt;/strong&gt;：&lt;code&gt;const&lt;/code&gt; 变量可以取地址，而 &lt;code&gt;#define&lt;/code&gt; 是文本替换，没有地址的概念。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨文件访问&lt;/strong&gt;：&lt;code&gt;const&lt;/code&gt; 变量可以通过 &lt;code&gt;extern&lt;/code&gt; 声明在多个文件中共享，而 &lt;code&gt;#define&lt;/code&gt; 无法跨文件共享，只能重新定义。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;当然，&lt;code&gt;const&lt;/code&gt; 最主要的优势还是&lt;strong&gt;类型检查&lt;/strong&gt;和&lt;strong&gt;作用域控制&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="const-与指针结合"&gt;&lt;code&gt;const&lt;/code&gt; 与指针结合&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官 (继续提问):&lt;/strong&gt; 好的，你对 &lt;code&gt;const&lt;/code&gt; 修饰普通变量的理解非常透彻。我们来看它和&lt;strong&gt;指针&lt;/strong&gt;的结合。&lt;/p&gt;
&lt;p&gt;请你解释一下，下面这三种声明中，&lt;code&gt;p&lt;/code&gt; 的类型有什么不同？分别都约束了什么东西不能被修改？&lt;/p&gt;</description></item><item><title>new运算符的细节</title><link>https://Mist2233.github.io/posts/new%E8%BF%90%E7%AE%97%E7%AC%A6%E7%9A%84%E7%BB%86%E8%8A%82/</link><pubDate>Tue, 07 Oct 2025 09:22:04 +0800</pubDate><guid>https://Mist2233.github.io/posts/new%E8%BF%90%E7%AE%97%E7%AC%A6%E7%9A%84%E7%BB%86%E8%8A%82/</guid><description>&lt;h2 id="new-的两步过程定位-new-操作"&gt;&lt;code&gt;new&lt;/code&gt; 的两步过程、定位 &lt;code&gt;new&lt;/code&gt; 操作&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 我们知道，&lt;code&gt;new&lt;/code&gt; 操作符用于在堆上分配内存并构造对象。比如 &lt;code&gt;MyClass* p = new MyClass();&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;其实，这个简单的 &lt;code&gt;new&lt;/code&gt; 表达式，背后可以被看作是两个步骤的组合。你能描述一下这两个步骤分别是什么吗？&lt;/p&gt;
&lt;p&gt;另外，C++ 还提供了一种叫做 &lt;strong&gt;“定位 &lt;code&gt;new&lt;/code&gt; (placement new)”&lt;/strong&gt; 的特殊语法。它的形式是 &lt;code&gt;new (address) Type(args)&lt;/code&gt;。你了解它是用来做什么的吗？它和普通的 &lt;code&gt;new&lt;/code&gt; 有什么核心区别？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;new&lt;/code&gt; 表达式可以看作这样两个步骤的组合：
&lt;ul&gt;
&lt;li&gt;第一步：分配内存。&lt;/li&gt;
&lt;li&gt;第二步：在分配到的内存上构造对象，即初始化。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;定位 &lt;code&gt;new&lt;/code&gt; 操作，顾名思义，就是在一个确定的地址上构造对象，而不是自己分配内存。通过定位 &lt;code&gt;new&lt;/code&gt; 构造的对象，不能调用 &lt;code&gt;delete&lt;/code&gt; 销毁，需要手动析构。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (总结与肯定):&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. &lt;code&gt;new&lt;/code&gt; 表达式的两步走&lt;/strong&gt;
你说的完全正确。&lt;code&gt;T* p = new T(args);&lt;/code&gt; 这个表达式，在概念上等价于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;分配内存 (Allocation)&lt;/strong&gt;：调用一个名为 &lt;code&gt;operator new&lt;/code&gt; 的函数，来分配一块足够大的、未初始化的裸内存。这个函数很像 &lt;code&gt;malloc&lt;/code&gt;。
&lt;code&gt;void* memory = operator new(sizeof(T));&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;构造对象 (Construction)&lt;/strong&gt;：在这块分配好的内存上，调用 &lt;code&gt;T&lt;/code&gt; 类的构造函数来初始化对象。
&lt;code&gt;T* obj = static_cast&amp;lt;T*&amp;gt;(memory);&lt;/code&gt;
&lt;code&gt;obj-&amp;gt;T::T(args);&lt;/code&gt; // 伪代码，表示调用构造函数&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;2. 定位 &lt;code&gt;new&lt;/code&gt; (placement new)&lt;/strong&gt;
你的解释也堪称完美：&lt;/p&gt;</description></item><item><title>栈、堆与栈溢出</title><link>https://Mist2233.github.io/posts/%E6%A0%88%E5%A0%86%E4%B8%8E%E6%A0%88%E6%BA%A2%E5%87%BA/</link><pubDate>Fri, 03 Oct 2025 14:32:45 +0800</pubDate><guid>https://Mist2233.github.io/posts/%E6%A0%88%E5%A0%86%E4%B8%8E%E6%A0%88%E6%BA%A2%E5%87%BA/</guid><description>&lt;h2 id="栈和堆的比较-stack-and-heap"&gt;栈和堆的比较 Stack and Heap&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 我们知道，C++ 程序在运行时，局部变量通常分配在&lt;strong&gt;栈 (Stack)&lt;/strong&gt; 上，而动态分配的内存则来自&lt;strong&gt;堆 (Heap)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;请你从&lt;strong&gt;内存管理方式&lt;/strong&gt;、&lt;strong&gt;分配效率&lt;/strong&gt;、&lt;strong&gt;空间大小&lt;/strong&gt;和&lt;strong&gt;数据生命周期&lt;/strong&gt;这四个角度，详细对比一下栈和堆的主要区别。&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在内存管理方式上，栈的内存是自动分配、释放的连续空间，而堆的内存是需要程序员手动分配、释放的非连续空间。&lt;/li&gt;
&lt;li&gt;在分配效率上，栈的分配效率比堆更高。&lt;/li&gt;
&lt;li&gt;在空间大小上，栈的空间大小比堆更小，当栈达到一定深度，就会发生溢出。&lt;/li&gt;
&lt;li&gt;在数据生命周期上，栈的生命周期更短，通常是一次函数调用开始时，栈空间被分配，而该次函数调用结束时，栈的内存就被释放。而堆上的内存，通常在整个程序的生命中始终存在，直到我们手动释放它。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="栈溢出-stack-overflow"&gt;栈溢出 Stack Overflow&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官 (深入追问):&lt;/strong&gt; 好的，你对基础区别已经很清楚了。我们来深入聊聊你提到的 &lt;strong&gt;“栈溢出 (Stack Overflow)”&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;你刚才说“当栈达到一定深度，就会发生溢出”。这通常是由&lt;strong&gt;无限递归&lt;/strong&gt;或&lt;strong&gt;过深的递归&lt;/strong&gt;导致的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;我的问题是：&lt;/strong&gt; 除了递归，还有没有&lt;strong&gt;其他&lt;/strong&gt;常见的编程行为，也可能导致栈溢出？你能否写一个&lt;strong&gt;不使用递归&lt;/strong&gt;的、非常简单的代码片段，来人为地触发一个栈溢出？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以，除了递归之外，两个函数无限制地相互调用也可以出发栈溢出，比如下面的例子。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;funcA&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;funcA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;funcB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;funcA&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;funcA&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (继续引导):&lt;/strong&gt; 很好。不过，我们还能不能让问题变得更“纯粹”一点？&lt;/p&gt;</description></item><item><title>模板：template和typename</title><link>https://Mist2233.github.io/posts/%E6%A8%A1%E6%9D%BFtemplate%E5%92%8Ctypename/</link><pubDate>Mon, 29 Sep 2025 09:33:17 +0800</pubDate><guid>https://Mist2233.github.io/posts/%E6%A8%A1%E6%9D%BFtemplate%E5%92%8Ctypename/</guid><description>&lt;h2 id="模板的作用与分类"&gt;模板的作用与分类&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 中，&lt;strong&gt;模板 (template)&lt;/strong&gt; 是实现泛型编程的核心机制。&lt;/p&gt;
&lt;p&gt;你能用自己的话，简单解释一下什么是模板吗？它主要解决了什么问题？C++ 中主要有哪几种类型的模板？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模板是 Cpp 的一种机制，它允许我们编写&lt;strong&gt;与类型无关&lt;/strong&gt;的代码（&lt;strong&gt;泛型&lt;/strong&gt;），即：使用同一段代码能覆盖许多的类型。这种机制让编译器能根据识别到的具体类型，执行不同的操作。&lt;/li&gt;
&lt;li&gt;模板主要解决的是&lt;strong&gt;代码复用&lt;/strong&gt;的问题，尤其是在函数或者类的逻辑一致、但处理数据类型不同的情况下，避免重复写同样的代码，极大地提高了代码的简洁性和可读性。&lt;/li&gt;
&lt;li&gt;C++中主要的模板，我认为有
&lt;ul&gt;
&lt;li&gt;函数模板：处理任意类型参数的模板&lt;/li&gt;
&lt;li&gt;类模板：处理任意类型成员的模板。&lt;/li&gt;
&lt;li&gt;模板特化：某一个具体类型需要特殊实现，提供一个特化类型的模板。&lt;/li&gt;
&lt;li&gt;模板偏特化：允许对模板参数的一部分特化，不过较为复杂，使用较少。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="模板实例化-template-instantiation"&gt;模板实例化 Template Instantiation&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官 (追问):&lt;/strong&gt; 好的，你提到了函数模板和类模板。我们知道，模板本身并不是可以直接执行的代码，它更像是一个“蓝图”。&lt;/p&gt;
&lt;p&gt;请问，从“模板蓝图”到“可执行代码”这个过程，是在什么时候发生的？这个过程通常被称为什么？&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;span class="lnt"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 发生了什么？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3.14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.71&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 这里又发生了什么？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;从“模板蓝图”到“可执行代码”这个过程，是在调用函数时，编译器识别到参数的具体类型时发生的。&lt;/li&gt;
&lt;li&gt;在上面的例子中，第一个 &lt;code&gt;add&lt;/code&gt; 函数识别到输入的参数为 &lt;code&gt;int&lt;/code&gt; 类型，因此执行 &lt;code&gt;int&lt;/code&gt; 类型的加法；而第二个 &lt;code&gt;add&lt;/code&gt; 函数识别到输入的参数为 &lt;code&gt;double&lt;/code&gt; 类型，因此执行 &lt;code&gt;double&lt;/code&gt; 类型的加法。&lt;/li&gt;
&lt;li&gt;这个过程被称为&lt;strong&gt;模板实例化&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;在上面的例子中，模板实例化由编译器自动完成，而不是程序员手动指定，这样的实例化过程被称为隐式实例化 (Implicit Instantiation)。&lt;/li&gt;
&lt;li&gt;而程序员手动指定类型并提前生成代码的实例化，被称为显式实例化 (Explicit Instantiation)。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面是一个基于 &lt;code&gt;add&lt;/code&gt; 函数的显式实例化的例子：&lt;/p&gt;</description></item><item><title>inline内联函数</title><link>https://Mist2233.github.io/posts/inline%E5%86%85%E8%81%94%E5%87%BD%E6%95%B0/</link><pubDate>Mon, 22 Sep 2025 08:39:31 +0800</pubDate><guid>https://Mist2233.github.io/posts/inline%E5%86%85%E8%81%94%E5%87%BD%E6%95%B0/</guid><description>&lt;h2 id="inline-的好处与坏处"&gt;&lt;code&gt;inline&lt;/code&gt; 的好处与坏处&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 中，我们可以在函数声明或定义前，加上 &lt;code&gt;inline&lt;/code&gt; 关键字。&lt;/p&gt;
&lt;p&gt;请问，&lt;code&gt;inline&lt;/code&gt; 关键字是用来做什么的？它是在向编译器&lt;strong&gt;建议&lt;/strong&gt;什么？使用内联函数，主要可能带来什么&lt;strong&gt;好处&lt;/strong&gt;，又可能带来什么&lt;strong&gt;坏处&lt;/strong&gt;？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;inline&lt;/code&gt; 关键字用于声明内联函数，它在向编译器建议：“这个函数代码很短，请你将它的代码直接嵌入我们调用它的地方，而不用进行调用跳转。”&lt;/li&gt;
&lt;li&gt;当然，这只是一个建议，编译器有最终的决定权。如果编译器觉得这个函数过于复杂，那么它会忽略 &lt;code&gt;inline&lt;/code&gt; 的建议，仍然执行调用跳转。&lt;/li&gt;
&lt;li&gt;好处：
&lt;ul&gt;
&lt;li&gt;使用内联函数，尤其是对短小且频繁调用的函数，可以省去函数调用的开销，执行效率更高。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;坏处：
&lt;ul&gt;
&lt;li&gt;编译更加复杂，导致编译时间增加。&lt;/li&gt;
&lt;li&gt;由于每次都要复制一份函数体代码到调用处，因此代码膨胀，且指令数量增加，指令缓存效率受影响。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (总结与补充):&lt;/strong&gt; 你说的非常好。我来帮你把这些点串联和补充一下，形成一个更完整的知识体系。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;什么是函数调用开销？&lt;/strong&gt;
当你省去“函数调用开销”时，具体省去了什么？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;参数压栈&lt;/strong&gt;：将函数参数按照调用约定压入栈中。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;返回地址压栈&lt;/strong&gt;：将调用点下一条指令的地址压入栈中，以便函数返回时能继续执行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跳转&lt;/strong&gt;：CPU 执行 &lt;code&gt;call&lt;/code&gt; 指令，跳转到函数体的入口地址。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;栈帧建立&lt;/strong&gt;：为函数的局部变量分配栈空间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;函数返回&lt;/strong&gt;：执行 &lt;code&gt;ret&lt;/code&gt; 指令，从栈中弹出返回地址，并跳转回去。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;栈帧销毁&lt;/strong&gt;：释放局部变量空间。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于一个只有一两行代码的函数，这些“行政”开销，可能比真正执行函数体代码的开销还要大得多。&lt;code&gt;inline&lt;/code&gt; 的目的就是消除这些“行政”开销。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你提到的坏处——代码膨胀 (Code Bloat)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这是一个非常重要的权衡。如果一个函数体本身很大，内联它会导致可执行文件的体积急剧增大。&lt;/li&gt;
&lt;li&gt;这不仅占用更多磁盘空间，更重要的是，它会破坏&lt;strong&gt;指令缓存 (Instruction Cache, i-cache) 的局部性&lt;/strong&gt;。CPU 访问内存的速度远慢于执行指令的速度，所以它会把最近用到的指令缓存起来。如果代码体积太大，缓存装不下，就会导致频繁的“缓存未命中 (cache miss)”，CPU 需要去慢速的主存中读取指令，反而降低了程序的整体性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;编译器的决定权&lt;/strong&gt;
现代编译器非常智能，它在决定是否内联时，通常会自己做判断，即使你没有加 &lt;code&gt;inline&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;它会&lt;strong&gt;自动内联&lt;/strong&gt;它认为合适的、足够简单的函数（比如定义在类头文件中的成员函数，默认就是 &lt;code&gt;inline&lt;/code&gt; 的）。&lt;/li&gt;
&lt;li&gt;它会&lt;strong&gt;拒绝内联&lt;/strong&gt;过于复杂的函数，即使你加了 &lt;code&gt;inline&lt;/code&gt; 关键字。比如，包含循环、递归、大量 &lt;code&gt;switch&lt;/code&gt; 的函数通常不会被内联。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="inline-的语法作用解决-odr-违例问题"&gt;&lt;code&gt;inline&lt;/code&gt; 的语法作用——解决 ODR 违例问题&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官 (深入提问):&lt;/strong&gt; 好的，你对 &lt;code&gt;inline&lt;/code&gt; 的性能考量已经很清楚了。&lt;/p&gt;</description></item><item><title>委托构造函数</title><link>https://Mist2233.github.io/posts/%E5%A7%94%E6%89%98%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0/</link><pubDate>Sat, 20 Sep 2025 09:59:58 +0800</pubDate><guid>https://Mist2233.github.io/posts/%E5%A7%94%E6%89%98%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0/</guid><description>&lt;h2 id="委托构造函数-delegating-constructors"&gt;委托构造函数 Delegating Constructors&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 中，我们经常会为一个类提供多个构造函数，以方便使用者用不同的方式来初始化对象。&lt;/p&gt;
&lt;p&gt;请看下面这个 C++03 风格的例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 构造函数 1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 假设还有一些其他的通用初始化逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Common logic executed.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 构造函数 2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;val_a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val_a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 同样的通用初始化逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Common logic executed.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 构造函数 3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;val_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;val_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val_a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;val_b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 又是同样的通用初始化逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Common logic executed.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;你可以看到，这三个构造函数中，有很多&lt;strong&gt;重复的代码&lt;/strong&gt;（比如对 &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt; 的初始化，以及那个通用的逻辑）。在 C++11 之前，处理这种代码重复是一个比较头疼的问题。&lt;/p&gt;</description></item><item><title>NULL和nullptr</title><link>https://Mist2233.github.io/posts/null%E5%92%8Cnullptr/</link><pubDate>Thu, 18 Sep 2025 08:33:33 +0800</pubDate><guid>https://Mist2233.github.io/posts/null%E5%92%8Cnullptr/</guid><description>&lt;h2 id="nullptr-解决函数重载的二义性"&gt;&lt;code&gt;nullptr&lt;/code&gt; 解决函数重载的二义性&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++11 之前，我们通常使用一个宏 &lt;code&gt;NULL&lt;/code&gt; 来表示空指针。而在 C++11 中，引入了一个新的关键字 &lt;code&gt;nullptr&lt;/code&gt; 来专门表示空指针。&lt;/p&gt;
&lt;p&gt;请问，我们为什么需要 &lt;code&gt;nullptr&lt;/code&gt;？或者说，使用宏 &lt;code&gt;NULL&lt;/code&gt; 在某些情况下，会带来什么样的问题或歧义，是 &lt;code&gt;nullptr&lt;/code&gt; 能够解决的？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;NULL&lt;/code&gt; 是一个宏，它除了表示空指针之外，更常用的含义是表示 &lt;code&gt;0&lt;/code&gt;，一个整数。&lt;/li&gt;
&lt;li&gt;由于 &lt;code&gt;NULL&lt;/code&gt; 既能表示空指针，又能表示 &lt;code&gt;0&lt;/code&gt;，因此它会引发歧义。&lt;/li&gt;
&lt;li&gt;比如，某个函数重载了两个版本，一个的参数类型是 &lt;code&gt;int&lt;/code&gt;，而另一个参数类型是 &lt;code&gt;char*&lt;/code&gt;。当输入 &lt;code&gt;NULL&lt;/code&gt; 时，通常会调用参数为 &lt;code&gt;int&lt;/code&gt; 的那个版本。&lt;/li&gt;
&lt;li&gt;而使用 &lt;code&gt;nullptr&lt;/code&gt; 则规避了这一风险。&lt;code&gt;nullptr&lt;/code&gt; 是一个真正的空指针常量，它是一个特殊的类型 &lt;code&gt;std::nullptr_t&lt;/code&gt;，可以隐式地转换为任何的指针类型，而不会和 &lt;code&gt;int&lt;/code&gt; 类型混淆。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (总结与肯定):&lt;/strong&gt; 你说的完全正确。我们来把这个过程再详细地梳理一遍。&lt;code&gt;nullptr&lt;/code&gt; 诞生的&lt;strong&gt;核心原因&lt;/strong&gt;是&lt;strong&gt;解决函数重载时的二义性&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;NULL&lt;/code&gt; 的“前世今生”&lt;/strong&gt;
&lt;code&gt;NULL&lt;/code&gt; 是一个定义在 &lt;code&gt;&amp;lt;cstddef&amp;gt;&lt;/code&gt; 等头文件中的&lt;strong&gt;预处理宏&lt;/strong&gt;。它的具体定义取决于编译器，但通常是下面两种之一：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define NULL 0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 或者
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define NULL 0L
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 或者在 C++ 编译器中，有时甚至是
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define NULL nullptr &lt;/span&gt;&lt;span class="c1"&gt;// 这是现代编译器的“向后兼容”行为
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在 C++98/03 的时代，你可以认为 &lt;code&gt;NULL&lt;/code&gt; 就是一个值为 &lt;code&gt;0&lt;/code&gt; 的&lt;strong&gt;整型常量&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>Cpp异常处理机制</title><link>https://Mist2233.github.io/posts/cpp%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6/</link><pubDate>Wed, 17 Sep 2025 09:14:16 +0800</pubDate><guid>https://Mist2233.github.io/posts/cpp%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E6%9C%BA%E5%88%B6/</guid><description>&lt;h2 id="栈展开"&gt;栈展开&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 中，当我们使用 &lt;code&gt;try...catch&lt;/code&gt; 块来处理异常时，有一个重要的过程叫做 &lt;strong&gt;“栈展开 (Stack Unwinding)”&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;你能用自己的话，简单描述一下，当一个异常被 &lt;code&gt;throw&lt;/code&gt; 出来之后，到它被某个 &lt;code&gt;catch&lt;/code&gt; 块捕获之前，这个“栈展开”的过程具体发生了什么吗？特别是，对于那些在栈上创建的对象，会发生什么？&lt;/p&gt;
&lt;p&gt;比如，请看下面这段代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 一个简单的类，在构造和析构时会打印信息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;RAII_Helper&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RAII_Helper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;RAII_Helper &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; constructed.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;RAII_Helper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;RAII_Helper &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; destructed.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;func_C&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RAII_Helper&lt;/span&gt; &lt;span class="n"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Entering func_C, about to throw.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;runtime_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;An error occurred in C!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;This line in func_C is never reached.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;func_B&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RAII_Helper&lt;/span&gt; &lt;span class="n"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Entering func_B, calling C.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;func_C&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;This line in func_B is never reached.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;func_A&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RAII_Helper&lt;/span&gt; &lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Entering func_A, calling B.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;func_B&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Caught exception in A: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;what&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Exiting func_A.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;func_A&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;函数调用链是 &lt;code&gt;main&lt;/code&gt; -&amp;gt; &lt;code&gt;func_A&lt;/code&gt; -&amp;gt; &lt;code&gt;func_B&lt;/code&gt; -&amp;gt; &lt;code&gt;func_C&lt;/code&gt;。&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>Cpp字符串处理</title><link>https://Mist2233.github.io/posts/cpp%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%A4%84%E7%90%86/</link><pubDate>Mon, 15 Sep 2025 09:21:27 +0800</pubDate><guid>https://Mist2233.github.io/posts/cpp%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%A4%84%E7%90%86/</guid><description>&lt;h2 id="stdstring-的优点"&gt;&lt;code&gt;std::string&lt;/code&gt; 的优点&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 中，我们有两种主要的方式来表示字符串：C++ 标准库提供的 &lt;code&gt;std::string&lt;/code&gt; 类，以及从 C 语言继承来的、以空字符 &lt;code&gt;\0&lt;/code&gt; 结尾的字符数组（我们常说的 C 风格字符串，通常用 &lt;code&gt;char*&lt;/code&gt; 或 &lt;code&gt;const char*&lt;/code&gt; 指针来表示）。&lt;/p&gt;
&lt;p&gt;请问，和传统的 C 风格字符串相比，使用 &lt;code&gt;std::string&lt;/code&gt; 类有什么主要的&lt;strong&gt;优点&lt;/strong&gt;？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;std::string&lt;/code&gt; 的封装程度更好，使用时不易出错。&lt;/li&gt;
&lt;li&gt;具体来说，包括自动内存管理、安全性和功能性三个方面。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (补充与扩展):&lt;/strong&gt; 你说的完全正确。&lt;code&gt;std.string&lt;/code&gt; 作为一个&lt;strong&gt;类&lt;/strong&gt;，把所有复杂的、容易出错的底层操作都&lt;strong&gt;封装&lt;/strong&gt;起来了，为我们提供了极大的便利和安全保障。&lt;/p&gt;
&lt;p&gt;我来帮你把它的优点展开成几个具体的点，这也是面试时希望听到的内容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;自动内存管理 (Automatic Memory Management)&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;std::string&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;string&lt;/code&gt; 对象自己会负责管理存储字符串所需的内存。当字符串变长时，它会自动&lt;strong&gt;扩容&lt;/strong&gt;；当 &lt;code&gt;string&lt;/code&gt; 对象被销毁时，它会自动&lt;strong&gt;释放&lt;/strong&gt;内存。你完全不需要操心 &lt;code&gt;new[]&lt;/code&gt; 和 &lt;code&gt;delete[]&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;char*&lt;/code&gt;&lt;/strong&gt;: 你必须手动管理内存。&lt;code&gt;malloc&lt;/code&gt; / &lt;code&gt;free&lt;/code&gt; 或 &lt;code&gt;new[]&lt;/code&gt; / &lt;code&gt;delete[]&lt;/code&gt; 必须成对出现，极其容易忘记释放，导致&lt;strong&gt;内存泄漏&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;安全性 (Safety)&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;std::string&lt;/code&gt;&lt;/strong&gt;: 它内部记录了字符串的&lt;strong&gt;当前长度&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;成员函数 &lt;code&gt;length()&lt;/code&gt; 或 &lt;code&gt;size()&lt;/code&gt; 可以 O (1) 复杂度地返回长度。&lt;/li&gt;
&lt;li&gt;成员函数 &lt;code&gt;at(i)&lt;/code&gt; 提供&lt;strong&gt;边界检查&lt;/strong&gt;，越界会抛出异常。&lt;/li&gt;
&lt;li&gt;拼接、拷贝等操作都会自动处理内存，不会造成缓冲区溢出。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;char*&lt;/code&gt;&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;长度信息依赖于结尾的 &lt;code&gt;\0&lt;/code&gt;。每次计算长度 (&lt;code&gt;strlen&lt;/code&gt;) 都需要从头遍历，时间复杂度 O (n)。&lt;/li&gt;
&lt;li&gt;所有操作（如 &lt;code&gt;strcpy&lt;/code&gt;, &lt;code&gt;strcat&lt;/code&gt;）都&lt;strong&gt;不进行边界检查&lt;/strong&gt;，如果目标缓冲区不够大，就会发生&lt;strong&gt;缓冲区溢出&lt;/strong&gt;，这是 C/C++ 中最危险的安全漏洞之一。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;功能丰富且易用 (Rich Functionality)&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>Cpp的三种类型推导关键字</title><link>https://Mist2233.github.io/posts/cpp%E7%9A%84%E4%B8%89%E7%A7%8D%E7%B1%BB%E5%9E%8B%E6%8E%A8%E5%AF%BC%E5%85%B3%E9%94%AE%E5%AD%97/</link><pubDate>Sun, 14 Sep 2025 09:33:26 +0800</pubDate><guid>https://Mist2233.github.io/posts/cpp%E7%9A%84%E4%B8%89%E7%A7%8D%E7%B1%BB%E5%9E%8B%E6%8E%A8%E5%AF%BC%E5%85%B3%E9%94%AE%E5%AD%97/</guid><description>&lt;h2 id="auto-关键字"&gt;&lt;code&gt;auto&lt;/code&gt; 关键字&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; C++11 引入了 &lt;code&gt;auto&lt;/code&gt; 关键字，它极大地改变了我们编写 C++ 代码的方式。&lt;/p&gt;
&lt;p&gt;你能简单解释一下，&lt;code&gt;auto&lt;/code&gt; 关键字的作用是什么吗？使用它有什么好处？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt; 关键字的作用是，省略具体的变量类型，而是根据实际变量的类型推导出其类型。&lt;/li&gt;
&lt;li&gt;使用 &lt;code&gt;auto&lt;/code&gt; 关键字，就不必写复杂的类型名（比如常用的 STL 迭代器），让代码看上去更简洁。&lt;/li&gt;
&lt;li&gt;同时，&lt;code&gt;auto&lt;/code&gt; 关键字还能实现类似“多态”的效果（这里说“多态”不太准确，应该说，是泛型编程），使得同一份代码可以被许多不同的类型复用。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (补充与澄清):&lt;/strong&gt; 你说的很对。我们来把你的回答再精确化和补充一下。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;auto&lt;/code&gt; 的作用：&lt;/strong&gt;
它是一个&lt;strong&gt;类型占位符&lt;/strong&gt;。编译器会在&lt;strong&gt;编译时&lt;/strong&gt;，根据变量的&lt;strong&gt;初始化表达式&lt;/strong&gt;，自动推导出变量应该具有的正确类型。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;auto&lt;/code&gt; 的好处：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;简洁性 (Brevity)&lt;/strong&gt;：正如你所说，它可以避免写冗长、复杂的类型名。这一点在处理 STL 的&lt;strong&gt;迭代器&lt;/strong&gt;和&lt;strong&gt;模板&lt;/strong&gt;时尤其明显。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// C++03
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;::&lt;/span&gt;&lt;span class="n"&gt;iterator&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// C++11 with auto
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 简洁、易读、不易出错
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;正确性 (Correctness)&lt;/strong&gt;：&lt;code&gt;auto&lt;/code&gt; 保证了变量的类型与初始化表达式的类型&lt;strong&gt;完全匹配&lt;/strong&gt;，避免了因手写类型错误或发生意外的类型转换而导致的 bug。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可维护性 (Maintainability)&lt;/strong&gt;：如果初始化表达式的类型未来发生了变化（比如一个函数的返回值从 &lt;code&gt;int&lt;/code&gt; 变成了 &lt;code&gt;long long&lt;/code&gt;），使用了 &lt;code&gt;auto&lt;/code&gt; 的代码&lt;strong&gt;不需要任何修改&lt;/strong&gt;，会自动适应新的类型。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;关于你提到的“多态效果”：&lt;/strong&gt;
这个描述非常有趣！&lt;code&gt;auto&lt;/code&gt; 本身是在编译期进行类型推导，不直接产生运行时的多态（那需要虚函数）。但你说的“使得同一份代码可以被许多不同的类型复用”，这个思想非常接近&lt;strong&gt;泛型编程 (Generic Programming)&lt;/strong&gt;。
&lt;code&gt;auto&lt;/code&gt; 在 C++14 的&lt;strong&gt;泛型 Lambda&lt;/strong&gt; 中 &lt;code&gt;[](auto x){ ... }&lt;/code&gt; 和 C++20 的&lt;strong&gt;函数参数&lt;/strong&gt;中 &lt;code&gt;void func(auto param)&lt;/code&gt;，确实扮演了类似模板参数的角色，让一段代码能适用于多种类型。你的直觉是非常准的。&lt;/p&gt;</description></item><item><title>Lambda表达式</title><link>https://Mist2233.github.io/posts/lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F/</link><pubDate>Sat, 13 Sep 2025 18:22:44 +0800</pubDate><guid>https://Mist2233.github.io/posts/lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F/</guid><description>&lt;h2 id="什么是-lambda-表达式"&gt;什么是 Lambda 表达式？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 好的，我们来聊聊 C++11 引入的一个非常强大的特性——&lt;strong&gt;Lambda 表达式&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;你能用自己的话简单解释一下，Lambda 表达式是什么吗？它主要解决了什么问题，或者说，它为我们编写 C++ 代码带来了什么样的便利？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我的理解是，lambda 表达式就是“匿名函数”，即省略名字的函数。&lt;/li&gt;
&lt;li&gt;它定义了一个函数，这个函数有函数的所有功能，但不需要名字。&lt;/li&gt;
&lt;li&gt;这让我们在需要写一些小巧的工具性一次性函数时，省去了从头定义函数的麻烦，让代码看上去更加简洁。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (补充与肯定):&lt;/strong&gt; 你说的完全正确。Lambda 表达式的出现，极大地改变了 C++ 的编程风格，特别是与标准库算法（STL Algorithms）结合使用时。&lt;/p&gt;
&lt;p&gt;在 C++11 之前，如果我们需要给 &lt;code&gt;std::sort&lt;/code&gt;, &lt;code&gt;std::find_if&lt;/code&gt; 这样的算法传递一个自定义的比较或判断逻辑，我们通常需要：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在别处定义一个完整的具名函数。&lt;/li&gt;
&lt;li&gt;或者定义一个函数对象（一个重载了 &lt;code&gt;operator()&lt;/code&gt; 的 &lt;code&gt;struct&lt;/code&gt; 或 &lt;code&gt;class&lt;/code&gt;）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这两种方式都比较繁琐，并且会导致&lt;strong&gt;逻辑和使用点的分离&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;而 Lambda 表达式，正如你所说，允许我们在&lt;strong&gt;需要的地方，就地定义&lt;/strong&gt;一个匿名的、小巧的函数，让代码更紧凑、可读性也更强。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="lambda-表达式的捕获列表"&gt;Lambda 表达式的捕获列表&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官 (深入提问):&lt;/strong&gt; 好的，你对 Lambda 的基本概念很清楚。我们来看一下 Lambda 表达式的语法结构。&lt;/p&gt;
&lt;p&gt;一个完整的 Lambda 表达式看起来像这样：
&lt;code&gt;[ captures ] ( params ) -&amp;gt; return_type { body }&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;其中，&lt;code&gt;[ captures ]&lt;/code&gt; 这个部分，我们称之为&lt;strong&gt;捕获列表 (Capture List)&lt;/strong&gt;，这是 Lambda 表达式最强大、也最核心的部分。&lt;/p&gt;</description></item><item><title>左值与右值</title><link>https://Mist2233.github.io/posts/%E5%B7%A6%E5%80%BC%E4%B8%8E%E5%8F%B3%E5%80%BC/</link><pubDate>Tue, 09 Sep 2025 10:09:30 +0800</pubDate><guid>https://Mist2233.github.io/posts/%E5%B7%A6%E5%80%BC%E4%B8%8E%E5%8F%B3%E5%80%BC/</guid><description>&lt;h2 id="什么是左值什么是右值如何区分它们"&gt;什么是左值？什么是右值？如何区分它们？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 中，我们经常听到“左值”和“右值”这两个术语。你能用自己的话，简单地解释一下，什么是左值，什么是右值吗？最简单的区分它们的方法是什么？&lt;/p&gt;
&lt;p&gt;回答：我在一年多前的程序设计课上学过这两个概念，但现在我的记忆已经模糊，凭感觉回答一下。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;左值是被持久保存而不是临时保存的值，它通常就是我们定义的变量的值。因为出现在赋值式子的左边，所以叫做“左值”。&lt;/li&gt;
&lt;li&gt;右值是通过某些代数计算式得到的临时值，它通常出现在赋值式子的右边，因此被称为“右值”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;面试官 (补充与深化):&lt;/strong&gt; 你说的“能否放在赋值运算符左边”是一个非常好的启发式判断方法。一个更根本的、适用于现代 C++ 的区分标准是：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;我们能否对这个表达式“取地址”？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;左值 (lvalue)&lt;/strong&gt;：是一个&lt;strong&gt;表达式&lt;/strong&gt;，它指向了一个&lt;strong&gt;具名的、有持久状态的&lt;/strong&gt;对象或函数。我们可以&lt;strong&gt;对它取地址&lt;/strong&gt; (&lt;code&gt;&amp;amp;&lt;/code&gt;)。它在表达式结束后，依然存在。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;例子&lt;/strong&gt;：变量名 &lt;code&gt;int x;&lt;/code&gt; &lt;code&gt;x&lt;/code&gt; 是一个左值，我们可以 &lt;code&gt;&amp;amp;x&lt;/code&gt;。&lt;code&gt;std::string s;&lt;/code&gt; &lt;code&gt;s&lt;/code&gt; 是一个左值。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;右值 (rvalue)&lt;/strong&gt;：是一个&lt;strong&gt;表达式&lt;/strong&gt;，它通常代表一个&lt;strong&gt;匿名的、即将被销毁的临时值&lt;/strong&gt;。我们&lt;strong&gt;无法对它取地址&lt;/strong&gt;。它在表达式结束后，就不复存在了。
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;例子&lt;/strong&gt;：字面量 &lt;code&gt;10&lt;/code&gt; 是一个右值，你不能 &lt;code&gt;&amp;amp;10&lt;/code&gt;。函数返回值 &lt;code&gt;get_string()&lt;/code&gt;（如果返回的是一个值而非引用）是一个右值。&lt;code&gt;x + y&lt;/code&gt; 这个表达式的结果也是一个右值。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;总结一下：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;左值&lt;/strong&gt;：有家（内存地址），能活得久。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;右值&lt;/strong&gt;：没家（没法取地址），是“过客”（马上就消失）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="右值引用"&gt;右值引用&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官 (引入新概念):&lt;/strong&gt; 好的，既然我们知道了左值和右值的区别。C++11 为了配合移动语义，引入了一种新的引用类型，叫做&lt;strong&gt;右值引用 (rvalue reference)&lt;/strong&gt;，用 &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 表示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// x 是一个左值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;l_ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 左值引用 l_ref 绑定到左值 x (OK)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;r_ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 右值引用 r_ref 绑定到右值 20 (OK)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// int&amp;amp;&amp;amp; r_ref2 = x; // 错误！右值引用不能直接绑定到左值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;请问，&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; 这个右值引用的主要设计目的是什么？它和我们之前讨论的&lt;strong&gt;移动语义 (Move Semantics)&lt;/strong&gt; 是如何关联起来的？&lt;/p&gt;</description></item><item><title>构造函数相关知识</title><link>https://Mist2233.github.io/posts/%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86/</link><pubDate>Sun, 07 Sep 2025 21:25:43 +0800</pubDate><guid>https://Mist2233.github.io/posts/%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86/</guid><description>&lt;h2 id="如果没有定义构造函数默认构造函数"&gt;如果没有定义构造函数——默认构造函数&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 好的，我们来聊聊 C++ 的一个核心特性——&lt;strong&gt;构造函数 (Constructor)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我们知道，构造函数是在创建对象时被自动调用的一个特殊函数。除了我们最常见的、带参数的普通构造函数之外，C++ 编译器在某些情况下，还会为我们&lt;strong&gt;自动生成&lt;/strong&gt;一些特殊的构造函数。&lt;/p&gt;
&lt;p&gt;我的第一个问题是：如果我们在类中&lt;strong&gt;没有定义任何&lt;/strong&gt;构造函数，编译器会为我们自动生成一个什么样的构造函数？它的作用是什么？&lt;/p&gt;
&lt;p&gt;回答：我不太了解这个问题，所以凭感觉回答，请你为我补充。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;编译器自动为我们生成的构造函数不会初始化任何的成员变量，所有的成员变量都处于原始状态。&lt;/li&gt;
&lt;li&gt;它的作用是保证对象能够生成，而不会导致报错，起到占位的作用。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (补充与解释):&lt;/strong&gt; 你说得基本正确。如果我们在类中没有定义任何构造函数，编译器会为我们生成一个&lt;strong&gt;默认构造函数 (Default Constructor)&lt;/strong&gt;。这是一个&lt;strong&gt;无参数&lt;/strong&gt;的构造函数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这个自动生成的默认构造函数，它会做什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它的行为比我们想象的要“智能”一点，它遵循一个规则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;对于类类型的成员 (Class-type Members)&lt;/strong&gt;：如果这个类成员&lt;strong&gt;有自己的默认构造函数&lt;/strong&gt;，那么编译器生成的默认构造函数就会&lt;strong&gt;自动调用&lt;/strong&gt;这个成员的默认构造函数。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Engine constructed&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 没有定义任何构造函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Engine&lt;/span&gt; &lt;span class="n"&gt;engine_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 类类型成员
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 当你创建 Car c; 时，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Car 的合成默认构造函数会被调用，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 它会自动调用 Engine 的默认构造函数，
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 所以你会看到 &amp;#34;Engine constructed&amp;#34; 输出。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;对于内置类型的成员 (Built-in Type Members, e.g., &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;, 指针)&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>final和override关键字</title><link>https://Mist2233.github.io/posts/final%E5%92%8Coverride%E5%85%B3%E9%94%AE%E5%AD%97/</link><pubDate>Sun, 07 Sep 2025 08:53:49 +0800</pubDate><guid>https://Mist2233.github.io/posts/final%E5%92%8Coverride%E5%85%B3%E9%94%AE%E5%AD%97/</guid><description>&lt;h2 id="关键字-override"&gt;关键字 &lt;code&gt;override&lt;/code&gt;&lt;/h2&gt;
&lt;h3 id="没有-override-时存在的风险"&gt;没有 &lt;code&gt;override&lt;/code&gt; 时存在的风险&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++11 之后，我们在处理类的继承和虚函数时，多了 &lt;code&gt;override&lt;/code&gt; 和 &lt;code&gt;final&lt;/code&gt; 这两个说明符。我们先来聊聊 &lt;strong&gt;&lt;code&gt;override&lt;/code&gt;&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;请看下面这段代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Derived&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 这里有一个小小的笔误，程序员将int写成了long
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;在 &lt;code&gt;Derived&lt;/code&gt; 类中，程序员的&lt;strong&gt;意图&lt;/strong&gt;是&lt;strong&gt;重写 (override)&lt;/strong&gt; 基类的 &lt;code&gt;doSomething&lt;/code&gt; 函数。但由于笔误，他把参数类型从 &lt;code&gt;int&lt;/code&gt; 写成了 &lt;code&gt;long&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;请问，在没有 &lt;code&gt;override&lt;/code&gt; 关键字的情况下，这段代码能编译通过吗？如果能，它在多态调用时，可能会产生什么样的问题？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;我认为编译能够通过。由于参数列表不同（这里是参数类型不同），编译器会认为程序员在 &lt;code&gt;Derived&lt;/code&gt; 类中重载了一个虚函数。&lt;/li&gt;
&lt;li&gt;可能的问题：在多态调用时，会出现函数参数实际类型不一致的情况，可能导致冲突。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;面试官 (补充与解释):&lt;/strong&gt; 你说的很对。我们来把这个问题分析得更透彻一些。&lt;/p&gt;</description></item><item><title>函数重载和函数重写</title><link>https://Mist2233.github.io/posts/%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD%E5%92%8C%E5%87%BD%E6%95%B0%E9%87%8D%E5%86%99/</link><pubDate>Sat, 06 Sep 2025 09:28:27 +0800</pubDate><guid>https://Mist2233.github.io/posts/%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD%E5%92%8C%E5%87%BD%E6%95%B0%E9%87%8D%E5%86%99/</guid><description>&lt;p&gt;昨天我们聊了虚函数和多态的实现，今天我们来聊一个与它紧密相关，但在概念上又容易混淆的话题：&lt;strong&gt;重载 (Overloading)、重写 (Overriding) 和隐藏 (Hiding)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这三个术语描述了 C++ 中函数名相同但行为不同的几种情况，是面试中考察“你是否能精确理解 C++ 概念”的经典问题。&lt;/p&gt;
&lt;h2 id="overloading-和-overriding-的区别"&gt;Overloading 和 Overriding 的区别&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 中，我们经常会遇到函数名相同的情况。你能用自己的话分别解释一下，什么是&lt;strong&gt;函数重载 (Overloading)&lt;/strong&gt; 和&lt;strong&gt;函数重写 (Overriding)&lt;/strong&gt; 吗？它们两者最主要的区别是什么？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回答&lt;/strong&gt;：Overloading 指的是两个函数同名，但是参数列表不同的情况。&lt;/p&gt;
&lt;p&gt;Overriding 指的是两个函数同名、参数也相同（更准确地说，函数签名完全相同），但是一个在派生类中，另一个在基类中的情况。&lt;/p&gt;
&lt;p&gt;我认为它们的主要区别是“参数是否相同”，以及“两者之间的关系是并列（Overloading）还是继承（Overriding）”。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;你的回答&lt;strong&gt;非常出色&lt;/strong&gt;！直截了当，并且准确地抓住了两者最核心的区别。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;重载 (Overloading)&lt;/strong&gt;: 关键在于&lt;strong&gt;参数列表不同&lt;/strong&gt; (参数个数、类型、顺序)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重写 (Overriding)&lt;/strong&gt;: 关键在于&lt;strong&gt;继承关系&lt;/strong&gt;，并且&lt;strong&gt;函数签名 (signature) 必须完全相同&lt;/strong&gt; (函数名、参数列表、&lt;code&gt;const&lt;/code&gt; 属性等都相同)。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你的总结“关系是并列还是继承”也非常形象。重载的函数之间是“兄弟”关系，而重写的函数之间是“父子”关系。&lt;/p&gt;
&lt;h2 id="确定多态的时机编译器运行期"&gt;确定多态的时机——编译器？运行期？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官 (补充与追问):&lt;/strong&gt; 你说得很好。我们来把这个概念再深化一下。&lt;/p&gt;
&lt;p&gt;重载和重写，它们分别是在哪个阶段被决定的？一个是在&lt;strong&gt;编译期 (Compile-time)&lt;/strong&gt;，一个是在&lt;strong&gt;运行期 (Run-time)&lt;/strong&gt;。你觉得哪个对应哪个？为什么？&lt;/p&gt;
&lt;p&gt;这可以帮助我们理解它们更深层次的机制差异。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;回答&lt;/strong&gt;：我认为，Overloading 属于&lt;strong&gt;静态多态&lt;/strong&gt;，在编译期就被确定了，因为具有 overloading 关系的两个函数只有名字相同，而函数签名不同，事实上可以被看作两个不同函数，这使得编译器可以分辨他们。（编译器在处理函数调用时，会根据传入的实参类型、数量和顺序，查找应该匹配的函数，这个过程被叫做“名字修饰”）&lt;/p&gt;
&lt;p&gt;而对于 overriding 属于&lt;strong&gt;动态多态&lt;/strong&gt;，需要在运行期才能被确定，这和我们昨天讨论的虚函数与多态相关，程序必须通过 v-ptr 和 v-table 才能确定我们调用的到底是哪一个函数。‘&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官 (总结与肯定):&lt;/strong&gt; 你说得对极了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;重载 (Overloading) 属于静态多态&lt;/strong&gt;，是在&lt;strong&gt;编译期&lt;/strong&gt;决定的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;编译器在处理函数调用时，会根据你传入的&lt;strong&gt;实参类型、数量和顺序&lt;/strong&gt;，像查字典一样，去查找应该匹配哪个版本的同名函数。这个过程叫做&lt;strong&gt;名字修饰 (Name Mangling)&lt;/strong&gt; 或名称改编。编译器会给每个重载函数一个独特的内部名称，所以对编译器来说，它们就是不同的函数。这个决策过程完全不需要等到程序运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;重写 (Overriding) 属于动态多态&lt;/strong&gt;，是在&lt;strong&gt;运行期&lt;/strong&gt;决定的。&lt;/p&gt;</description></item><item><title>面向对象与多态</title><link>https://Mist2233.github.io/posts/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E4%B8%8E%E5%A4%9A%E6%80%81/</link><pubDate>Sat, 06 Sep 2025 09:28:10 +0800</pubDate><guid>https://Mist2233.github.io/posts/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E4%B8%8E%E5%A4%9A%E6%80%81/</guid><description>&lt;h2 id="什么是多态实现技术是什么"&gt;什么是多态？实现技术是什么？&lt;/h2&gt;
&lt;blockquote&gt;&lt;p&gt;看到你的简历上写着熟悉 C++ 的面向对象编程。那你能用自己的话简单解释一下，什么是&lt;strong&gt;多态&lt;/strong&gt;吗？在 C++ 中，我们通常通过什么关键技术来实现多态？&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;我理解的多态，就是同一个函数在不同的继承类中可以有不同的内容，这取决于子类自己的实现方式。（更精炼的表达：&lt;strong&gt;同一个接口，不同的实现。&lt;/strong&gt;）&lt;/p&gt;
&lt;p&gt;实现多态的关键技术通常是虚函数 (virtual function)，即基类中声明的函数，在派生类中可以有自己另外的实现 (override)，从而适配每个派生类的具体情况。（如果基类中没有对这一函数的实现，全部靠派生类自己实现，那么这种函数就是纯虚函数）&lt;/p&gt;
&lt;h2 id="用基类指针指向派生类对象"&gt;用基类指针指向派生类对象&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 这是一个普通的虚函数，它有自己的实现
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;makeSound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Some generic animal sound&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Dog 类重写(override)了父类的虚函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;makeSound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Woof!&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Animal&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pAnimal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 用基类指针指向派生类对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pAnimal&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;makeSound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 请问，这里会输出什么？
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;如果用基类指针指向派生类对象，并调用函数，那么这个函数应该是派生类中覆写后的版本，而不是基类中的版本。&lt;/p&gt;
&lt;p&gt;即：输出结果取决于指针实际指向的对象的类型（&lt;strong&gt;动态类型&lt;/strong&gt;），而不是指针变量本身声明的类型（&lt;strong&gt;静态类型&lt;/strong&gt;）。&lt;/p&gt;
&lt;p&gt;C++如何保证能调用正确的函数呢？这一点我只是依稀记得和 v-table 还有 v-ptr 相关，具体内容不记得了。&lt;/p&gt;</description></item><item><title>vector的内部实现和优化</title><link>https://Mist2233.github.io/posts/vector%E7%9A%84%E5%86%85%E9%83%A8%E5%AE%9E%E7%8E%B0%E5%92%8C%E4%BC%98%E5%8C%96/</link><pubDate>Sat, 06 Sep 2025 09:27:46 +0800</pubDate><guid>https://Mist2233.github.io/posts/vector%E7%9A%84%E5%86%85%E9%83%A8%E5%AE%9E%E7%8E%B0%E5%92%8C%E4%BC%98%E5%8C%96/</guid><description>&lt;h2 id="vector-在内存中如何存储数据和-array-的区别"&gt;&lt;code&gt;vector&lt;/code&gt; 在内存中如何存储数据？和 &lt;code&gt;array&lt;/code&gt; 的区别？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 我看你写的代码里经常使用 &lt;code&gt;std::vector&lt;/code&gt;。你能简单描述一下 &lt;code&gt;std::vector&lt;/code&gt; 在内存中是如何存储数据的吗？它和普通的 C 风格数组（比如 &lt;code&gt;int arr[10]&lt;/code&gt;）有什么主要的区别？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于这个问题，我并不太了解，我谈一谈我粗浅的看法。&lt;/li&gt;
&lt;li&gt;首先，vector 应该是基于数组 array 实现的，其底层就是一块动态分配的、连续的内存数组。这是 vector 能够支持快速随机访问的根本原因。但是，vector 肯定有它自身的优化在。&lt;/li&gt;
&lt;li&gt;边界检查：
&lt;ul&gt;
&lt;li&gt;array 只管给你分配一段连续的内存，其他的管理你都要自己来，也不会管你数组 idx 是否越界；&lt;/li&gt;
&lt;li&gt;在 vector 中，如果用 &lt;code&gt;[]&lt;/code&gt; 操作符，那么行为和 array 一样，不会管你越界与否；&lt;/li&gt;
&lt;li&gt;但是，vector 提供了 &lt;code&gt;at()&lt;/code&gt; 这个成员函数，&lt;code&gt;vec.at(i)&lt;/code&gt; 会进行边界检查。如果 &lt;code&gt;i&lt;/code&gt; 越界，vector 会抛出 &lt;code&gt;std::out_of_range&lt;/code&gt; 异常。这说明 vector 的安全性更好。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;自动初始化：
&lt;ul&gt;
&lt;li&gt;再比如，定义 array 时，程序不会帮我们自动初始化，array 中可能有一些奇怪的原始数据（随机值）；&lt;/li&gt;
&lt;li&gt;但是，定义 vector 时，程序会帮我们自动初始化。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不过，我没有提到 vector 和 array 最重要的区别：（根据 Gemini 的解释补充）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vector 的大小是动态可变的，可以不断地 &lt;code&gt;push_back&lt;/code&gt; 新的元素，而 array 的大小是固定的。&lt;/li&gt;
&lt;li&gt;这就是 vector 的动态扩容机制。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="vector-的扩容机制-reallocation"&gt;&lt;code&gt;vector&lt;/code&gt; 的扩容机制 (Reallocation)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官 (补充与追问):&lt;/strong&gt; 你说得很好。vector 最大的特点就是它的大小是&lt;strong&gt;动态可变&lt;/strong&gt;的。我们可以不断地对它 &lt;code&gt;push_back&lt;/code&gt; 新的元素。&lt;/p&gt;</description></item><item><title>C++的三种访问权限修饰符</title><link>https://Mist2233.github.io/posts/c++%E7%9A%84%E4%B8%89%E7%A7%8D%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90%E4%BF%AE%E9%A5%B0%E7%AC%A6/</link><pubDate>Sat, 06 Sep 2025 09:21:34 +0800</pubDate><guid>https://Mist2233.github.io/posts/c++%E7%9A%84%E4%B8%89%E7%A7%8D%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90%E4%BF%AE%E9%A5%B0%E7%AC%A6/</guid><description>&lt;h2 id="成员访问的三种权限"&gt;成员访问的三种权限&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官：&lt;/strong&gt; 在 C++ 的类（&lt;code&gt;class&lt;/code&gt;）定义中，我们有 &lt;code&gt;public&lt;/code&gt;, &lt;code&gt;protected&lt;/code&gt;, 和 &lt;code&gt;private&lt;/code&gt; 这三个关键字来控制成员的访问权限。&lt;/p&gt;
&lt;p&gt;你能简单解释一下，这三种权限分别意味着什么吗？也就是说，什么样的代码可以访问被它们修饰的成员？&lt;/p&gt;
&lt;p&gt;回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;public&lt;/code&gt; 修饰的成员，可以被该类的对象、该类的子类成员，以及该类的其他成员访问。（最宽松）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;private&lt;/code&gt; 修饰的成员，只能被该类的其他成员访问，而不能被对象和子类成员访问。（最严格）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;protected&lt;/code&gt; 修饰的成员，可以被该类的其他成员和子类的成员访问，但不能被该类的对象访问。（介于 &lt;code&gt;public&lt;/code&gt; 和 &lt;code&gt;private&lt;/code&gt; 之间）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Gemini 更好的概括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;public&lt;/code&gt;&lt;/strong&gt;: 类内、子类、类外（通过对象）都能访问。权限最开放。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;private&lt;/code&gt;&lt;/strong&gt;: 仅限类内访问。权限最严格，实现了完全的封装。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;protected&lt;/code&gt;&lt;/strong&gt;: 类内、子类可以访问，但类外不行。权限介于两者之间，专门为继承体系设计。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="类继承的三种权限"&gt;类继承的三种权限&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官 (深入提问):&lt;/strong&gt; 好的，你对成员访问权限很清楚。现在我们把这个概念和&lt;strong&gt;继承&lt;/strong&gt;结合起来。&lt;/p&gt;
&lt;p&gt;C++ 中，继承也有三种方式：&lt;code&gt;public&lt;/code&gt; 继承、&lt;code&gt;protected&lt;/code&gt; 继承和 &lt;code&gt;private&lt;/code&gt; 继承。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;public_member&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;protected&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;protected_member&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;private_member&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Derived_Public&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Derived_Protected&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Derived_Private&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;请问，这三种不同的继承方式，会如何影响&lt;strong&gt;基类 (&lt;code&gt;Base&lt;/code&gt;) 的成员&lt;/strong&gt;在&lt;strong&gt;派生类 (&lt;code&gt;Derived&lt;/code&gt;) 中&lt;/strong&gt;的访问权限？&lt;/p&gt;</description></item><item><title>explicit关键字</title><link>https://Mist2233.github.io/posts/explicit%E5%85%B3%E9%94%AE%E5%AD%97/</link><pubDate>Sat, 12 Jul 2025 10:35:00 +0000</pubDate><guid>https://Mist2233.github.io/posts/explicit%E5%85%B3%E9%94%AE%E5%AD%97/</guid><description>&lt;p&gt;好的，我们来深入解析 &lt;code&gt;explicit&lt;/code&gt; 这个虽小但非常重要的关键字。&lt;/p&gt;
&lt;p&gt;你的理解完全正确！&lt;code&gt;explicit&lt;/code&gt; 关键字就像一个“门卫”，它守在你的构造函数门口，防止一些“不请自来”的隐式类型转换，从而让代码的行为更加清晰、可控。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="一问题根源什么是构造函数的隐式转换"&gt;一、问题根源：什么是构造函数的“隐式转换”？&lt;/h3&gt;
&lt;p&gt;在 C++ 中，编译器有时候会“自作主张”地帮你进行类型转换，让代码能够通过编译。如果一个类的&lt;strong&gt;构造函数可以只用一个参数来调用&lt;/strong&gt;，那么这个构造函数就可能被编译器用来进行&lt;strong&gt;隐式转换 (Implicit Conversion)&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;让我们来看一个没有 &lt;code&gt;explicit&lt;/code&gt; 的“事故现场”：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景设定&lt;/strong&gt;：我们有一个字符串类 &lt;code&gt;MyString&lt;/code&gt;，它有一个构造函数，可以接受一个整数 &lt;code&gt;n&lt;/code&gt; 来创建一个由 &lt;code&gt;n&lt;/code&gt; 个 &lt;code&gt;'A'&lt;/code&gt; 组成的字符串。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyString&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;m_str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 这个构造函数可以用一个 int 参数来调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;m_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;MyString(&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;) 被调用了！&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m_str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 这是一个希望接收 MyString 对象的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;printString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MyString&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;打印: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;现在，在 &lt;code&gt;main&lt;/code&gt; 函数中，我们可能会写出这样的代码：&lt;/p&gt;</description></item></channel></rss>