C++中using的用法

Last Updated: 2023-08-01 08:09:46 Tuesday

-- TOC --

C++中的using主要用于引入指定的namespace,还可以定义类型别名,以及在子类中引用基类的成员。

推荐学习:C++中的namespace的用法

using namespace

在阅读代码的时候,常常见到这样一句:

// C++
using namespace std;

这行代码的含义,就是引入std namespace中的所有symbol到某个space或block,有了这行代码,std namespace中的这些symbol就都可以直接在对应的namespace或code block中使用了,比如cin,cout。

这行代码的含义,有点像Python的star import:

# Python
from std import *

当然,Python没有std这个模块,以上只是示意。

Python并不推荐使用这种star import,C++据说也是一样的,这样做很容易导致冲突。

我一般能够容忍自己在一个Python模块中只是用一行star import,同理,如果C++同时使用多行using namespace,很容易造成symbol conflict符号冲突。不过C++在编译阶段能够发现这类冲突。

还可以在一个code block范围内using namespace,我有写了下面的测试代码,能够正常执行,说明using引入的namespace,也存在有效的scope范围:

#include <cstdio>
#include <iostream>

namespace abc {
    int cout = 16;
}

void func(void) {
    using namespace abc;
    printf("%d\n", cout);
}

using namespace std;

int main(void) {
    cout << "std" << endl;
    func();
    return 0;
}

输出:

$ clang++ -Wall -Wextra test_using.cpp -o using
$ ./using
std
16

以上代码,using namespace std放在全局,using namespace abc放在func函数内,相当于只在func内引入abc中的name。

C++中的那些namespace定义在include文件中,下面的测试代码,就隐藏了这个秘密:

$ cat test_using.cpp
#include <iostream>

using namespace std;

int main(void) {
    cout << "std" << std::endl;
    return 0;
}

以上代码 ,直接使用cout,但是通过域选择符::来间接指定endl,都OK!对应的Python代码示意代码:

# Python
import std
from std import *

就是这个意思,std和std内的符号,都可以直接使用。

不要在头文件中使用using namespace!

You should never put a using namespace directive within a header file. Every source file that includes your header will dump all the symbols from that using directive into the global namespace. This can cause issues that are very difficult to debug.

当出现nested namespace时:

using namespace a::b

a::b中的name就导入进来了。

using directive

推荐的编程风格如下,学名叫using diretive。(但对于std名字空间,我从来不这样用,除非特殊情况)

// C++
using std::cout;
using std::cin;
using std::endl;
// OR
using std::cout, std::cin, std::endl;

这就像Python的:

# Python
from std import cout, cin, endl

下面是一个在code block中使用using directive的示例:

#include <cstdio>

namespace BroopKidron13::Shaltanac {
    enum class Color {
        Mauve,
        Pink,
        Russet
    };
}

int main() {
    using BroopKidron13::Shaltanac::Color; //!!
    const auto shaltanac_grass = Color::Russetv;
    if(shaltanac_grass == Color::Russetw) {
        printf("The other Shaltanac's joopleberry shrub is always "
            "a more mauvey shade of pinky russet.");
}
}

type aliasing,类型别名

C++推荐使用using=的组合来代替C语言的typedef!typedef像是在定义新的类型,而using仅仅只是定义了一个新的别名。

A type alias defines a name that refers to a previously defined name. You can use a type alias as a synonym for the existing type name.

using可以用来定义type的别名,较短的更清晰的别名,会提升代码的可读性和可维护性。比如:

// C++ style
using String = const char[260];
using ShaltanacColor = BroopKidron13::Shaltanac::Color; 
// C style
typedef const char String[260]; // example: String a = {0};

能看出来,typedef的表达比较费解,另一个因费解而不推荐在C++中使用typedef的示例,是用typedef定义函数指针类型

C++20开始,当把type aliasing应用到template的时候,出现了partial application这个概念(类似Python中的partial),确定了部分或全部type的template别名。请看如下示例:

You can introduce template parameters into type aliases. This enables two important usages:

#include <iostream>
using namespace std;

template<typename A, typename B>
struct xyz {
    A add(A a, B b) {
        return (A)(a+b);
    }
};

template<typename B>
using add_cast2_int = xyz<int, B>;

using add_cast2 = xyz<int,int>;

int main(void) {
    add_cast2_int<char> x;
    cout << x.add(1,(char)2) << endl;
    add_cast2_int<short> y;
    cout << y.add(1,(short)3) << endl;
    add_cast2_int<int> z;
    cout << z.add(1, 4) << endl;

    add_cast2 a;
    cout << a.add(10,10) << endl;
    return 0;
}

编译和输出:

$ g++ -std=c++20 -Wall -Wextra test.cpp -o test
$ ./test
3
4
5
20

typedef不支持template,这是C++标准委员会的特意选择,目的就是为了避免混淆。

本文链接:https://cs.pynote.net/sf/c/cpp/202208051/

-- EOF --

-- MORE --