第 18.3 節

using

0瀏覽次數0訪問次數--跳出率--平均停留

本節解決什麼問題

C 語言中,用 typedef 給類型起別名。但 typedef 的語法很彆扭,特別是給函數指針、模板起別名時,寫法不直觀、難讀。

C++11 引入了 using 別名聲明,語法更清晰,還支持模板別名typedef 做不到)。

這個特性是什麼

using 有兩種常見用途:

  1. 類型別名:給已有類型起新名字,類似 typedef 但語法更清晰。
  2. 模板別名:給模板類型起別名(typedef 做不到這一點)。

C++ 標準版本

C++11(類型別名語法),C++11 模板別名。

需要的頭文件

不需要額外頭文件。using 是語言關鍵字。

基本語法

// 类型别名
using 新名字 = 已有类型;

// 模板别名
template<typename T>
using 新名字 = 模板类型<T...>;

與 typedef 的對比

場景typedefusing
基本類型typedef int Integer;using Integer = int;
函數指針typedef void (*Func)(int);using Func = void(*)(int);
數組typedef int Arr10[10];using Arr10 = int[10];
模板別名❌ 不支持using Vec<T> = std::vector<T>;

using 能做什麼,不能做什麼

using 創建的是別名,不是新類型。它能讓複雜類型更好讀,但不能阻止你把兩個底層相同的類型混用。

需求using 是否適合說明
縮短複雜類型名✅ 適合using Callback = std::function<void(int)>;
統一項目裡的業務名稱✅ 適合using UserId = int; 讓代碼更有語義
定義模板的簡化寫法✅ 很適合template<typename T> using Vec = std::vector<T>;
防止不同業務類型互相傳錯❌ 不夠using Meter = double;using Second = double; 本質仍都是 double
創建真正的新類型struct / class / enum class編譯器才能幫你檢查混用

示例代碼

示例 1:using 基礎——替換 typedef

#include <iostream>
#include <string>
#include <vector>

// 旧写法(typedef)
typedef std::vector<int> IntVector1;

// 新写法(using)
using IntVector2 = std::vector<int>;

int main()
{
    // 两种写法效果完全一样
    IntVector1 v1 = {1, 2, 3};
    IntVector2 v2 = {4, 5, 6};

    std::cout << "v1: ";
    for (int n : v1) std::cout << n << " ";
    std::cout << "\n";

    std::cout << "v2: ";
    for (int n : v2) std::cout << n << " ";
    std::cout << "\n";

    return 0;
}

運行結果

v1: 1 2 3 
v2: 4 5 6 

示例 2:在示例 1 基礎上,using 給函數指針起別名

#include <iostream>

// typedef 的函数指针写法(别扭)
typedef int (*FuncPtr1)(int, int);

// using 的函数指针写法(直观)
using FuncPtr2 = int (*)(int, int);

int add(int a, int b)
{
    return a + b;
}

int multiply(int a, int b)
{
    return a * b;
}

int main()
{
    FuncPtr2 op1 = add;
    FuncPtr2 op2 = multiply;

    std::cout << "add(3, 5) = " << op1(3, 5) << "\n";
    std::cout << "multiply(3, 5) = " << op2(3, 5) << "\n";

    return 0;
}

運行結果

add(3, 5) = 8
multiply(3, 5) = 15

示例 3:在示例 2 基礎上,模板別名(typedef 做不到)

#include <iostream>
#include <vector>
#include <map>
#include <string>

// 模板别名:定义一个泛型的 vector
template<typename T>
using Vec = std::vector<T>;

// 模板别名:键为 string 的 map
template<typename T>
using StringMap = std::map<std::string, T>;

int main()
{
    Vec<int> vi = {1, 2, 3};
    Vec<double> vd = {1.1, 2.2, 3.3};
    StringMap<int> scores = {{"Alice", 85}, {"Bob", 92}};

    std::cout << "Vec<int>: ";
    for (int n : vi) std::cout << n << " ";
    std::cout << "\n";

    std::cout << "Vec<double>: ";
    for (double d : vd) std::cout << d << " ";
    std::cout << "\n";

    std::cout << "StringMap<int>: ";
    for (const auto& p : scores)
        std::cout << p.first << ":" << p.second << " ";
    std::cout << "\n";

    return 0;
}

運行結果

Vec<int>: 1 2 3 
Vec<double>: 1.1 2.2 3.3 
StringMap<int>: Alice:85 Bob:92 

示例 4:在示例 3 基礎上,using 別名不是新類型

#include <iomanip>
#include <iostream>

using Meter = double;
using Second = double;

double speed(Meter distance, Second time)
{
    return distance / time;
}

struct MeterValue
{
    double value;
};

struct SecondValue
{
    double value;
};

double safe_speed(MeterValue distance, SecondValue time)
{
    return distance.value / time.value;
}

int main()
{
    Meter distance = 100.0;
    Second time = 9.58;

    std::cout << std::fixed << std::setprecision(2);
    std::cout << "speed = " << speed(distance, time) << "\n";

    // using 只是别名,下面这行语义错了,但编译器仍然允许
    std::cout << "wrong order = " << speed(time, distance) << "\n";

    MeterValue d{100.0};
    SecondValue t{9.58};
    std::cout << "safe speed = " << safe_speed(d, t) << "\n";

    // safe_speed(t, d); // ❌ 编译错误:SecondValue 不能当 MeterValue 用

    return 0;
}

運行結果

speed = 10.44
wrong order = 0.10
safe speed = 10.44

運行結果

見上方每個示例的"運行結果"。

示例中的關鍵語法解釋

示例講了什麼新出現的語法為什麼這樣寫注意事項
示例 1基礎類型別名using Name = Type;語法更直觀,= 讓人一眼看出"別名 = 原類型"typedef 也能做,但 using 更清晰
示例 2函數指針別名using Func = int(*)(int,int);名字在中間,比 typedef 的名字夾在中間更好讀實際項目中建議用 std::function 代替裸函數指針
示例 3模板別名template<T> using Vec = vector<T>;typedef 做不到模板別名,這是 using 的獨特能力非常適合簡化嵌套模板類型
示例 4using 不是新類型using Meter = double、包裝結構體別名提升可讀性,結構體提供類型安全需要防止參數傳反時,不要只靠 using

常見錯誤

錯誤 1:把 using 別名的 = 方向寫反

using int = MyInt;  // ❌ 方向反了!应该是 using 别名 = 原类型

正確做法:using MyInt = int;

錯誤 2:在頭文件中不加限制地使用 using

// 头文件中
using namespace std;  // ❌ 污染全局/外部命名空间!

正確做法:頭文件中避免 using namespace,只在 .cpp 的實現文件或函數內部使用。

錯誤 3:using 聲明和 using 別名混淆

using std::cout;       // using 声明:引入名字
using MyVec = std::vector<int>;  // using 别名:创建别名

這是兩種不同的用法,前者是引入名字到當前作用域,後者是創建類型別名。

錯誤 4:以為 using 能提供強類型檢查

using UserId = int;
using ProductId = int;

void load_user(UserId id);

ProductId pid = 10;
load_user(pid);  // 能编译,因为 UserId 和 ProductId 本质都是 int

正確做法:如果必須防止混用,用 struct UserId { int value; }; 這種包裝類型,或者用 enum class 表達有限集合。

使用建議

  1. using 代替 typedef:語法更清晰,還支持模板別名。
  2. 善用模板別名簡化代碼:例如 using TaskMap = std::map<int, std::function<void()>>;
  3. 不要在頭文件中 using namespace:避免命名空間汙染。
  4. using 聲明(using std::cout)可以用在 .cpp 或函數內部,簡化代碼。
  5. 需要強類型時不要只用 using:using 改善可讀性,struct/class/enum class 才能改變類型本身。

小結

  • using NewName = OldType;typedef 語法更直觀。
  • template<typename T> using Alias = ...; 是 typedef 做不到的模板別名。
  • 函數指針別名、容器類型別名在項目中很實用。
  • using 只是別名,不是新類型;需要類型安全時要引入包裝類型。
  • 別混淆 using 別名和 using 聲明(命名空間引入)。
音乐页