【C++基础】Day 3:关键字之 define、typedef、using、引用&、inline 和 const

目录

学习日志|Day 3

一、#define vs typedef vs using vs 引用&

1. 简要回答

2. 详细解释

1)#define

2)typedef

3)C++11 using(现代 C++ 的首选方式)

4)typedef 与 引用(reference)

(1)引用

(2)typedef 是“类型别名”

(3)引用是“变量别名”

(3) 两者关系

3. 图表总结

4. 代码示例

5. 面试常问 & 易错点

6. 一句话总结

二、#define vs inline

1. 简要回答

2. 详细解释

1)#define(宏函数)

2)inline(内联函数)

3. 图表总结

4. 代码示例

5. 面试常问 & 易错点

1)为什么宏函数有危险?

2)inline 一定会被内联吗?

3)哪些情况下 inline 会失效?

4)为什么 inline 安全?

6. 一句话总结

三、#define vs const

1. 简要回答

2. 详细解释

1)#define(宏常量)

2)const(带类型常量)

3. 图表总结

4. 代码示例(含输出)

5. 面试常问 & 易错点

1)define 定义常量的最大问题?

2)const 一定会分配内存吗?

3)define 和 const 谁更推荐?

4)define 会进入符号表吗?

6. 一句话总结


学习日志|Day 3

第三篇文章主要梳理了以下关键字的高频考点:
define / typedef / using / 引用& / inline / const 

主要是对以下关键字进行对比总结:

define vs typedef vs using vs 引用 、define vs inline 、const vs define 


一、#define vs typedef vs using vs 引用&

1. 简要回答

  • #define预处理阶段的字符串替换,没类型、没作用域、没检查。

  • typedef(以及C++11的using给类型起别名,参与编译,有类型检查,更安全。


2. 详细解释

1)#define

  • #define 是预处理指令,在编译之前就已经把宏展开完了,编译器根本“看不到”宏本身,只看到展开后的结果。
  • 不参与类型系统 → 不做类型检查。
  • 宏只是文本替换 → 容易出错(比如少括号)。
  • 没有作用域的概念,只要宏未被 #undef,全文件有效

2)typedef

  • typedef 是在 类型系统里起别名
  • 只是给已有类型取一个新名字,本身不分配内存
  • 参与编译,有类型检查(写错类型编译器会报错)。
  • 遵守作用域规则:在块内/命名空间内定义则只在对应作用域内可见。

3)C++11 using(现代 C++ 的首选方式)

usingtypedef 的现代替代写法:

using TPINT = int*;

它比 typedef 更强大:

  • 语法更自然(左边是名字,右边是类型)

  • 可用于模板别名(typedef 做不到)

template<typename T>
using Vec = std::vector<T>;
  • 能给函数指针、STL类型别名写出更清晰的形式;

typedef void (*Func1)(int, double);
using    Func2 = void(*)(int, double);

推荐规则:

现代 C++ 中:能用 using 就不用 typedef

4)typedef 与 引用(reference)

很多人误以为 typedef 和引用都“起别名”,其实不对。

(1)引用
  • 给“变量”起别名,而不是给类型起别名(不是类型别名)

  • 必须立即绑定一个对象

  • 不能绑定 null

  • 不能更换绑定关系(不能重新指向其他对象)

  • 本质是 变量别名,不是类型别名

  • 运行期概念(和具体对象绑定)

(2)typedef 是“类型别名”
typedef int& Ref;
(3)引用是“变量别名”
int a = 10;
int& r = a; 

引用必须绑定到某个对象,且无法“重新绑定”。

(3) 两者关系

引用不等价 typedef 的一个关键证明

  • typedef 可以“给引用类型本身起别名”,但引用语义不因此改变。

  • typedef 不是引用机制

示例:

int a = 1, c = 2;

int& b = a; // b 绑定 a
b = c;      // 把 c 的值赋给 a,a 变成 2

如果引用是 typedef,应该能像下面这样改变“别名绑定对象”:

typedef int Alias;
Alias x = a;   // 是新变量,不是别名
x = c;         // 不影响 a

结论:

        typedef 只是类型别名,只在编译期起名字;                                                                            引用是对象别名,运行期必须绑定某个变量,两者完全不同,只是 typedef 恰好可以给引用类型起别名。

3. 图表总结

对比项#definetypedef / using(类型别名)引用(reference,变量别名)
本质预处理器文本替换类型别名(编译期)变量别名(运行期)
生效阶段预处理阶段编译阶段运行阶段
类型检查❌ 无✅ 有不涉及类型检查(绑定对象后就是对象本身)
是否有作用域❌ 无(只要未 #undef✅ 遵循 C++ 作用域规则取决于引用的作用域
是否分配内存❌ 不分配❌ 不分配(只是类型别名)❌ 无额外内存(通常优化为同一对象)
是否绑定具体对象❌ 不绑定❌ 不绑定✅ 必须立即绑定且不可重新绑定
是否可重新绑定--❌ 不能修改引用的绑定关系
可处理复杂类型❌ 容易出问题⭐ 非常适合(特别是函数指针、模板容器)❌ 不适合(不是类型别名)
模板别名❌ 不支持⭐ using 完全支持❌ 不相关
是否能给引用起别名❌ 不能✅ 可以 typedef int& R❌ 引用不是“类型别名”,不能互换
推荐程度(现代 C++)❌ 不推荐用于类型✔ typedef 可用 / ⭐ using 最推荐引用不参与类型定义,是另一类机制
使用场景核心定位字符串替换、常量宏类型别名(复杂类型重命名)变量别名(指向具体对象)

4. 代码示例

#include <iostream>
using namespace std;

// 宏定义“指针类型”
#define PINT int*

// typedef 定义指针类型别名
typedef int* TPINT;

// using 定义指针类型别名(现代C++推荐)
using UPINT = int*;

// typedef 给引用类型起别名(注意语义)
typedef int& RefInt;

int main() {
    // 宏展开后:int* a, b;   → a是指针,b是普通int!
    PINT a, b;   

    TPINT c, d;  // c、d 都是 int* 指针
    UPINT e, f;  // e、f 也都是 int*,using 效果最好

    int x = 10, y = 20;
    a = &x;
    // b = &y;         // 编译错误(b不是指针)
    c = &x;
    d = &y;

    // 使用 typedef 定义的引用类型
    RefInt r = x;  // r 是 x 的引用
    r = y;         // r = y 表示 x = y,而不是 r 绑定到 y!

    cout << *a << " " << *c << " " << *d << endl;
    cout << "x = " << x << ", y = " << y << ", r = " << r << endl;

    return 0;
}
10 10 20
x=20 y=20 r=20

5. 面试常问 & 易错点

  1. Q:typedef 会分配内存吗?
     A:不会,它只是给类型起一个别名。

  2. Q:用宏定义函数和 typedef 定义函数指针的区别?
     A:宏函数是纯文本替换,无类型检查;函数指针是完整的类型,调用时会做类型检查。

  3. Q:实际开发中推荐用哪个来做“类型别名”?
     A:肯定是 typedef(C++11 以后更推荐 using =)。宏只用于少量简单场景。

  4. Q:typedef 与 define 的区别?   
     A:类型系统 vs 文本替换。

  5. Q:typedef 与 using 的区别?
     A:using 支持模板,是现代 C++ 推荐写法。

  6. Q:typedef 与引用是什么关系?
     A:typedef 可以给“引用类型”起别名,但引用是变量别名,两者完全不同。

define 是“替换”,typedef 是“类型”,using 是“现代类型”,引用是“对象别名”。


6. 一句话总结

#define 是预处理阶段的纯文本替换,没有任何类型检查,也没有作用域,全局生效,适合简单常量和宏;
typedef 是编译阶段参与类型系统的类型别名,会进行严格的类型检查,遵循作用域规则,更安全也更现代;
using 则是 C++11 引入的更强大的类型别名语法,语义清晰、支持模板,是现代 C++ 的首选写法;
而引用(reference)虽然看起来像“别名”,但它是运行期绑定的变量别名,不属于类型别名体系,不能重新绑定,与 typedef/using 的编译期类型别名本质完全不同。

总结一句话:define 是“替换”,typedef/using 是“类型”,引用是“对象”,各自语义和用途完全不同,能用类型别名绝不用宏。


二、#define vs inline

1. 简要回答

#define预处理阶段的纯文本宏替换,没有类型、没有作用域、没有检查;
inline编译阶段的内联函数,请求编译器将函数体展开,属于类型系统、语义安全、可调试。
宏只是“替换”,inline 是真正的“函数”。


2. 详细解释

1)#define(宏函数)

  • 纯文本替换,不属于 C++ 类型系统

  • 不做类型检查,参数可能被多次求值

  • 没有作用域,除非手动 #undef

  • 调试器看不到宏本身

  • 容易引发副作用,例如 SQR(a++) 导致 a++ 执行两次

典型示例:

#define SQR(x) ((x) * (x))

若调用:

SQR(a++);

实际展开为:

((a++) * (a++))

产生严重副作用。


2)inline(内联函数)

  • 仍然是真正的函数(有类型检查)

  • 编译器可选择是否内联(不是强制)

  • 避免函数调用开销(栈操作、跳转等)

  • 参数只求值一次(安全)

  • 作用域清晰(和普通函数一致)

  • 可在调试器中看到并单步调试

  • 若函数体过大/有循环/递归 → 编译器会拒绝 inline

示例:

inline int sqr(int x) {
    return x * x;
}

3. 图表总结

对比项#define(宏函数)inline(内联函数)
本质文本替换函数(参与类型系统)
类型检查❌ 无✅ 有
作用域❌ 无✅ 有
参数多次求值风险⭐ 高❌ 无
调试支持❌ 看不到宏⭐ 可正常调试
副作用风险
编译器优化权编译器可决定是否内联
推荐程度❌ 不推荐⭐ 强烈推荐

4. 代码示例

#include <iostream>
using namespace std;

#define SQR_MACRO(x) ((x) * (x))

inline int sqr_inline(int x) {
    return x * x;
}

int main() {
    int a = 3;

    int r1 = SQR_MACRO(a++);   // a++ 执行两次
    a = 3;
    int r2 = sqr_inline(a++);  // a++ 执行一次

    cout << "宏函数 r1=" << r1 << "  a=" << a << endl;
    cout << "inline r2=" << r2 << " a=" << a << endl;

    return 0;
}

输出:

宏函数 r1=12  a=5
inline r2=9 a=4
对比宏版本 SQR_MACRO(a++)inline 版本 sqr_inline(a++)
是否多次求值是(两次 a++)否(一次 a++)
执行序列3++ → 4++3++
a 最终值54
返回值3*4=123*3=9
是否安全❌ 不安全✔ 安全

5. 面试常问 & 易错点

1)为什么宏函数有危险?

因为会进行“多次求值”,例如 SQR(a++) 导致 a++ 执行两次。

2)inline 一定会被内联吗?

不会!只是“请求”,编译器可能拒绝。

3)哪些情况下 inline 会失效?

  • 函数体过大

  • 有循环、递归

  • 编译器优化策略决定不内联

4)为什么 inline 安全?

因为它仍然是普通函数,具有类型检查与单次参数求值。


6. 一句话总结

define 是预处理阶段的危险文本替换;

inline 是类型安全的函数内联请求,现代 C++ 中所有“宏函数”都应改写为 inline。


三、#define vs const


第二天已经详细介绍了 const 和之前关于 const 的具体内容,具体链接如下:

【C++基础】Day 2:关键字之 const 与 static-优快云博客https://blog.youkuaiyun.com/m0_58954356/article/details/155004996?spm=1001.2014.3001.5502


1. 简要回答

#define 定义的常量本质是“字符替换”,没有类型检查,也没有作用域,不安全;
const真正带类型的常量,有类型系统约束与作用域,能参与编译优化,是 C++ 中定义常量的正确方式。


2. 详细解释

1)#define(宏常量)

  • 本质是文本替换,不进入符号表

  • 不参与类型检查

  • 没有作用域(全文件有效)

  • 调试器看不到宏

  • 容易出错,如须加括号保护

#define PI 3.14

编译器实际看到的是 3.14,根本不知道“PI”这个标识符存在。


2)const(带类型常量)

  • 有明确类型,例如 const double PI = 3.14;

  • 在符号表中可见,可被调试

  • 遵循作用域(块级、命名空间、类内均可)

  • 可参与类型检查(重载解析更精准)

  • 可作为函数参数类型明确

  • 可参与优化(编译器可能将其当立即数)


3. 图表总结

对比项#define 常量const 常量
本质文本替换有类型的常量
生效阶段预处理编译期
是否类型检查❌ 无✅ 有
是否进入符号表❌ 不进入⭐ 可进入
是否有作用域❌ 无⭐ 遵循 C++ 作用域
是否可调试❌ 不可⭐ 可查看
安全性❌ 易出错⭐ 安全、可优化
推荐程度❌ 不推荐⭐ 强烈推荐

4. 代码示例(含输出)

#include <iostream>
using namespace std;

#define PI_MACRO 3.14
const double PI_CONST = 3.14;

void foo(double x) {
    cout << "foo: " << x << endl;
}

int main() {
    foo(PI_MACRO);  // 类型不明确(宏替换)
    foo(PI_CONST);  // 类型 double

    const int N = 3;
    int arr[N] = {1,2,3};
    cout << sizeof(arr)/sizeof(arr[0]) << endl;
}

输出:

foo: 3.14
foo: 3.14
3

5. 面试常问 & 易错点

1)define 定义常量的最大问题?

无类型,无作用域,调试困难,容易踩坑。

2)const 一定会分配内存吗?

不一定,编译器可能直接优化成立即数。

3)define 和 const 谁更推荐?

永远推荐 const(以及现代 C++ 的 constexpr)。

4)define 会进入符号表吗?

不会,因此调试器中看不到“PI”,只看到 3.14。


6. 一句话总结

define 是“替换”,const 是“类型化常量”;宏常量不安全,const 才是 C++ 中正确的常量写法。

基于共轭转移与噬菌体介导的 CRISPR 系统对抗耐药菌的建模研究(Matlab代码实现)内容概要:本文围绕&ldquo;基于共轭转移与噬菌体介导的CRISPR系统对抗耐药菌&rdquo;的生物医学工程建模研究展开,重点介绍了利用Matlab进行系统建模与仿真分析的技术路线。研究结合合成生物学与微生物基因编辑机制,构建了描述共轭转移、噬菌体感染及CRISPR-Cas系统靶向清除耐药菌的动力学模型,旨在通过数学建模手段揭示该复合系统的抗菌效率与稳定性特征。文中提供了完整的Matlab代码实现,便于复现进一步优化,体现了理论建模与实验设计之间的桥梁作用。; 适合人群:具备一定生物信息学、系统生物学或控制工程背景,熟悉Matlab编程,从事交叉学科科研工作的研究生、青年科研人员及生物工程领域开发者。; 使用场景及目标:①用于理解并模拟CRISPR系统在微生物群体中传播与调控的动态行为;②支持抗菌策略的设计与优化,特别是在应对多重耐药菌感染方面提供理论依据;③适用于科研教学、项目原型开发及学术论文复现。; 阅读建议:建议读者结合分子生物学基础知识与Matlab编程实践同步学习,重点关注模型假设的合理性、微分方程构建逻辑及参数敏感性分析部分,以便深入掌握建模思想并灵活迁移至其他生物系统仿真任务中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值