☰
深入理解C++ using的用法
2026/10/28 18:09:33 网站建设 项目流程

C++ 中using的完整用法详解

using在 C++ 里是个"多面手",从 C++98 到 C++20 被不断扩展。按用途可以分成以下几类:

#用法引入版本典型场景
1using 声明(引入单个名字)C++98using std::cout;
2using 指令(引入整个命名空间)C++98using namespace std;
3命名空间别名C++98namespace fs = std::filesystem;
4类型别名(替代 typedef)C++11using IntVec = std::vector<int>;
5模板别名C++11template<class T> using Vec = std::vector<T>;
6类内 using(解除隐藏 / 改权限)C++98using Base::foo;
7继承构造函数C++11using Base::Base;
8using enumC++20using enum Color;

下面逐个说明,最后给一个综合小例子。


1. using 声明(using-declaration):把单个名字引入当前作用域

cpp

#include <iostream> void f() { using std::cout; // 只引入 cout 这一个名字 cout << "hello\n"; // OK // cin << ...; // 错误,cin 没被引入 }

也可以在命名空间内部引入:

cpp

namespace app { using std::string; // app 里可以直接用 string string name; }

特点:只引入指定的名字,不像using namespace那样"污染"整个作用域。在头文件里尤其推荐用这种方式,而不是using namespace。


2. using 指令(using-directive):把整个命名空间的名字都"拉进来"

cpp

#include <iostream> using namespace std; // 整个 std 都可见 int main() { cout << "hi" << endl; }

注意:

  • 在头文件里千万不要写using namespace std;,会让包含它的所有文件都被污染。

  • 更好的做法是在函数体内局部使用,或直接用 using 声明。


3. 命名空间别名

cpp

#include <filesystem> namespace fs = std::filesystem; // 给长命名空间起个短名 fs::path p = "/tmp/a.txt";

C++11 起也支持命名空间别名模板(但用得少):

cpp

template<class T> namespace myns = std::chrono; // 实际上不太常见,意义有限

4. 类型别名(type alias declaration)—— 替代typedef

这是using最常用的用法之一。C++11 引入,语法更直观:

cpp

// 老写法 typedef std::vector<int> IntVec; typedef void (*Callback)(int); // 新写法(推荐) using IntVec = std::vector<int>; using Callback = void (*)(int);

为什么推荐using?

  • using的语法是名字 = 类型,符合直觉;typedef是反的。

  • using可以定义模板别名(见第 5 节),typedef不行。

经典对比——难读的typedef:

cpp

// 一个函数指针,参数是 int,返回 int typedef int (*FuncPtr)(int); // 等价 using,读起来更清楚 using FuncPtr = int (*)(int);

5. 模板别名(alias template)——typedef做不到的

cpp

template<class T> using Vec = std::vector<T, MyAllocator<T>>; Vec<int> v; // 等价 std::vector<int, MyAllocator<int>>

也可以把EmTimer<T>这种冗长类型统一封装(呼应你前面那段代码):

cpp

template<class Tag> using EmTimerAlias = common::platform::EmTimer<Tag>; EmTimerAlias<TempUeTimerInd> t; // 和 EmTimer<TempUeTimerInd> 完全等价

注意:模板别名是真正的别名(同一类型),不像继承那样产生新类型。你之前看到的struct OptionalEmTimer : std::optional<...>之所以用继承而不用using,正是为了得到一个独立的新类型。


6. 类内 using:解除派生类对基类成员的隐藏 / 改变访问权限

6.1 解决"名字隐藏"

cpp

struct Base { void f(int) { } void f(double) { } }; struct Derived : Base { void f(int) { } // 隐藏了 Base::f(double) }; Derived d; d.f(3.14); // 调用 Derived::f(int)(隐式转换),Base::f(double) 被藏起来了

用using把基类的重载集合重新引入:

cpp

struct Derived : Base { using Base::f; // 把 Base 的所有 f 都拉进来 void f(int) { } }; Derived d; d.f(3.14); // 现在正确调用 Base::f(double)

6.2 改变访问权限

cpp

class Base { protected: void helper(); }; class Derived : private Base { public: using Base::helper; // 把 protected 的 helper 变成 public };

7. 继承构造函数(C++11)

派生类想"原封不动"地用基类的构造函数,不用手写转发:

cpp

struct Base { Base(int) { } Base(int, double) { } }; struct Derived : Base { using Base::Base; // 继承 Base 的所有构造函数 }; Derived d1(1); // 调用 Base::Base(int) Derived d2(1, 2.0); // 调用 Base::Base(int,double)

不写using Base::Base时,派生类只会生成默认/拷贝/移动构造,基类的带参构造不会自动继承。

(这正是上一条回复里提到的:OptionalEmTimer那个空 struct 没有using Base::Base;,所以它只能通过默认构造或直接构造为空值,不能用optional(std::in_place, ...)之类的构造。)


8.using enum(C++20)

把枚举的所有枚举项一次性引入当前作用域:

cpp

enum class Color { Red, Green, Blue }; void f() { using enum Color; // 之后可以直接写 Red / Green / Blue Color c = Red; // 不用写 Color::Red }

作用域只在函数(或块)内,很安全。等价于逐个写using Color::Red; using Color::Green; ...。


9. 在模板里配合typename使用别名

当using右侧是依赖名(依赖模板参数)时,需要typename:

cpp

template<class Container> using ValueType = typename Container::value_type; ValueType<std::vector<int>> x; // int

这是using与模板、依赖名交互的一个小细节。

#include <iostream> #include <vector> #include <memory> #include <chrono> #include <string> // (3) 命名空间别名:给真实存在的 std::chrono 起短名 namespace ch = std::chrono; namespace demo { using std::string; // (1) using 声明:只引入 string using Name = string; // (4) 类型别名 using Callback = void (*)(Name); // 函数指针别名 template<class T> using Ptr = std::unique_ptr<T>; // (5) 模板别名 struct FastTag {}; struct SlowTag {}; template<class Tag> struct Timer { using TagType = Tag; // (9) 模板内的依赖别名 void run() { std::cout << "timer run\n"; } }; struct Base { Base(int) {} void f(double) { std::cout << "Base::f(double)\n"; } }; struct Derived : Base { using Base::Base; // (7) 继承构造函数 using Base::f; // (6) 解除基类名字隐藏 void f(int) { std::cout << "Derived::f(int)\n"; } }; } // namespace demo int main() { using demo::Name; // (1) using namespace demo; // (2) 块作用域内用,安全 Name n = "alice"; Ptr<int> p = std::make_unique<int>(42); // (5) Timer<FastTag> t; // 与 Timer<FastTag> 同类型 t.run(); Derived d(7); // (7) 继承构造函数 d.f(3.14); // (6) 正确调用 Base::f(double) d.f(7); // 调用 Derived::f(int) ch::milliseconds ms(100); // (3) 命名空间别名演示 std::cout << n << " " << *p << " " << ms.count() << "\n"; return 0; }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询