卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
大模型
  • Java面经
  • C++面经
  • 大模型面经
简历专栏
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
大模型
  • Java面经
  • C++面经
  • 大模型面经
简历专栏
代码随想录 (opens new window)
  • 基础与语法

    • 介绍c++一下三大特性
    • 指针和引用的区别
    • 结构体和类的区别
    • 结构体与联合体的区别
    • static关键字和const关键字的作用
      • 详细回答
      • 💻 Part 03 · 代码示例
      • 🎯 Part 04 · 内容拓展 · 面试追问
    • extern C的作用
    • volatile关键字的作用
    • inline函数与宏的区别与优劣
    • auto和decltype的区别
    • sizeof和strlen的区别
    • 浮点数比较方法
    • 静态局部变量,全局变量,局部变量的特点,以及使用场景
    • C++中四种类型转换
  • 面向对象

  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

  • 智能指针

  • 并发与 I/O

# C++ 面试题:static 关键字与 const 关键字的作用


##简要回答

static —— 控制生命周期和可见性。 它让局部变量在函数调用之间持久存在,让全局变量/函数的作用域限制在当前文件,让类成员被所有对象共享而非各自持有。核心思想:"存储不随栈帧消亡,名字不向外部暴露"。

const —— 承诺"不修改"。 它把变量标记为只读,把指针/引用标记为不可通过它来修改所指对象,把成员函数标记为不会修改对象状态。核心思想:"编译器帮你守住承诺,一旦违背立刻报错"。


# 详细回答

# static 关键字详解

# 1. 局部静态变量

在函数内用 static 声明的变量,生命周期延长到整个程序运行期间,但作用域仍限于函数内部。它只在第一次执行到声明语句时初始化一次,后续调用保留上次的值。

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│ 程序启动  │ ──→ │ 首次调用  │ ──→ │ 后续调用  │ ──→ │ 程序结束  │
│ 分配静态  │     │ 执行初始化│     │ 保留上次  │     │ 析构释放  │
│ 存储区    │     │(仅一次) │     │ 的值      │     │          │
└──────────┘     └──────────┘     └──────────┘     └──────────┘
1
2
3
4
5

# 2. 全局静态变量 / 函数(文件作用域)

在文件作用域加 static,会限制该符号的链接属性为内部链接(internal linkage),即其他 .cpp 文件无法通过 extern 访问它——实现"文件级私有"。

# 3. 类的静态成员变量

属于类本身而非某个对象。所有对象共享同一份拷贝,存储在全局/静态区。必须在类外单独定义(C++17 起可用 inline static 类内定义)。

# 4. 类的静态成员函数

没有 this 指针,因此不能访问非静态成员。可直接通过 类名::函数名() 调用,常用于工厂方法和单例模式。


# const 关键字详解

# 1. 修饰普通变量

变量被标记为只读,编译器会阻止任何对它的赋值操作。const int x = 10; 之后 x = 20; 会编译报错。

# 2. 修饰指针(顶层 vs 底层)

这是面试重灾区!口诀:const 在 * 左边修饰值,在 * 右边修饰指针。

┌─────────────────────┬──────────────────────────────────────┐
│ 写法                 │ 含义                                 │
├─────────────────────┼──────────────────────────────────────┤
│ const int* p        │ 底层 const → 指向的「值」不可改       │
│                     │             指针可以指向别处           │
├─────────────────────┼──────────────────────────────────────┤
│ int* const p        │ 顶层 const → 「指针」本身不可改       │
│                     │             指向的值可以修改           │
├─────────────────────┼──────────────────────────────────────┤
│ const int* const p  │ 双重 const → 值和指针「都不可改」     │
└─────────────────────┴──────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11

# 3. 修饰引用

const int& ref = x; 表示不能通过 ref 修改 x。常用于函数参数传递——既避免拷贝开销,又保证不会意外修改原对象。

# 4. 修饰成员函数

在成员函数签名末尾加 const,承诺该函数不修改对象的任何非 mutable 成员。const 对象只能调用 const 成员函数。


# 核心差异对比表

┌────────────────┬─────────────────────────┬─────────────────────────┐
│ 维度           │ static                  │ const                   │
├────────────────┼─────────────────────────┼─────────────────────────┤
│ 核心语义       │ 控制生命周期和可见性      │ 控制可修改性(只读)      │
├────────────────┼─────────────────────────┼─────────────────────────┤
│ 修饰局部变量   │ 延长生命周期至程序结束    │ 值不可更改               │
├────────────────┼─────────────────────────┼─────────────────────────┤
│ 修饰全局变量   │ 限制为文件内部链接        │ 默认内部链接(C++) + 只读 │
├────────────────┼─────────────────────────┼─────────────────────────┤
│ 修饰类成员变量 │ 所有对象共享一份          │ 必须在初始化列表中初始化  │
├────────────────┼─────────────────────────┼─────────────────────────┤
│ 修饰成员函数   │ 无 this 指针             │ 不修改成员               │
│                │ 可用类名直接调用          │ const 对象可调用         │
├────────────────┼─────────────────────────┼─────────────────────────┤
│ 能否同时使用   │          ✅ 可以!static const int X = 42;         │
└────────────────┴─────────────────────────┴─────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 📊 变量存储位置对比

  ┌─────────────────┐   ┌─────────────────┐   ┌─────────────────┐
  │   栈区 STACK     │   │ 全局/静态区 DATA │   │  只读区 RODATA   │
  ├─────────────────┤   ├─────────────────┤   ├─────────────────┤
  │ int x = 5;      │   │ static int cnt; │   │ "hello"         │
  │  → 普通局部变量  │   │  → 静态局部变量  │   │  → 字符串字面量  │
  │                 │   │                 │   │                 │
  │ const int y=10; │   │ static int g;   │   │ constexpr int N │
  │  → const局部变量 │   │  → 静态全局变量  │   │  → 编译期常量    │
  │                 │   │                 │   │                 │
  │                 │   │ Cls::s_val      │   │                 │
  │                 │   │  → 类静态成员    │   │                 │
  └─────────────────┘   └─────────────────┘   └─────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12

# 💻 Part 03 · 代码示例

# 示例一:static 关键字综合示例

#include <iostream>
using namespace std;

// ① 文件作用域的 static:仅本文件可见
static int filePrivate = 42;

// ② 类中的 static 成员
class Counter {
public:
    static int count;              // 声明(类内)
    Counter()  { ++count; }
    ~Counter() { --count; }

    // ④ 静态成员函数:无 this,不能访问非静态成员
    static int getCount() { return count; }
};

int Counter::count = 0;            // 定义(类外,必须!)

// ③ 局部 static 变量
void callMe() {
    static int times = 0;          // 仅初始化一次
    cout << "called " << ++times << " times\n";
}

int main() {
    callMe();   // called 1 times
    callMe();   // called 2 times
    callMe();   // called 3 times

    { Counter a, b, c; }          // 三个对象创建后立即析构
    cout << "alive: " << Counter::getCount() << "\n";

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

输出:

called 1 times
called 2 times
called 3 times
alive: 0
1
2
3
4

# 示例二:const 关键字综合示例

#include <iostream>
#include <string>
using namespace std;

class Student {
    string name_;
    mutable int accessCount_ = 0;  // mutable 允许在 const 函数中修改
public:
    Student(const string& n) : name_(n) {}

    // ④ const 成员函数:承诺不修改对象
    string getName() const {
        ++accessCount_;            // OK,mutable 允许
        return name_;
    }

    void setName(const string& n) { name_ = n; }
};

int main() {
    // ① const 变量
    const int MAX = 100;
    // MAX = 200;                  // ❌ 编译错误

    // ② const 与指针
    int a = 10, b = 20;

    const int* p1 = &a;           // 指向 const → 不能改值
    // *p1 = 30;                   // ❌ 编译错误
    p1 = &b;                       // ✅ 可以改指向

    int* const p2 = &a;           // const 指针 → 不能改指向
    *p2 = 30;                      // ✅ 可以改值
    // p2 = &b;                    // ❌ 编译错误

    // ③ const 对象
    const Student s("Alice");
    cout << s.getName();           // ✅ getName 是 const 函数
    // s.setName("Bob");           // ❌ const 对象不能调非 const 函数

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

💡 面试技巧: 回答 const 指针问题时,画一张表格比口述更清晰。面试官会非常欣赏你能快速画出 const int* vs int* const 的对比。


# 🎯 Part 04 · 内容拓展 · 面试追问

面试官经常会在基础问题后继续追问。以下是最常见的追问方向与参考回答:


# Q1:const 和 #define 有什么区别?

#define 是预处理阶段的文本替换,没有类型检查,不占内存,不受作用域限制,调试时看不到符号名。const 是编译阶段处理,有类型安全、有作用域、可以调试,并且编译器可能会做常量折叠优化。

结论:C++ 中应优先使用 const(或 constexpr)而非 #define。


# Q2:const 和 constexpr 有什么区别?

const 表示"运行时不可修改",初始值可以在运行时才确定。constexpr(C++11)更强,表示"编译期常量",值必须在编译时就能确定。例如 constexpr int N = 1 + 2; 编译时就算好了 3,可以用于数组大小、模板参数等。

const     → 运行时只读    → 值可以运行时确定
constexpr → 编译期常量    → 值必须编译时确定(更强的保证)
1
2

# Q3:static 局部变量是线程安全的吗?

C++11 标准保证:局部 static 变量的初始化是线程安全的("magic statics")。编译器会在底层加锁保证只有一个线程执行初始化。但初始化之后的读写操作并不是线程安全的,仍需手动加锁或使用原子操作。

这也是单例模式使用 static 局部变量实现(Meyer's Singleton)的理论基础:

class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance;   // C++11 保证线程安全初始化
        return instance;
    }
private:
    Singleton() = default;
};
1
2
3
4
5
6
7
8
9

# Q4:mutable 关键字的作用是什么?

mutable 允许一个成员变量即使在 const 成员函数中也可以被修改。典型场景:缓存计算结果、访问计数器、互斥锁(mutable std::mutex mtx_;)。它不破坏逻辑上的 const 语义——对象的"可观察状态"没有变化,只是内部实现细节改变了。


# Q5:能不能用 const_cast 去掉 const?有什么风险?

const_cast 可以移除或添加 const 限定。但如果原始对象本身就是 const 的(比如 const int x = 10;),去掉 const 后修改它是未定义行为(UB)。

合法场景:对象本身不是 const 的,但通过 const 引用/指针传递进来,确信可以安全修改时才使用。

面试建议:强调"尽量不用"。


# Q6:static 变量的初始化顺序有什么问题?

不同编译单元(.cpp 文件)中的全局/静态变量,初始化顺序是未定义的,称为 "Static Initialization Order Fiasco"。如果 A 文件的静态变量依赖 B 文件的静态变量,可能在 B 还没初始化时就被使用。

解决方案: 用函数内的局部 static 变量替代(Construct On First Use Idiom),保证首次访问时才初始化。

// ❌ 危险:初始化顺序不确定
// file_a.cpp
extern int b_val;
int a_val = b_val + 1;    // b_val 可能还没初始化!

// ✅ 安全:首次使用时才初始化
int& getA() {
    static int a_val = getB() + 1;
    return a_val;
}
1
2
3
4
5
6
7
8
9
10

# Q7:C 语言的 const 和 C++ 的 const 有什么不同?

C 中的 const 变量默认是外部链接的,不能用于数组大小(非 VLA 编译器),本质上是"只读变量"。C++ 中的 const 默认是内部链接的,编译器会尝试将其当作编译期常量处理,可以用于数组大小。所以 C++ 的 const 更接近"常量"的语义。

C   中的 const  →  只读变量(外部链接,不能做数组大小)
C++ 中的 const  →  编译期常量(内部链接,可做数组大小)
1
2

⚠️ 面试加分项: 如果你能自然地把 static 与单例模式、const 与 constexpr 联系起来,会显示出你对 C++ 有更深层的理解,而不仅仅是背诵概念。


C++ Interview Series · static & const · 祝面试顺利 🚀

Last Updated: 4/8/2026, 4:09:35 PM

← 结构体与联合体的区别 extern C的作用 →

评论

验证登录状态...

侧边栏
夜间
卡码简历
代码随想录
卡码投递表🔥
2026群
添加客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记
鼓励/支持/赞赏Carl
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪