1. using 关键字
使用 using 关键字,可以将父类中被隐藏的函数暴露在子类中,但是需要注意的是,在相同情况下,子类函数的优先级更高。
2. 继承构造函数(C++11)
在c++11之前,构造函数、析构函数、赋值操作符,这些都不能被继承。但是,C++11允许我们使用 using 关键字来继承基类的构造函数。
示例1
示例2
3. 重写方法时的特殊情况
1) static 超类方法
在C++中,无法重写静态方法,因为方法不可能既是静态的又是虚的。如果子类中存在的静态方法与超类中的静态方法同名,实际上这是两个独立的方法。
2) 重写 private 或者 protected 超类方法
完全没有问题。记住:子类无法调用父类的 private 方法并不意味着无法重写这个方法。
4. 超类方法具有默认参数
子类与超类可以具有不同的默认参数,但使用的参数取决于声明的变量类型,而不是底层的对象。也就是说,C++根据描述对象的表达式类型绑定默认参数,而不是根据实际的对象类型参数。来看下面例子,使用的即为超类方法的默认参数。
再来看一个例子:
5. 子类方法具有不同的访问级别
我们可以修改父类方法在子类中的访问级别——可以加强限制也可以放宽限制。在 C++ 中,无论是加强限制还是放宽限制,意义都不是很大,但是这么做也是有合理原因的。
为了加强某个方法(或者数据成员)的限制,有两种方法。方法之一是修改整个子类的访问说明符,本文后面将讲述该方法。另一种方法是在子类中重新定义访问限制。
我们没有很好的方法(也没有很好的理由)来限制访问父类的 public 方法。
实际上,在子类中放宽访问限制是比较容易,也相对更有意义的。最简答的方法是在子类中提供一个 public 方法来访问父类的 protected 方法,如下所示:
调用 Blabber 对象的 public tell() 方法的用户代码可以有效地访问 Secret 类的 protected() 方法。当然,这并没有真正改变 dontTell() 的访问级别,只是提供了访问这个方法的 public 方法,对外提供了一个接口而已。
实际上,我们可以在 Blabber 子类中显式地重写 dontTell(),并将这个方法设置为 public 访问。来看以下代码:
以上代码如果通过 blabber 来调用 dontTell() 当然没有问题,但是由于父类中的 protected 方法仍然是 protected 的,因此使用指针或者引用来调用 Secret 的 dontTell() 将无法通过编译。
注意:在工程中唯一有益的,是对父类中的 protected 方法提供较为宽松的访问限制,也就是放宽限制。
6. 子类中的复制构造函数以及赋值运算符
当我们需要在类中动态分配内存时,提供一个 copy constructor 和 assignment operator 是必要的。当定义子类时,我们需要特别关注 copy constructors 以及 operatpr=。
无论父类是否定义了非默认的拷贝构造函数以及复制赋值运算符,只要子类没有特殊的数据成员(通常是指针)需要我们定义一个非默认的拷贝构造函数或者复制赋值运算符,那么我们就无需定义。如果子类省略了 copy constructor 或者 operator=,那么编译器会为子类中的数据成员提供默认的 copy constructor 以及 operator=,同时父类中的 copy constructor 和 operator= 会被用于父类中的数据成员。
另一方面,如果在子类中自定义了 copy constructor,我们就需要在该 copy constructor 中显式地调用父类的 copy constructor。 如果不这么做,那么默认构造函数(不是拷贝构造函数)将被用于对象中的父类成分。
[Why?我个人是这样理解的,因为通常一个类中数据成员都是私有的,那么只有父类的构造函数(无论是默认构造函数还是拷贝构造函数)才能对这些 private 数据成员进行初始化,为了统一,cpp便规定子类中的构造函数必须调用父类的构造函数来对父类部分的数据成员进行初始化。]
相似的,如果子类需要重写 operator=,调用父类版本的 operator= 往往是必要的([事实上,对于非 private 数据成员即使不调用父类的 operator= 来完成赋值,语法上也没有错,这点不像拷贝构造函数那样严格])。如果不这样做,可能处于某些很奇怪的原因,使得你只想对 object 的部分数据成员进行赋值。下面的代码示范了如何在子类中调用父类的operator=。
If your subclass does not specify its own copy constructor or operator=, the
parent functionality continues to work. If the subclass does provide its own copy
constructor or operator=, it needs to explicitly reference the parent versions.
如果想禁止复制一个类,应该怎么办?显然我们可以把类的复制构造函数设为private,但是这样一来该类的 friend 成员仍然可以复制该类,于是我们只声明这个函数,而不去实现。另外,如果你不需要复制该类的对象,最好把赋值运算也一并禁用掉。
所以这里的做法是:把复制构造函数和赋值运算符的声明设为 private 而不去实现。
实际上,更通用的做法是写一个类noncopyable,凡是继承该类的任何类都无法复制和赋值。Why?子类想要定义拷贝构造函数以及赋值运算符,却发现没有办法调用父类的拷贝构造函数以及赋值运算符。
7. The Need for virtual Destructors
无论如何,我们一定要将析构函数设置为 virtual,因为不这么做,很容易导致内存泄漏。来看以下例子:
Unless you have a specific reason not to, we highly recommend making all
methods, including destructors but not constructors, virtual. Constructors
cannot and need not be virtual because you always specify the exact class
being constructed when creating an object.
当然,将赋值运算符设置为 virtual 意义并不大,因为父类引用或者指针只能管到自己本身的数据成员。
INTERESTING AND OBSCURE INHERITANCE ISSUES WITH CPP的更多相关文章
-
mac 下的 homebrew
如果安装了macport 就不能安装homebrew ,必须先卸载macport $ sudo port -f uninstall installed$ sudo rm -rf \/opt/local ...
-
DependencyProperties or INotifyPropertyChanged ?
When you want to make an object binding-aware you have two choices : implements INotifyPropertyChang ...
-
PHP filesystem attack vectors
http://www.ush.it/2009/02/08/php-filesystem-attack-vectors/ On Apr 07, 2008 I spoke with Kuza55 and ...
-
Swift中面向协议的编程
什么是面向协议的编程? 面向协议的编程,是一种编程范式. 编程范式,是一个计算机科学用语.*中的解释是,计算机编程的基本风格或典型模式.通俗来说,就是解决某一个问题的方法不同方法和思路. 像大家 ...
-
为什么swift是面向协议的编程--对面向对象机制的改进
主要目标是提供抽象能力和解决值类型的多态问题 Actually, Abrahams says, those are all attributes of types, and classes are j ...
-
Spring Security(九):2.4.4 Checking out the Source(检查来源)
Since Spring Security is an Open Source project, we’d strongly encourage you to check out the source ...
-
ASP.NET 4.0 forms authentication issues with IE11
As I mentioned earlier, solutions that rely on User-Agent sniffing may break, when a new browser or ...
-
CF #365 (Div. 2) D - Mishka and Interesting sum 离线树状数组
题目链接:CF #365 (Div. 2) D - Mishka and Interesting sum 题意:给出n个数和m个询问,(1 ≤ n, m ≤ 1 000 000) ,问在每个区间里所有 ...
-
Think Python - Chapter 18 - Inheritance
In this chapter I present classes to represent playing cards, decks of cards, and poker hands.If you ...
随机推荐
-
web.xml中url-pattern的用法
目录结构: // contents structure [-] url-pattern的三种写法 servlet匹配原则 filter匹配原则 语法错误的后果 参考文章 一.url-pattern的三 ...
-
JVM内存管理------垃圾搜集器精解(让你在垃圾搜集器的世界里耍的游刃有余)
引言 在上一章我们已经探讨过hotspot上垃圾搜集器的实现,一共有六种实现六种组合.本次LZ与各位一起探讨下这六种搜集器各自的威力以及组合的威力如何. 为了方便各位的观看与对比,LZ决定采用当初写设 ...
-
centos初始配置
修改语言环境 [root@oracledb ~]# sudo vim /etc/sysconfig/i18n 将将zh_CH修改为"en_US.UTF-8" 搭建yum本地源 参考 ...
-
mysql-查询一天,一周,一月,一年,以及mysql的基本日期函数
查询一天: select * from table where to_days(column_time) = to_days(now()); select * from table where dat ...
-
10款Windows命令行工具
Windows下CMD不好用,远没有Linux,或者一些SSH工具用起来方便.其实Windows下,也有一些不错的工具替代CMD: 0.powercmd经过比较,我最终选择了这款,这里补充一下截图:
-
PAT (Advanced Level) 1062. Talent and Virtue (25)
简单排序.题意较长. #include<cstdio> #include<cstring> #include<cmath> #include<queue> ...
-
SpringBoot的第一个例子
1. 安装springboot的开发IDE,IntelliJ IDEA 2016.3.1这个工具,在IDE的官网上可以下载最新版本.https://www.jetbrains.com/idea/#ch ...
-
Less常用知识点
上篇文章介绍了如何安装Less,我们将所有东西都写在.less里面,最后通过命令将.less转换成.css文件,就可以放入到项目里用了.今天了解一些less常用知识点. 1.变量:声明两个变量,一个是 ...
-
yarn依赖管理工具的使用
Yarn是Facebook发布的一款依赖管理工具,它比npm更快.更高效. 与NPM命令对照 npm install => yarn install npm install --save [pa ...
-
【Git】 GitLab配置优化及汉化
GitLab配置 1.修改GitLab绑定的域名 a.修改/etc/gitlab/gitlab.rb配置文件,修改成自己的域名 external_url 'http://gitlab.example. ...