在 C++ 中实现 super 关键字

Objective-C 里面有一个 super 关键字,可以用来调用该类的父类,但是 C++ 里没有。

我的工作历程是 C ==> Objective-C ==> C++,所以我的 OOP 习惯很大程度上是来自于 Objective-C 的。玩 C++ 的时候忽然就很不习惯了:因为没有 super 啊。于是就有了这篇文章。

本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

原文发布于:https://segmentfault.com/a/1190000010105061,同为本人的专栏。

Reference


C++ 有 super 关键字吗?


根据参考资料,其实 C++ 在设计之初是有考虑 super 关键字的。

StackOverflow 上有人回答:Bjarne Stroustrup 在《Design and Evolution of C++》一书中提到,super 作为一个关键字,在 C++ 一开始进行标准化的时候,曾经被 ISO C++ 委员会考虑。

(原文:Bjarne Stroustrup mentions in Design and Evolution of C++ that super as a keyword was considered by the ISO C++ Standards committee the first time C++ was standardized.)

但是为什么不使用 super 呢?主要是因为 多重继承 这一 C++ 特性。如果一个 class 有多个 父类,那么使用 super 的语义就不清晰了。所以,最终 C++ 标准出来之后,就取消了 super 这个关键字。

使用 super 的好处


目前我看到所有网上的文章,都提到要调用父类的同名成员函数时,可以直接使用父类的类名就可以完成问题了。那么似乎这就是最好的解决方案了。那什么时候需要用 super 呢?

请看下面的一个例子:

比如在某个项目中,有一个父类 PrototypeClass,因应这个父类,继承了十数十个子类出来,比如 DerivedAlpha, DerivedBrabo, DerivedCharlie, ..... 如下:

PrototypeClass
    +--> DerivedAlpha
    +--> DerivedBrabo
    +--> DerivedCharlie
    ......

突然某一天,我们需要在这数十个子类中,有十几个类需要增加某个公有的成员函数 newFunc(),其实现都是一样的。我不想把一模一样的代码复制粘贴十几次(不好维护),于是我自然而然地想到:在父类实现就好了。

但是问题来了:如果在父类增加实现,自然影响到其他不需要 newFunc()的类。于是解决方法就是,添加一个 PrototypeClass 的子类 DerivedMama,实现 newFunc(),并且将这十几个类设置为该新类的子类。继承关系就变成这样:

PrototypeClass
    +--> DerivedAlpha
    +--> DerivedMama                # 实现了 newFunc()
    |       +--> DerivedBrabo
    |       +--> DerivedCharlie
    ...     ...
    +--> DerivedDelta
    ......

麻烦来了,这些个派生类中,或多或少调用了父类的实现 PrototypeClass::someFunc(),如果变成上图的关系的话,PrototypeClass 变成了这些类的 祖父类。按照继承的关系来说,调用祖父类的实现是不推荐的。

这就需要我们在 C++ 的代码里,除了修改相关类的父类之外,一个一个地在类的实现里修改父类名出现的位置。人工操作总有可能出错。这就是 super 关键字的作用。

在 C++ 中使用 super


解决方法很简单,以 DerivedBrabo 类为例,在 DerivedBrabo.h 文件中这么写:

#ifndef __DERIVED_BRAVO_H__
#define __DERIVED_BRAVO_H__

#include "DerivedMama.h"

namespace blahblah
{
    #define super DerivedMama
    class DerivedBrabo : public super {
        ......
    }
    #undef super

    // other classes if any
    ......
    
}    // end of namespace blahblah


#endif    // end of __DERIVED_BRAVO_H__
// end of file

不过事实上,由于 .h 文件经常会被其他文件包含,可能会出现一些不规范的包含方式导致重复定义;此外,宏定义也有一些老生常谈的风险。

所以比较好的方法是将类的声明与实现分开,所有的实现都放在 .cpp 文件中定义。这样的话,可以在 .cpp 文件的开头,作以下定义:

typedef DerivedMama super;

这就解决了一些安全问题,也可以把 super 的作用域限制在本文件内。

后记


C 是一个无所不能的语言,而其承继者 C++ 毫不示弱,在一些领域中往往是青出蓝而胜蓝。并不是 C++ 不能用 super。实际上只要对程序设计有足够的了解,是完全可以做到的。

C++ 经常被黑,正是因为它的强大、自由(嗯,C 也是如此)。但是无脑黑,反而说明程序员素养的低下。见识多了,任何语言我都不会黑,什么工具干什么事,什么语言自有什么设计模式和编程规范。当对一个语言足够了解了之后,它必然成为你手下的一刃利剑。


本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

原文发布于:https://segmentfault.com/a/1190000010105061,同为本人的专栏。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java思维导图

自下向上的编写容易阅读的代码(上)

我在 关于极简编程的思考 中曾提到要编写可阅读的代码。因为代码是编写一次,阅读多次。 阅读者包括代码编写者,以及后来的维护人员。能让阅读代码更轻松,有利于增强项...

3438
来自专栏编程

浅谈Java学习方法和后期面试技巧 含学习笔记

下面简单列举一下大家学习java的一个系统知识点的一些介绍: 一、java基础部分:java基础的时候,有些知识点是非常重要的,比如循环系列。For,while...

1988
来自专栏Crossin的编程教室

【Python 第59课】 正则表达式(5)

听说有人已经开始国庆假期了,甚至还有人中秋之后就请了年假一休到底,表示羡慕嫉妒恨!今天发完这课,我也要进入休假状态,谁也别拦着我。 来说上次的习题: (021...

3238
来自专栏老九学堂

如何零基础学习一门编程语言?

每种编程语言必然有其优点和缺点,这也决定了它有适合的应用场景和不适合的应用场景。现代软件行业,想一门编程语言包打天下是不现实的。这中现状也造成了一种现象,一个程...

1524
来自专栏北京马哥教育

国家认证的Python工程师有什么能力要求?

Python这门语言近来是越来越火,在国家层面越来越被重视。除了之前热议的加入高考和中小学教育之外,现在连普通大学生也无法逃脱Python的毒手了。

2250
来自专栏Android 开发者

[译] Kotlin 揭秘:理解并速记 Lambda 语法

在奥地利旅行期间,我参观了维也纳的奥地利国家图书馆。特别是国会大厅,这个令人惊叹的空间感觉就像印第安纳琼斯电影中的一些东西。房间周围的空间是这些门被装在架子上,...

850
来自专栏维C果糖

编程思想 之「语言导论」

Java 是一门面向对象编程语言,它不仅吸收了 C++ 语言的各种优点,还摒弃了 C++ 里难以理解的多继承、指针等概念,因此 Java 语言具有功能强大和简单...

44819
来自专栏码洞

编程的智慧

编程是一种创造性的工作,是一门艺术。精通任何一门艺术,都需要很多的练习和领悟,所以这里提出的“智慧”,并不是号称一天瘦十斤的减肥药,它并不能代替你自己的勤奋。然...

531
来自专栏ACM小冰成长之路

KWIC-C/C++实现

吐槽 最近我们 JavaJava 老师不知道为啥非要我用 C/C++C/C++ 来实现 KWICKWIC,但是因为没有上过课,不知道这个东西是干嘛的,所以想网上...

22210
来自专栏Java技术栈

跟我学 Java 8 新特性之 Stream 流(四)并行流

在开始讨论并行流之前,我先引发一下大家的思考,就你看到这篇文章的时间,你们是不是经常听到,Intel i7 CPU什么8核16线程,什么Android手机8核4...

822

扫码关注云+社区