C++11中using关键字的主要作用是:为一个模板库定义一个别名。

文章链接:派生类中使用using别名改变基类成员的访问权限 

一、《Effective Modern C++》里有比较完整的解释

各个作用

/*定义别名*/template<class T>using Tlist = std::list<T>;using Tlist = std::list<char>;Tlist listChar;//typedef void (*df)()using  df = void(*)();/*使用外部构造*/using A::A;/*引用外部类型*/
using typename A;

二、Using 关键字的作用:重载父类函数

1.在当前文件中引入命名空间

这是我们最熟悉的用法,例如:using namespace std;

2.在子类中使用 using 声明引入基类成员名称(参见C++ primer)

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

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

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

class Derived : private Base {
public:
using Base::size;
protected:
using Base::n;
// ...
};

另外,当子类中的成员函数和基类同名时,子类中重定义的成员函数将隐藏基类中的版本,即使函数原型不同也是如此(隐藏条件见下面)。

如果基类中成员函数有多个重载版本,派生类可以重定义所继承的 0 个或多个版本,但是通过派生类型只能访问派生类中重定义的那些版本,所以如果派生类想通过自身类型使用所有的重载版本,则派生类必须要么重定义所有重载版本要么一个也不重定义。有时类需要仅仅重定义一个重载集中某些版本的行为,并且想要继承其他版本的含义,在这种情况下,为了重定义需要特化的某个版本而不得不重定义每一个基类版本,可能会令人厌烦。可以在派生类中为重载成员名称提供 using 声明(为基类成员函数名称而作的 using 声明将该函数的所有重载实例加到派生类的作用域),使派生类不用重定义所继承的每一个基类版本。一个 using 声明只能指定一个名字,不能指定形参表,使用using声明将名字加入作用域之后,派生类只需要重定义本类型确实必须定义的那些函数,对其他版本可以使用继承的定义。

“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

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

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

#include "StdAfx.h"
#include <iostream>
using namespace std;
class Base
{
public:    void menfcn(){cout<<"Base function"<<endl; }void menfcn(int n){cout<< cout<<"Base function with int"<<endl; }
};class Derived : Base
{
public:
using Base::menfcn;//using声明只能指定一个名字,不能带形参表
int menfcn(int)
{ cout<< cout<<"Derived function with int"<<endl; }
};
int main()
{    Base b; Derived d;   b.menfcn();   d.menfcn();//如果去掉Derived类中的using声明,会出现错误:error C2660: 'Derived::menfcn' : function does not take 0 arguments    std::cin.ignore(std::cin.gcount()+1);//清空缓冲区    std::cin.get();//暂停程序执行
}

三、需要注意的情况

子类中using引入基类函数时需要注意的情况

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

此时derived::test()会隐藏(hide)父类中的两个test重载函数(base::test()和base::test(int)),因此我们为子类中加上一个using声明:

class derived : public base{
public:void test(){cout << "derived::test()" << endl;}using base::test;//此声明放在test前面和后面效果都一样
};

现在会不会出现下面所述的情况呢?
---------------------------------------------------------------------------------------------------------------
既然using base::test将父类中的两个test函数都引入子类,则子类中就相当于有了一个void test()函数,所以我们在子类中重新定义的void test()函数将会和从父类中引入的void test()函数发生冲突,进而出现“重定义”错误。
---------------------------------------------------------------------------------------------------------------
答案是:不会!
此时,子类中重新定义的void test()函数将“顶替”从父类中引入的void test()函数。
(PS:从父类中引入的另外一个void test(int)函数则没有发生变化(仍然是父类中的函数实现)。)
类似的另外一种情况如下,此时加入了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;}
};

此时derived::test()虽然重写(override)了base::test(),但是同时也隐藏(hide)父类中的两个test重载函数(一个virtual函数base::test(double)和一个nonvirtual函数base::test(int))。现在,我们为子类中加上一个using声明:

class derived : public base{
public:void test(){cout << "derived::test()" << endl;}using base::test;//此声明放在test前面和后面效果都一样
};

与上面的类似,此时derived::test()“仍然重写”了父类的base::test(),并且与父类中的base::test(double)和base::test(int)[在子类的域]中形成重载集合。


最后,留一个思考题目,如下:

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;pb->test(2.4);return 0;
}

问题:derived中的using base::test加上与否,对程序的结果有什么影响?
答:没有影响。(关键点:名字解析是编译时期的事情,而virtual函数动态绑定是运行时期的事情。)
(PS:但是将main函数改成“derived *pd = new A; pd->test(2.4);”,则有区别了:如果将using base::test去掉,则编译失败。)

C++11:using 的各种作用相关推荐

  1. html oninput的作用,html范围滑块 - oninput在IE 11中不起作用

    我已经实现了一个范围滑块,它使用该值从数组中获取元素并显示该元素,而不是显示范围值.它适用于Chrome和Firefox但不适用于IE 11 - 当滑块移动时,该值不会获得更新的元素. HTML: t ...

  2. C++11 explicit关键字的作用

    explicit 在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换.因为无参构造函数和多参构造函数本身就是显示调用 ...

  3. 11种维生素的作用和来源

            1 维生素A 对大多数动物来说,维生素A的来源是植物中的类胡萝卜素,主要是β-胡萝卜素,其次有α-胡萝卜素,γ-胡萝卜素,隐黄素等,它们存在于有色蔬菜及黄水果中. 2 维生素D 含维生 ...

  4. Intent Action_dial 在 android 11 中不起作用

    在注册文件中添加 <queries><intent><action android:name="android.intent.action.DIAL" ...

  5. C++11:shrink_to_fit的基本作用与使用

    vector::shrink_to_fit() 是 C++ STL 中的内置函数,它减少容器的容量以适应其大小并销毁超出容量的所有元素. #include <iostream> #incl ...

  6. 双11大幕拉开,菜鸟智能机器人也将测试运行

    不知道有了机器人的帮忙,今年剁手的伙伴们能不能早点拿到快递. 菜鸟网络近日宣布智能仓库全面升级,在浙江嘉兴打造的大型自动化流水线将在今年双11中发挥重要作用.与此同时,一批智能机器人也在仓库内开始测试 ...

  7. HTML5中常用的标签(及标签的属性和作用)

    1.标签:<!DOCTYPE> 作用:声明是文档中的第一成分,位于<html>标签之前. 2.标签:<html> 作用:此元素可告知浏览器其自身是一个HTML文档. ...

  8. C++11新标准 default 和 delete的使用

    写这个知识点的初衷也是在面试的时候被问到过的,由于对C++11新标准不是很了解,所以你懂得...,好了不多说了 首先我们要了解一下C++类中的四类特殊成员函数:分别是默认构造函数.析构函数.拷贝构造函 ...

  9. cdi 作用 spring_什么是CDI,它与@EJB和Spring有什么关系?

    cdi 作用 spring 简要概述了Java EE中的依赖项注入,@ Resource / @ EJB和@Inject之间的区别以及它们与Spring的关系-主要是链接形式. 上下文依赖注入(CDI ...

  10. c++ enum 给定类型_C++11作用域内枚举enum

    在C++11之前的枚举(enum),是没有办法两个枚举(enum)内有相同枚举名的.如果还不知道C++中枚举(enum)是什么,可以看这篇:枚举enum 如:苹果和桔子都有大,中,小.写个代码来说明下 ...

最新文章

  1. SimpleHTTPServer中出错信息:SocketServer doesn't handle client disconnects properly
  2. 详解Batch Normalization及其反向传播
  3. 中断描述符表IDT以及Linux内核IDT表的初始化的基本情况
  4. HDFS底层原理系列讲解之fsimage、editslog
  5. QUIC实战(二) AWS 搭建nginx(http3.0) + upsync + consul(server-client模式) 集群
  6. SSH连接linux时,长时间不操作就断开的解决方案
  7. Pyplot绘图的格式
  8. Mac下搭建手机APP开发环境(HBuilder X ,HTML5plus Runtime,MUI,springboot)
  9. Tomcat中设置数据源和连接池
  10. github 仓库管理及代码上传
  11. python中怎样划分时间段_如何划分重叠的日期时间间隔(组织模式时钟时间)?...
  12. Java二叉树基础操作常见代码例题
  13. cd linux制作u盘启动盘,【cdlinux u盘启动】cdlinux制作U盘启动盘详细教程
  14. 女神也用的约会决策:决策树算法实践
  15. 无线网络 看不到其他计算机,无线局域网内两台电脑网上邻居看不到
  16. html关于圣诞节主题的网页,灵感: 8个以圣诞节为主题的网站欣赏
  17. 共享充电宝为啥能够盈利
  18. 小米手机超越苹果,成欧洲第二;马斯克特斯拉内部邮件:痛恨开会,少讲黑话;Spring 6.0 发布|极客头条
  19. python国际象棋ai程序_Python开发AI应用-国际象棋应用
  20. PLSQL自动登录,记住用户名密码日常使用技巧

热门文章

  1. [译]GC专家系列4-Apache的MaxClients设置及其对Tomcat Full GC的影响
  2. 再一次证明了普通的U盘和SD(TF)卡的不可靠
  3. nginx优化-nginx事件处理模型优化use epoll;
  4. 微信小程序自定义组件方案
  5. [Amaze UI] 如何推进 mobile first 的前端 Web 方案
  6. js学习笔记15----子节点和兄弟节点的操作
  7. java用循环方式实现和计算机玩猜拳的程序
  8. povray[1] = 天空
  9. 【Bugly 技术干货】Android开发必备知识:为什么说Kotlin值得一试
  10. OSCACHE(转)