C++ 模拟 super 的那些事

By | 2015-06-04

撸过 Java 的应该都知道 super 的好用, 到了 C++ 世界, 一切都屎了

不过 C++ 是个擅长造轮子的语言, 于是, 也来造个 super 的轮子吧 (VC 的 __super 这里不表)


很容易就能想到的基础版本:

class Base {
public:
    virtual void func(void) {}
    virtual void func2(void) {}
};

class Child : public Base {
protected:
    typedef Base super;
public:
    virtual void func(void) {
        super::func();
    }
};

class GrandChild : public Child {
protected:
    typedef Child super;
public:
    virtual void func(void) {
        super::func();
    }
    virtual void func2(void) {
        super::func2();
    }
};

能解决大多数问题了, 注意这里的 GrandChild::func2, 已经能够自动匹配 Child 或者 Base 中的函数了

要方便一些的话可以用宏来自动生成 typedef

不过副作用就是, 万一其中一个父类忘记了 typedef, 很可能会出现意外的调用关系


大多数教程或问答也就停留于此了, 可惜 C++ 是个复杂的语言, 还有好多情况无法简单的用 typedef 解决

纯虚函数的情况:

让我们先来看看到底出了什么问题

class Base {
    virtual void func(void) = 0;
};

class Child : public Base {
    virtual void func(void) {
        super::func(); // Base::func() 未定义
    }
};

这个还好解决, 因为 C++ 在提供了纯虚函数的同时居然还允许定义纯虚函数, 于是, 解决方法大约是这样:

class Base {
    virtual void func(void) = 0;
};

class Child : public Base {
    virtual void func(void) {
        super::func(); // 这次没有问题了
    }
};
// 在某个 cpp 文件中
void Base::func(void) {} // 此处提供定义

嗯嗯, C++ 总是能出其不意的出现一些奇葩的语法和逻辑 (- -#)

此外, 据说还有种更加奇葩的写法: (未考证)

class Base {
    virtual void func(void) = 0
    {
    }
};

多继承的情况:

class Base {
};

class BaseInterface {
    virtual void func(void) {}
};

class Child : public Base, public BaseInterface {
    typedef Base super;
    virtual void func(void) {
        // super::func(); // 错误, Base 没有 func
        BaseInterface::func(); // 正确, 但是用不了 super 了
    }
};

class GrandChild : public Child {
    typedef Child super;
    virtual void func(void) {
        super::func(); // 正确, 这里又可以很酷的用 super 了
    }
};

(PS: 为什么会存在 Interface 设计却提供函数体呢? 因为可以简单粗暴的实现 "可选" 接口的功能)

除了不能愉快的使用 super 外, 多继承的情景对于 GrandChild 这种情况也比较繁琐

BaseInterface 的直接子类只能用 BaseInterface:: 进行调用, 然而二级子类却要明确的指定 Child:: (或文中的 super::) 进行调用, 当继承关系变化的时候这些内容就得全部重新修改

虽然这里不能愉快的使用 super 了, 不过还是有一个变通的方式来实现, 可以不用关心是否是二级子类:

首先你得有个能够在编译期判断某个类型是否是另一个类型的子类的东西, 形如

bool check = class_is_type_of(MyClass, TypeToCheck);

这部分本文不表, 请自行搜索

然后, 定义一个模板来根据继承关系判断最终所需的类型:

template<typename T_super, typename T_superInterface, int superAlsoImplInterface>
class _superT {
public:
    typedef T_superInterface SuperType;
};

template<typename T_super, typename T_superInterface>
class _superT<T_super, T_superInterface, 1> {
public:
    typedef T_super SuperType;
};

#define superT(T_superInterface) \
    _superT<super, T_superInterface, class_is_type_of(super, T_superInterface)>::SuperType

最后, 用起来的效果差不多是这样:

class Base {
};

class BaseInterface {
    virtual void func(void) {}
    virtual void func2(void) {}
};

class Child : public Base, public BaseInterface {
    typedef Base super;
    virtual void func(void) {
        superT(BaseInterface)::func(); // 正确, 调用 BaseInterface::func
    }
};

class GrandChild : public Child {
    typedef Child super;
    virtual void func(void) {
        superT(BaseInterface)::func(); // 正确, 调用 Child::func
    }
    virtual void func2(void) {
        superT(BaseInterface)::func2(); // 正确, 调用 BaseInterface::func2
    }
};

不过这种情况比较少出现, 而且仅适用于单根继承+interface体系

转载请注明来自: http://zsaber.com/blog/p/40

既然都来了, 有啥想法顺便留个言呗? (无奈小广告太多, 需审核, 见谅)

Category: C++

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注