在 C++ 中实现 super 关键字
Objective-C 里面有一个 super
关键字,可以用来调用该类的父类,但是 C++ 里没有
我的工作历程是 C ==> Objective-C ==> C++,所以我的 OOP 习惯很大程度上是来自于 Objective-C 的。玩 C++ 的时候忽然就很不习惯了:因为没有 super
啊。于是就有了这篇文章。
本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
Reference
Using “super” in C++
C++ equivalent of “super”?
請問C++是否有類似super這樣的功能
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 也是如此)。但是无脑黑,反而说明程序员素养的低下。见识多了,任何语言我都不会黑,什么工具干什么事,什么语言自有什么设计模式和编程规范。当对一个语言足够了解了之后,它必然成为你手下的一刃利剑。