命名空间、缺省函数、函数重载和引用

命名空间

在这里插入图片描述

  1. 基础概念

    1. 为什么需要命名空间?

      写代码时定义的变量名可能跟库中的变量名冲突等导致无法编译

​ 2.命名空间的核心作用是什么?
​ 隔离不同作用域中的标识符(变量、函数、类等),解决命名冲突问题(例如避免自定义函数与标准库函数同名冲突)。

​ 3.定义命名空间的语法格式是什么?
namespace 命名空间名称 { // 标识符的声明或定义(变量、函数、类等) }
​ 例: namespace MySpace { int add(int a, int b) { return a + b; } }

  1. 使用方式

    :: 域作用限定符

访问命名空间中标识符的4种方式是什么?请举例说明。

  • 直接指明访问: MySpace::add(1, 2); (最安全,无歧义)

  • using展开

    • using声明: using MySpace::add; add(1, 2); (仅引入指定标识符)
    • using指令: using namespace MySpace; add(1, 2); (引入整个命名空间,简洁但可能冲突)
  • 无名命名空间: namespace { int x = 10; } (仅当前文件可见,等价于static全局变量)

using声明和using指令的区别是什么?

  • using声明:仅引入命名空间中单个指定标识符,冲突风险低;
  • using指令:引入命名空间中所有标识符,简洁但冲突风险高(例如同时引入两个命名空间的同名函数)。
  1. 特性与细节

    命名空间只能定义在全局,因为在局部内无需进行隔离

命名空间是否支持嵌套?如何访问嵌套命名空间中的标识符?
支持嵌套;访问时需逐层指定命名空间,例:

namespace A {
    namespace B {
        int num = 100;
    }
}
// 访问方式:A::B::num
cout << A::B::num << endl;

同一命名空间能否拆分到多个文件中?有什么注意事项?
可以;注意事项:多个文件中需使用相同的命名空间名称,且在使用前需声明命名空间(通常在头文件中声明,源文件中定义)。多文件同一命名空间到最后会自动合并。

如何给命名空间起别名?语法是什么?
使用 namespace 别名 = 原命名空间名 ;例:
namespace MS = MySpace; MS::add(1, 2); (适用于命名空间名称较长的场景)

  1. 标准库与实战

std命名空间的作用是什么?为什么不建议在头文件中使用using namespace std;

  • 作用:std是C++标准库的统一命名空间,包含cout、cin、vector等所有标准库组件;
  • 不建议在头文件中使用的原因:头文件会被多个源文件包含,使用using指令会导致std的所有标识符暴露在全局作用域,引发命名冲突。

以下代码是否存在问题?如何修改?


#include <iostream>
using namespace std;

int cout = 10; // 错误:与std::cout命名冲突

int main() {
    cout << "Hello" << endl; // 歧义:无法区分是全局变量cout还是std::cout
    return 0;}

​ 方案1:删除全局变量 int cout = 10; (避免与标准库标识符同名);

  • 方案2:不使用using指令,直接使用 std::cout
#include <iostream>
int cout = 10;
int main() {
    std::cout << "Hello" << std::endl; // 明确指定std命名空间
    return 0;
}

  1. 函数局部域 只在函数内部有效,出了域就会销毁(影响生命周期)
  2. 全局域 只在全局有效,出了域就会销毁(影响生命周期)
  3. 命名空间域 不影响生命周期
  4. 类域 不影响生命周期

编译时变量的搜索顺序:先在局部内找,找不到就会在全局找。在未指明的情况下不会访问命名空间和类内。(:: 左边为空默认是访问全局的)


缺省参数

  1. 为什么需要缺省参数?
    在声明或定义函数时,为一个或多个参数指定一个默认值。在调用时没有指定实参,默认调用缺省的默认值。

  2. 全缺省
    函数的所有参数都提供了默认值。

    // 声明
    
    void printInfo(std::string name = "Unknown", int age = 0, std::string gender = "Not specified");
    
    // 调用方式
    
     printInfo();                  // 所有参数都使用默认值
    
    printInfo("Alice");           // 只提供第一个参数,后两个用默认值
    
    printInfo("Bob", 25);         // 提供前两个参数,最后一个用默认值
    
    printInfo("Charlie", 30, "Male"); // 提供所有参数
    
  3. 半缺省
    函数的部分参数提供了默认值。

  4. 注意点

    1. 指定顺序
      半缺省参数必须从右向左连续指定。你不能跳过一个参数不给默认值,而给它右边的参数指定默认值。

    2. 不可重复指定

      在同一个作用域内,一个参数只能被指定一次默认值。这就是为什么声明和定义不能同时指定的原因。

    3. 默认值必须是编译期常量表达式
      默认参数的值必须是在编译时就能确定的常量表达式(Literal、const 变量、constexpr 变量或函数)。不能是一个普通的变量。

    4. 声明和定义分离时,只能在声明时给缺省。


    函数重载

    1. 函数重载是指在同一个作用域内,可以定义多个同名函数,但这些函数的参数列表必须不同。(同名不同参)
    2. 构成函数重载的条件
      1. 参数个数不同:例如 void func()void func(int a)
      2. 参数类型不同:例如 int add(int a, int b)double add(double a, double b)
      3. 参数顺序不同(当参数类型不同时):例如 void func(int a, double b)void func(double a, int b)
      4. 注意:返回值类型不同,不能构成函数重载
        • 例如,int func(int a)double func(int a) 不能构成重载。
        • 原因:编译器在解析函数调用时,只根据函数名和实参来匹配函数,不考虑返回值。调用 func(5) 时,编译器无法判断应该调用哪个版本

引用

  1. 定义:给变量取别名,取地址后都是一样的。

  2. 特性

  3. 必须初始化

    :定义引用时,必须立即将其绑定到一个已存在的变量上。

    • int& ref; // 错误!引用必须初始化。
  4. 不可改变指向

    :一旦引用被绑定到某个变量,它就不能再作为其他变量的别名。

    • int a = 10, b = 20;
    • int& ref = a;
    • ref = b; // 这不是让 ref 指向 b,而是将 b 的值赋给 ref 所指向的 a。执行后 a 的值变为 20。
  5. 不存在空引用:引用必须指向一个有效的对象或变量,不能像指针那样为 nullptr

  6. 普通引用和常引用(const 引用)有什么区别?常引用有什么特殊用途?

    普通引用和常引用的主要区别在于是否允许通过引用修改原始变量的值

    1. 普通引用 (Type&)

      • 可以通过引用读取和修改所指向变量的值。
      • 只能绑定到一个可修改的左值(如一个普通变量)。
      int x = 10;
      int& ref_x = x;
      ref_x = 100; // 正确,可以修改 x 的值。
      // int& ref_y = 20; // 错误!不能绑定到右值(临时变量)。
      
    2. 常引用 (const Type&)

      • “常” 修饰的是引用,意味着不能通过这个引用去修改它所指向的变量的值。
      • 它的指向依然不能改变。
      • 特殊用途:可以绑定到右值(如字面量、表达式结果等临时变量),并且可以延长该临时变量的生命周期,使其与引用的生命周期相同。这是非常重要和常用的特性。
      int y = 20;
      const int& ref_y = y;
      // ref_y = 200; // 错误!不能通过常引用修改 y 的值。
      
      // 常引用的关键用途:绑定右值
      const int& ref_z = 100; // 正确!常引用可以绑定到字面量(右值)。
      double d = 3.14;
      const int& ref_d = d;   // 正确!会创建一个临时的 int 变量(值为 3),ref_d 绑定这个临时变量。
      

      常引用在函数参数中非常有用,可以避免不必要的拷贝,同时又能保证函数内部不会修改传入的数据。

  7. 注意事项

    1. 返回引用时绝对不能返回函数内局部变量的引用。因为局部变量在函数调用结束后会被销毁,返回的引用会变成 “野引用”,访问它会导致未定义行为。可以返回全局变量、静态局部变量或类的成员变量的引用。
  8. 与指针的区别

特性引用 (Reference)指针 (Pointer)
定义与初始化必须在定义时初始化,绑定到一个变量。可以先定义,后赋值。可以为 nullptr
指向的可变性一旦绑定,不能再指向其他变量。可以随时改变指向,指向其他同类型变量。
空值不存在空引用。存在空指针 (nullptr)。
内存开销不占用额外内存(编译器内部可能用指针实现,但语法上没有)。本身需要占用内存(存储一个地址)。
语法使用时无需解引用 (*),像使用普通变量一样。使用时需要解引用 (*) 来访问目标值。
安全性更高,没有空引用和野引用的风险(只要正确使用)。较低,存在空指针、野指针和内存泄漏的风险。

因此,引用和指针都是无法替代的。

针实现,但语法上没有)。 | 本身需要占用内存(存储一个地址)。 |
| 语法 | 使用时无需解引用 (*),像使用普通变量一样。 | 使用时需要解引用 (*) 来访问目标值。 |
| 安全性 | 更高,没有空引用和野引用的风险(只要正确使用)。 | 较低,存在空指针、野指针和内存泄漏的风险。 |

因此,引用和指针都是无法替代的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值