C++笔记1:命名空间,缺省参数,引用等

目录

命名空间:

缺省参数:

全缺省:

半缺省:

函数重载:

引用:

指针和引用的关系:

inline:

建议定义也放在头文件中:


命名空间:

假设在一个头文件LibA中定义了一个全局变量log

然后在另一个头文件LibB中也定义了一个全局变量log

当我们包含这两个头文件并且开始使用这个全局变量时,编译就会出错:

cpp 复制代码
// LibA 的定义(可能是某个头文件)
int log = 1;  // LibA 的日志级别

// LibB 的定义(可能是另一个头文件)
int log = 2;  // LibB 的日志级别

int main() {
    std::cout << log;  // 编译错误:'log' 重复定义
    return 0;
}

这个时候我们使用命名空间,在LibA文件中定义一个命名空间LibA,在LibB中定义一个命名空间LibB,并且在命名空间中来定义这个全局变量,这时我们就可以在主函数中指定命名空间来访问不同文件中的全局变量log。

cpp 复制代码
// LibA 的命名空间
namespace LibA {
    int log = 1;  // LibA::log
}

// LibB 的命名空间
namespace LibB {
    int log = 2;  // LibB::log
}

int main() {
    std::cout << LibA::log << "\n";  // 输出 1
    std::cout << LibB::log << "\n";  // 输出 2
    return 0;
}

此时命名空间就解决了全局变量命名冲突的问题。

命名空间的使用:

假设一个命名空间Utils

cpp 复制代码
namespace Utils {
    int version = 3;
    void print() { std::cout << "Utils version: " << version << "\n"; }
    void log(const std::string& msg) { std::cout << "[LOG] " << msg << "\n"; }
}

1、指定命名空间访问:

空间名::成员变量/函数名。

cpp 复制代码
int main() {
    std::cout << Utils::version << "\n";  // 输出 3
    Utils::print();                       // 调用 Utils::print()
    Utils::log("Hello");                  // 调用 Utils::log()
    return 0;
}

2、展开某个成员变量或者函数:

使用using关键字,指定哪个成员变量/函数,就展开哪个。

cpp 复制代码
int main() {
    using Utils::version;  // 只引入 version
    using Utils::log;      // 只引入 log

    std::cout << version << "\n";  // 直接使用 version
    log("Hello");                  // 直接调用 log()
    // print();                    // 错误!未引入 print()
    return 0;
}

3、展开整个命名空间:

使用using关键字,指定哪个命名空间就展开哪个。

cpp 复制代码
int main() {
    using namespace Utils;  // 引入整个 Utils

    std::cout << version << "\n";  // 直接使用 version
    print();                       // 直接调用 print()
    log("Hello");                  // 直接调用 log()
    return 0;
}

展开命名空间,实际上是编译器在查找变量、函数、类型、的时候,不仅会和原来一样,从局部域中找,从全局域中找,还会额外从展开了的命名空间去找,如果此时展开的命名空间中定义的变量名和某个全局变量产生了冲突,编译器还是会报错。

所以展开整个命名空间的操作是有风险的,只不过为了方便,写小练习的时候会使用。

缺省参数:

全缺省:

cpp 复制代码
#include <iostream>
using namespace std;

// 全缺省函数:所有参数都有默认值
void printInfo(string name = "Unknown", int age = 0, string country = "Earth") {
    cout << "Name: " << name << ", Age: " << age << ", Country: " << country << endl;
}

int main() {
    printInfo();                     // 输出: Name: Unknown, Age: 0, Country: Earth
    printInfo("Alice");              // 输出: Name: Alice, Age: 0, Country: Earth
    printInfo("Bob", 25);            // 输出: Name: Bob, Age: 25, Country: Earth
    printInfo("Charlie", 30, "Mars");// 输出: Name: Charlie, Age: 30, Country: Mars
    return 0;
}

半缺省:

半缺省参数,必须从右到左连续的给缺省值。

cpp 复制代码
#include <iostream>
using namespace std;

// 半缺省函数:部分参数有默认值(必须从右往左连续缺省)
void connectDatabase(string ip, int port = 3306, string user = "root") {
    cout << "Connecting to: " << ip << ":" << port << " as " << user << endl;
}

int main() {
    // connectDatabase();             // 错误!ip 无默认值,必须传参
    connectDatabase("127.0.0.1");                  // 输出: Connecting to: 127.0.0.1:3306 as root
    connectDatabase("192.168.1.1", 5432);          // 输出: Connecting to: 192.168.1.1:5432 as root
    connectDatabase("10.0.0.1", 8080, "admin");    // 输出: Connecting to: 10.0.0.1:8080 as admin
    return 0;
}

1、调用有缺省值的函数时,必须从左到右连续的给实参

cpp 复制代码
void connect(string ip, int port = 3306, string user = "root") {
    cout << "IP: " << ip << ", Port: " << port << ", User: " << user << endl;
}
//正确调用方式
connect("127.0.0.1");              // 只传 ip,port 和 user 用默认值
connect("192.168.1.1", 5432);      // 传 ip 和 port,user 用默认值
connect("10.0.0.1", 8080, "admin");// 传所有参数
//错误调用方式
connect();                         // 错误!ip 必须传参
connect("localhost", , "guest");   // 错误!不能跳过 port 直接传 user

2、缺省参数不能在函数的声明和定义中同时出现,这是为了避免声明和定义中缺省值不同的情况。

cpp 复制代码
// 声明(通常在头文件 .h 中)
void printInfo(string name = "Unknown", int age = 0);

// 定义(在 .cpp 文件中)
void printInfo(string name, int age) {
    cout << "Name: " << name << ", Age: " << age << endl;
}
printInfo();          //  输出: Name: Unknown, Age: 0
printInfo("Alice");   //  输出: Name: Alice, Age: 0
printInfo("Bob", 25); //  输出: Name: Bob, Age: 25

函数重载:

c++允许同一作用域中出现同名函数,只不过这些同名函数参数不同,这样才能在调用函数时区分调用的是哪个函数。

引用:

引用就是给对象起一个别名,使用方法是:类型 & 别名

引用必须初始化:

cpp 复制代码
int main() {
    int x = 10;
    int &ref; // ❌ 错误!引用必须初始化
    int &ref = x; // ✅ 正确:ref 是 x 的别名
    return 0;
}

引用定义后就无法改变指向对象:

cpp 复制代码
int main() {
    int x = 10;
    int y = 20;
    int &ref = x; // ref 绑定到 x
    ref = y;     // ❌ 不是改变绑定,而是把 y 的值赋给 x!
    
    std::cout << x; // 输出 20(x 的值被修改)
    std::cout << ref; // 输出 20(ref 仍然是 x 的别名)
    return 0;
}

由于引用必须初始化,所以不存在指向空值的引用

下面行为是未定义的:

cpp 复制代码
//空引用
int* ptr = NULL;
int& rb = *ptr;
rb++;

由于引用底层使用的是指针,所以"引用传值,指针传地址"这句话是错的。

指针和引用的关系:

1、从概念上讲,引用就是给一个变量取一个别名,不会新开一个空间,而指针则是取出一个变量的地址。

2、引用在定义时必须初始化,而指针不必须

3、引用无法改变引用的对象,而指针可以改变指向的对象,这也是引用无法替代指针的点。

4、引用可以直接访问指向的对象,而指针需要先解引用。

5、sizeof(别名)、sizeof(指针)的值不同,引用的sizeof代表指向对象的大小,而指针永远表示地址空间所占字节数。

6、由于引用必须初始化,所以使用起来比指针安全一些。

inline:

当一个函数的代码量很少,但是调用的却很频繁时,为了减少函数栈帧创建带来的时间开销,采取空间换时间的方式,直接在调用的地方展开函数,而不是为它创建栈帧。

cpp 复制代码
// 在声明和定义处都加 inline(推荐)
inline int add(int a, int b) {
    return a + b;
}

// 调用时和普通函数一样
int result = add(3, 5);  // 可能被展开为:int result = 3 + 5;

inline对于编译器而言只是一个建议,当函数代码量过大或者是递归层次过深,这个建议就会被忽略。

C语言中的宏函数也是为了解决小函数调用栈帧开销过大的问题,但是实现起来过于繁琐和复杂。

inline的声明和定义不能放在不同文件中:

cpp 复制代码
// 错误示例:分离声明和定义
// math.h
inline int add(int a, int b); // 只有声明

// math.cpp
inline int add(int a, int b) { return a + b; } // 定义在另一个文件

// main.cpp
#include "math.h"
int main() {
    int r = add(2, 3); // 链接错误:找不到定义
    return 0;
}

建议定义也放在头文件中:

cpp 复制代码
// math.h
inline int add(int a, int b) { // 声明和定义在一起
    return a + b;
}

// main.cpp
#include "math.h"
int main() {
    int r = add(2, 3); // 正确:编译器看到定义后可以内联
    return 0;
}
相关推荐
玩代码5 小时前
备忘录设计模式
java·开发语言·设计模式·备忘录设计模式
岁忧6 小时前
(nice!!!)(LeetCode 面试经典 150 题 ) 30. 串联所有单词的子串 (哈希表+字符串+滑动窗口)
java·c++·leetcode·面试·go·散列表
技术猿188702783516 小时前
实现“micro 关键字搜索全覆盖商品”并通过 API 接口提供实时数据(一个方法)
开发语言·网络·python·深度学习·测试工具
放飞自我的Coder6 小时前
【colab 使用uv创建一个新的python版本运行】
开发语言·python·uv
SunkingYang6 小时前
MFC/C++语言怎么比较CString类型最后一个字符
c++·mfc·cstring·子串·最后一个字符·比较
界面开发小八哥6 小时前
MFC扩展库BCGControlBar Pro v36.2新版亮点:可视化设计器升级
c++·mfc·bcg·界面控件·ui开发
R-G-B6 小时前
【15】MFC入门到精通——MFC弹窗提示 MFC关闭对话框 弹窗提示 MFC按键触发 弹窗提示
c++·mfc·mfc弹窗提示·mfc关闭弹窗提示·mfc按键触发 弹窗提示
艾莉丝努力练剑6 小时前
【数据结构与算法】数据结构初阶:详解顺序表和链表(四)——单链表(下)
c语言·开发语言·数据结构·学习·算法·链表
zyhomepage7 小时前
科技的成就(六十九)
开发语言·网络·人工智能·科技·内容运营
十秒耿直拆包选手7 小时前
Qt:QCustomPlot类介绍
c++·qt·qcustomplot