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++性质,那么多继承肯定会更好.另外一个阵营则争辩道单继承诚然是好的,但多继承太 ...
随机推荐
- Spring的@Configuration和@Bean注解定义第三方bean
@Configuration和@Bean注解的使用 @Configuration标注在类上,相当于把该类作为spring的xml配置文件中<beans>,作用为:配置spring容器(应用 ...
- 解决方案 | Citrix Receiver无法正常启动的多种解决方案
下面是个人在实践过程中总结的解决办法: 方案1:卸载Citrix Receiver(一般通过控制面板卸载,如果正常无法卸载则需要通过官方卸载软件ReceiverCleanupUtility软件卸载), ...
- ModuleNotFoundError: No module named 'import_export'
当你遇到 "ModuleNotFoundError: No module named 'import_export'" 错误时,这表示你的 Python 脚本或应用程序试图导入名为 ...
- SMU Summer 2024 Contest Round 1(7.8)zhaosang
A-A http://162.14.124.219/contest/1005/problem/A 一道数学问题,求概率. 要求成功的概率,有两个色子, 一个用来抛正反面,一个用来控制得分大小,当超过某 ...
- ABC348
A link 这道题就先输出整个的\(oox\),再输出剩一个两个的. 点击查看代码 #include<bits/stdc++.h> using namespace std; int n; ...
- Centos7下安装配置最新版本Jenkins(2.452.3)
1.基础环境配置 1.1 服务器下载Jenkins安装包 下载地址:https://www.jenkins.io/download/ 下载命令:wget https://get.jenkins.io/ ...
- IDEA整合Spring+Struts+Hibernate项目
新手使用idea整合Spring+Struts+Hibernate项目 项目所需jar下载: https://download.csdn.net/download/weixin_44906002/12 ...
- java开发,json转list集合,原生实现
java 是一门面象对象的语言,对象需要先定义,但是在外理网络请求时候会用到json 转成java 对象,虽然现代开发框架中也提供了很多工具和方法直接转换, 但是作为学习者了解 一下底层实现,更能灵活 ...
- 【Java】实体类转换框架 MapStruct
简单尝试了下发现比Dozer还有BeanUtil还方便小巧 注解的作用是在生成字节码文件时实现具体GetterSetter方法,实际转换时就是赋值操作,嘎嘎快 参考文章: https://juejin ...
- 【Java】系统找不到指定路径
报错信息: 2021-05-26 13:50:11,737 RMI TCP Connection(3)-127.0.0.1 ERROR DefaultRolloverStrategy contains ...