C++ 关键字using

using

using 作用

using std::cout; // using 声明,形式: using namespace_name::name 
using std::cin; 

using namespace std; // using 指示,形式: using namespace 命名空间名
/*定义别名*/
//******************************************************************************************//
using value_type = _Ty;                         // 类型别名

//******************************************************************************************//
typedef void (*FP) (int, const std::string&);   // 函数别名:FP代表一个函数指针,指向返回类型 void,参数(...)
using FP = void (*) (int, const std::string&); // C++11 推荐此种写法,可读性要比 typedef 好

 typedef std::string (Foo::* fooMemFnPtr) (const std::string&);  // 函数别名
 using fooMemFnPtr = std::string (Foo::*) (const std::string&);  // 函数别名

//******************************************************************************************//
template<calss T>                              // 模板别名
using Tlist = std::list<T>;                    // 定义了 std::list<T> 的别名 Tlist
using Clist = std::list<char>;                 // 定义了 std::list<chart> 的别名 Clist
Clist listChar;                                // 初始化 std::list<chart> 对象 listChar

template <typename T>                          // 表示模板别名时,using 与 typedef的对比
using Vec = MyVector<T, MyAlloc<T>>;           
// usage
Vec<int> vec;

template <typename T>
typedef MyVector<T, MyAlloc<T>> Vec;            // 编译器报错:"error: a typedef cannot be a template"
// usage                                        // C++11 完全鼓励使用 using,而不用 typedef 来做模板别名
Vec<int> vec;

using 声明

using 声明中引入的名字遵循常规作用域规则:从using声明点开始,直到包含该using声明的作用域的末尾,名字都是可见的。外部作用域中定义的同名实体被屏蔽

例如:

--example 1--
#include<iostream>
using namespace std;
namespace Lib
{
    void print(int x)
    {
        cout<<"int"<<x<<endl;
    }
}
void print(double y){
        cout<<"double"<<y<<endl;
    }
int main()
{
    using Lib::print;              // example 1 : main作用域中嵌套了Lib命名空间
    print(1.3);                    // main外的 void print(double y) 函数被屏蔽
    print(3);
    getchar();
    return 1;
}
//输出:
int 1
int 3
--example 2--
#include<iostream>
using namespace std;
namespace Lib
{
    void print(int x)
    {
        cout<<"int"<<x<<endl;
    }
}
void print(double y){
        cout<<"double"<<y<<endl;
    }
using Lib::print;                // example 2 : main作用域中平行于Lib命名空间
int main()
{
    print(1.3);                  // 选择调用重载函数中的 void print(double y)
    print(3);                    // 选择调用重载函数中的 void print(int y)
    getchar();
    return 1;
}
//输出:
double 1.3
int 3

using 指示:引入命名空间

using 指示使得某个特定命名空间中所有名字可见,这样就无需在后面的源程序中再添加前缀限定符,如:

using namespace std;

尽量少使用 using 指示污染命名空间

一般来说,使用 using 命令比使用 using 编译命令更安全,这是由于它只引入了制定的名称。如果该名称与局部名称发生冲突,编译器将发出指示。using 编译命令导入所有的名称,包括可能并不需要的名称。如果与局部名称发生冲突,则局部名称将覆盖名称空间版本,而编译器并不会发出警告。另外,名称空间的开放性意味着名称空间的名称可能分散在多个地方,这使得难以准确知道添加了哪些名称。

using namespace std;                 // 应尽量少使用

int x;
std::cin >> x;                       // 应尽量这样使用
std::cout << x << std::endl;  

using std::cin;                      // 或者像这样集中命名
using std::cout;
using std::endl;
int x;
cin >> x;
cout << x <<endl;

不恰当使用using可能带来的错误:

namespace blip
{
    int bi = 10, bj = 20, bk = 30;
}
int bj = 0;                            //
void main(){
    using namespace blip;              // 在 main 作用域引入命名空间 blip
    ++bi;                              // OK, bi = 11
    ++bj;                              // wrong , “bj”: 不明确的符号
    ++ ::bj;                           // OK, bj = 1;
    ++ blip::bj;                       // OK, bj = 21;
    int bk = 97;
    ++bk;                             // OK, bk = 98
}

using 与重载父类函数

1. 在子类中使用 using 声明引入基类成员名称

当继承为 private 或者 protecd 时,基类成员的访问级别在派生类中受限:

class Base{
public:
    std::size_t size() const {return n;}
protected:
    std::size_t n;
};
class Derived : privete Base { ... };    

在这一继承层次(private)中,成员函数 size 在 Base 中为 public,但在 Derived 中为private。为了使 size 在 Derived 中成为 public,可以在 Derived 的public 部分增加一个 using 声明。如下这样改变 Derived 的定义,可以使 size 成员能够被Derived对象访问,并使 n 能够被 Derived 的派生类访问:

class Derived : private Base
{
public:
    using Base::size;                // using 声明只能指定一个名字,不能带形参
protected:
    using Base::n;   
};

如果基类中成员函数有多个重载版本,派生类可以重定义所继承的 0 个或多个版本,但是通过派生类型只能访问派生类中重定义的那些版本,所以如果派生类想通过自身类型使用所有基类中成员函数的重载版本,则派生类必须要么重定义所有重载版本,要么一个也不重定义。为了避免多余的工作,可以使用 using 声明。将名字引入作用域后,派生类只需要重定义类型必须要重定义的那些函数,对其他版本的可以使用继承过来的定义。

#include "StdAfx.h"
#include <iostream>
using namespace std;
class Base
{
public:    
   void menfcn()
  {
     cout<<"Base function"<<endl; 
  }
    int menfcn(int n)
    {
     cout<<"Base function with int"<<endl; 
    }
};
 
class Derived : private Base
{
public:    
    using Base::menfcn;  // using声明只能指定一个名字,不能带形参表; 若去掉using,基类的2个menfcn函数会被隐藏  
    int menfcn(int)      // 重载了 Base 基类的 int menfcn(int n) 函数
    { cout<<"Derived function with int"<<endl; }
    };
int main()
{    
    Base b; 
    Derived d;           // 派生类的对象 d
    b.menfcn();   
    d.menfcn();          // 如果去掉Derived类中的using声明,会出现错误:
                         // error C2660: 'Derived::menfcn' :function does not take 0 arguments
}

2 构造函数的 using 声明【C++11】

在 C++11 中,派生类能够重用其直接基类定义的构造函数:

class Derived : Base
{
public:
    using Base::B;
    /* ... */
};   

如上 using 声明,对于基类的每个构造函数,编译器都生成一个与之对应(形参列表完全相同)的派生类构造函数。生成如下类型构造函数:

derived(params) : base(args) {}

3. 隐藏:派生类的函数屏蔽了与其同名的基类函数

如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏;(注意别与重载混淆?)

如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有 virtual 关键字。此时,基类的函数将被隐藏;(注意别与覆盖混淆?)

class Base{
public:
 virtual void test(){
      cout << "base::test()" << endl; }
 virtual void test(double){
      cout << "base::test(double)" << endl; }
 void test(int){
     cout << "base::test(int)" << endl; }
};

class Derived : public base{
public:
     void test(){
     cout << "derived::test()" << endl; }
 //using base::test;                        
};

class A : public Derived{
public:
     void test(double){
     cout << "A::test(double)" << endl; }
};
int main(int argc, char **argv){
     Base *pb = new A;            // 此时,Derived 中的using base::test 是否加上对程序没有影响,名字解析是编译时期的事情,而virtual函数动态绑定是运行时期的事情
     pb->test(2.4);
     Derived *pd = new A;
     pd->test(2.4);               // 此时,若 Derived 中没有using base::test,将会报错编译失败。
     return 0;
}

【参考资料】

《C++ Primer》

https://blog.csdn.net/shift_wwx/article/details/78742459

https://blog.csdn.net/wishchin/article/details/79870177

https://blog.csdn.net/mlyjqx/article/details/74783811

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值