Effective C++——Item33: 避免隐藏继承的名字
Effective C++——Item33: 避免隐藏继承的名字
一、从原理理解隐藏
- 从变量作用域看隐藏

全局变量x和局部变量x的类型是不同的,但C++的隐藏规则:只隐藏名字(hiding names)。
int x; // global variable
void someFunc()
{
double x; // local variable
std::cin >> x; // read a new value for local x
}
对于继承而言,隐藏的原理即为:派生类作用域内嵌在基类作用域中。
这是为了强调我们正在谈论名称。该示例还可以包含类型名称,例如枚举、嵌套类和 typedef。在这次讨论中唯一重要的是它们的名字。
从例子理解名字(names)的查找过程
class Base {
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf2();
void mf3();
};
class Derived: public Base {
public:
virtual void mf1();
void mf4() {
//..
mf2();
//..
}
};
在mf4()中查找mf2()的过程:
- 局部作用域mf4()函数
- 包含作用域Derived类
- 下一个包含作用域Base类
- Base类的namespace中查找
二、从实例理解隐藏
- 基类函数被隐藏,即使参数不同
#include <iostream>
using namespace std;
class Base {
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int) {
cout << "Base::mf1(int)" << endl;
}
virtual void mf2() {
cout << "Base::mf2()" << endl;
}
void mf3() {
cout << "Base::mf3()" << endl;
}
void mf3(double) {
cout << "Base::mf3(double)" << endl;
}
};
class Derived: public Base {
public:
virtual void mf1() {
cout << "Derived::mf1()" << endl;
}
void mf3() {
cout << "Derived::mf3()" << endl;
}
void mf4() {
cout << "Derived::mf4()" << endl;
}
};
int main() {
Derived d;
d.mf1(); // call Derived::mf1
d.mf1(1); // error, Derived::mf1 hides Base::mf1, can't find Base::mf1(int)
d.mf2(); // ok, call Base::mf2
d.mf3(); //ok, hides Base::mf3, call Derived::mf3(),
d.mf3(1.0); // error, Derived::mf3() hides Base::mf3, can't find Base::mf3(double)
return 0;
}
- 如何使被隐藏的函数可见
using声明——使得所有某个名字的事物都可见
using Base::mf1;
using Base::mf3;
使得Base类中所有名为mf1、mf3的事物都在Derived类中可见。
#include <iostream>
using namespace std;
class Base {
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int) {
cout << "Base::mf1(int)" << endl;
}
virtual void mf2() {
cout << "Base::mf2()" << endl;
}
void mf3() {
cout << "Base::mf3()" << endl;
}
void mf3(double) {
cout << "Base::mf3(double)" << endl;
}
};
class Derived: public Base {
public:
using Base::mf1;
using Base::mf3;
virtual void mf1() {
cout << "Derived::mf1()" << endl;
}
void mf3() {
cout << "Derived::mf3()" << endl;
}
void mf4() {
cout << "Derived::mf4()" << endl;
}
};
int main() {
Derived d;
d.mf1(); // ok
d.mf1(1); // ok, call Base::mf1(int)
d.mf2(); // ok, call Base::mf2
d.mf3(); //ok, call Derived::mf3(),
d.mf3(1.0); // ok, Base::mf3(double)
return 0;
}
- 内联转发函数——不希望全部可见
class Base {
public:
virtual void mf1() = 0;
virtual void mf1(int);
};
class Derived: private Base {
public:
virtual void mf1() // forwarding function; implicitly inline
{
Base::mf1();
}
};
...
Derived d;
int x;
d.mf1(); // fine, calls Derived::mf1
d.mf1(x); // error! Base::mf1() is hidde
三、重载、重写、隐藏的区别
- 函数重载发生在相同作用域
重载时机:参数数量、类型、返回值、是否const函数
- 函数隐藏发生在不同作用域
隐藏时机:隐藏上一级同名变量、函数(不管参数类型、返回类型)
- 函数覆盖就是函数重写。准确地叫做虚函数覆盖和虚函数重写,也是函数隐藏的特例。
Effective C++——Item33: 避免隐藏继承的名字的更多相关文章
- effective C++ Item 33 避免隐藏继承而来的名字
1. 普通作用域中的隐藏 名字实际上和继承没有关系.有关系的是作用域.我们都知道像下面的代码: int x; // global variable void someFunc() { double x ...
- 读书笔记 effective C++ Item 33 避免隐藏继承而来的名字
1. 普通作用域中的隐藏 名字实际上和继承没有关系.有关系的是作用域.我们都知道像下面的代码: int x; // global variable void someFunc() { double x ...
- Effective JavaScript Item 40 避免继承标准类型
本系列作为Effective JavaScript的读书笔记. ECMAScript标准库不大.可是提供了一些重要的类型如Array,Function和Date.在一些场合下.你或许会考虑继承当中的某 ...
- 1.隐藏继承的成员new / 虚方法(override)/ abstract / 多态 ----- 重写
总结: 1. 在继承上, new/override没区别 2. 在多态上,new不支持多态,override支持 在C#中改变类中相同名称的方法的实现过程中有三种方式:重载.重写和覆盖. 重载:指具有 ...
- Effective C++ 34 区分接口继承和实现继承
public继承从根本上讲,有两部分:接口继承和实现继承.两者之前的区别很像函数声明与函数定义. 具体设计中,会呈现三种形式:derived class只继承成员函数的接口(纯虚函数):derived ...
- Effective C++ 33 避免遮掩继承而来的名称
首先介绍一个原则LSP(Liskov Substitution Principle),如果Class D以Public方式继承Class B,则所有B对象可以派上用场的任何地方,D对象一样可以派上用场 ...
- [Effective C++ --033]避免遮掩继承而来的名称
这一章一直在想怎么写,因为比较基础,很容易理解,就按照需要来写吧. 假设我们有这样一个类: class Base { private: int x; public: ; virtual void mf ...
- 读书笔记 effective c++ Item 43 了解如何访问模板化基类中的名字
1. 问题的引入——派生类不会发现模板基类中的名字 假设我们需要写一个应用,使用它可以为不同的公司发送消息.消息可以以加密或者明文(未加密)的方式被发送.如果在编译阶段我们有足够的信息来确定哪个信息会 ...
- Effective C++(20) 继承与面向对象设计
本文主要参考<Effective C++ 3rd>中的第六章部分章节的内容. 关注的问题集中在继承.派生.virtual函数等.如: virtual? non-virtual? pure ...
- 读书笔记 effective C++ Item 40 明智而谨慎的使用多继承
1. 多继承的两个阵营 当我们谈论到多继承(MI)的时候,C++委员会被分为两个基本阵营.一个阵营相信如果单继承是好的C++性质,那么多继承肯定会更好.另外一个阵营则争辩道单继承诚然是好的,但多继承太 ...
随机推荐
- Linux常用指令及shell脚本记录
记录一些常用指令在博客上,以防哪天因太久不敲而忘却,还可以直接翻看博客记录,不用再一条条百度搜...... 一.Linux常用指令 一.设置文件权限为aapp用户及用户组-- chown -R app ...
- k8s 实战 3----标签
如果你对k8s还不了解,可以看下前文k8s 实战 1 ---- 初识 (https://www.cnblogs.com/jilodream/p/18245222)k8s 实战 2 ---- pod 基 ...
- 国内版Unity 2023编辑器无法切换到DX12模式的解决方法
2024.7.4更新:至6000.0.5f1c1,此问题已修复 在{安装目录}\Editor里(也就是Unity安装的根目录)建立一个名叫D3D12的文件夹. 去{安装目录}\Editor\Data\ ...
- 首届 DIVE 精彩回顾丨践行企业数字化,基础软件如何创新
"墙高基下,虽得必失."在构建数字企业大厦的工程中,基础软件的重要性不言而喻.但对于各行各业而言,面向传统经营模式设计的基础软件已经难以支撑数字业务的创新,唯有汲取专业团队的经验, ...
- [oeasy]python0083_十进制数如何存入计算机_八卦纪事_BCD编码_Binary_Coded_Decimal
编码进化 回忆上次内容 上次 研究了 视频终端的 演化 从VT05 到 VT100 从 黑底绿字 到 RGB 24位真彩色 形成了 VT100选项 从而 将颜色 数字化 了 生活中我们更常用 10个数 ...
- [oeasy]python0082_VT100_演化_颜色设置_VT选项_基础色_高亮色_索引色_RGB总结
更多颜色 回忆上次内容 上次 了解了控制序列 背后的故事 一切标准 都是 从无到有 的 就连 负责标准的组织 也是 从无到有 的 VT-05 奠定了 基础颜色 黑底 绿字 隔行 扫描 但 多颜色设置 ...
- oeasy教您玩转vim - 40 - # 复制粘贴
复制粘贴 回忆上节课内容 我们上次的内容是粘贴 小写p意味着在光标下面或者后面粘贴 大写P意味着在光标上面或者前面粘贴 p的意思是放上去,就是put 把什么放上去呢? 把 reg 中 " ...
- 封装的grid控件
class CGridCtrl : public CWnd { DECLARE_DYNAMIC(CGridCtrl) public: void Create(CWnd* pParent, DWORD ...
- 系动词&使役动词
系动词 系动词的作用就是赋值 I am a rabbit 把 a rabbit赋值给i我 我是一只兔子 The rabbit is smart 这兔子是聪明的 smart赋值给兔子 系动词连系的方式, ...
- 从pytest源码的角度分析pytest工作原理
从pytest源码的角度分析pytest工作原理 从 pytest 源代码的角度来分析其工作原理,我们需要关注几个关键的部分,特别是 pytest 的启动过程以及测试的收集与执行.下面是基于 pyte ...