当前位置:  开发笔记 > 编程语言 > 正文

在C++中使用"super"

如何解决《在C++中使用"super"》经验,为你挑选了8个好方法。

我的编码风格包括以下习语:

class Derived : public Base
{
   public :
      typedef Base super; // note that it could be hidden in
                          // protected/private section, instead

      // Etc.
} ;

这使我能够使用"super"作为Base的别名,例如,在构造函数中:

Derived(int i, int j)
   : super(i), J(j)
{
}

或者甚至在其重写版本中从基类调用方法时:

void Derived::foo()
{
   super::foo() ;

   // ... And then, do something else
}

它甚至可以链接(我仍然可以找到它的用途):

class DerivedDerived : public Derived
{
   public :
      typedef Derived super; // note that it could be hidden in
                             // protected/private section, instead

      // Etc.
} ;

void DerivedDerived::bar()
{
   super::bar() ; // will call Derived::bar
   super::super::bar ; // will call Base::bar

   // ... And then, do something else
}

无论如何,我发现使用"typedef super"非常有用,例如,当Base是详细和/或模板时.

事实上,super是用Java实现的,也是用C#实现的(除非我错了,否则称为"base").但是C++缺少这个关键字.

所以,我的问题:

这是使用typedef超常见/稀有/从未在您使用的代码中看到过吗?

这是使用typedef super Ok(即你是否看到强大或不那么强烈的理由不使用它)?

应该"超级"是一件好事,它应该在C++中有些标准化,还是已经足够使用typedef?

编辑:罗迪提到了typedef应该是私有的事实.这意味着任何派生类都无法在不重新声明的情况下使用它.但我想这也会阻止super :: super chaining(但是谁会为此而哭?).

编辑2:现在,在大量使用"超级"之后的几个月,我全心全意地赞同罗迪的观点:"超级"应该是私人的.我会两次回答他的答案,但我想我不能.



1> Max Lybbert..:

Bjarne Stroustrup在C++的设计和演变中提到,super作为关键词,ISO C++标准委员会首次考虑C++是标准化的.

Dag Bruck提出了这个扩展,称基类为"继承".该提案提到了多重继承问题,并且会标记含糊不清的用法.甚至Stroustrup也深信不疑.

经过讨论,Dag Bruck(是的,提出提案的人)写道,该提案是可实现的,技术上合理,没有重大缺陷,并处理多重继承.另一方面,没有足够的收益,委员会应该处理棘手的问题.

Michael Tiemann迟到了,然后表明一个typedef'ed super会工作得很好,使用的技术与本文中提到的相同.

所以,不,这可能永远不会标准化.

如果您没有副本,Design and Evolution非常值得支付.使用过的副本大约需要10美元.


`typedef`技术存在一个主要缺陷:它不尊重DRY.唯一的方法是使用丑陋的宏来声明类.继承时,base可能是一个很长的多参数模板类,或者更糟.(例如多课程)你必须第二次重写所有这些.最后,我看到模板库有一个很大的问题,它有模板类参数.在这种情况下,super是模板(而不是模板的instanciation).哪个不能打字.即使在C++ 11中,对于这种情况你也需要`using`.
D&E确实是一本好书.但似乎我需要重新阅读它 - 我不记得这两个故事.
我记得在D&E中讨论过的三个未被接受的功能.这是第一个(在索引中查找"Michael Tiemann"查找故事),两周规则是第二个(在索引中查找"两周规则"),第三个是命名参数(查找"命名参数"在索引中".

2> Roddy..:

我总是使用"继承"而不是超级.(可能是由于Delphi背景),并且我总是把它设为私有,以避免在类中错误地省略'inherited'但子类试图使用它时的问题.

class MyClass : public MyBase
{
private:  // Prevents erroneous use by other classes.
  typedef MyBase inherited;
...

我用于创建新类的标准"代码模板"包括typedef,因此我几乎没有机会忽略它.

我不认为链接的"超级超级"建议是个好主意 - 如果你这样做,你可能很难与特定的层次结构联系起来,而改变它可能会严重破坏它.


至于"私人",好建议.+ 1.
在我几个月之后,我被转换为你的观点(而且我有一个错误,因为一个被遗忘的"超级",就像你提到的那样......).你的答案非常正确,包括链接,我猜.^ _ ^ ......
至于链接super :: super,正如我在问题中提到的那样,我仍然会找到一个有趣的用途.现在,我只把它看成是一个黑客,但值得一提,如果只是因为与Java的差异(你不能链"超级").

3> Kristopher J..:

这样做的一个问题是,如果你忘记(重新)为派生类定义super,那么对super :: something的任何调用都可以正常编译,但可能不会调用所需的函数.

例如:

class Base
{
public:  virtual void foo() { ... }
};

class Derived: public Base
{
public:
    typedef Base super;
    virtual void foo()
    {
        super::foo();   // call superclass implementation

        // do other stuff
        ...
    }
};

class DerivedAgain: public Derived
{
public:
    virtual void foo()
    {
        // Call superclass function
        super::foo();    // oops, calls Base::foo() rather than Derived::foo()

        ...
    }
};

(正如Martin York在对这个答案的评论中指出的那样,可以通过使typedef为私有而不是公共或受保护来消除这个问题.)


这是通过制作超级私有typedef来解决的.
但是,私有typedef会阻止原始帖子中提到的链式使用.

4> 小智..:

FWIW Microsoft已在其编译器中添加了__super的扩展名.


我正在开发一个Windows应用程序,并喜欢__super扩展.令我感到遗憾的是,标准委员会拒绝了它,支持这里提到的typedef技巧,因为虽然这种typedef技巧很好,但是当你改变继承层次结构时,它需要比编译器关键字更多的维护,并正确处理多个继承(不需要两个) typedef,如super1和super2).简而言之,我同意另一个评论员认为MS扩展非常有用,任何使用Visual Studio的人都应该强烈考虑使用它.

5> Colin Jensen..:

超级(或继承)是非常好的事情,因为如果你需要在Base和Derived之间粘贴另一个继承层,你只需要改变两件事:1."class Base:foo"和2. typedef

如果我没记错的话,C++标准委员会正在考虑为此添加一个关键字......直到Michael Tiemann指出这种类型的def技巧有效.

至于多重继承,因为它在程序员控制下你可以做任何你想做的事:也许是super1和super2,或者其他什么.



6> paperjam..:

我刚刚找到了另一种解决方法.我有一个关于typedef方法的一个大问题,今天让我感到困惑:

typedef需要类名的精确副本.如果有人更改了类名但没有更改typedef,那么您将遇到问题.

所以我想出了一个使用非常简单的模板的更好的解决方案.

template 
struct MakeAlias : C
{ 
    typedef C BaseAlias;
};

所以现在,而不是

class Derived : public Base
{
private:
    typedef Base Super;
};

你有

class Derived : public MakeAlias
{
    // Can refer to Base as BaseAlias here
};

在这种情况下,BaseAlias不是私密的,我试图通过选择应提醒其他开发人员的类型名称来防止粗心使用.


`public`别名是一个缺点,因为你对[Roddy's](http://stackoverflow.com/a/180634/264047)和[Kristopher's](http://stackoverflow.com/a)中提到的bug持开放态度./180627/264047)答案(例如,你可以(错误地)派生自`派生'而不是'MakeAlias <派生>`)
您也无法访问初始化列表中的基类构造函数.(这可以在C++ 11中使用`MakeAlias`中的继承构造函数或完美转发来补偿,但它确实需要您引用`MakeAlias `构造函数而不是直接引用`C`的构造函数.)

7> Michael Burr..:

我不记得以前见过这个,但乍一看我喜欢它.正如Ferruccio指出的那样,面对MI,它并不能很好地发挥作用,但是MI更像是一个例外而不是规则,并且没有任何东西可以说任何东西都需要在任何地方都可以使用.


Upvote只是为了这句话,"没有任何东西可以说某些东西需要在任何地方都可以使用才有用."

8> Konrad Rudol..:

我已经在许多代码中看到了这个习惯用法,我很确定我甚至在Boost的库中看到过它.但是,据我记得,最常见的名字是base(或Base)而不是super.

如果使用模板类,这个习惯用法特别有用.作为示例,请考虑以下类(来自实际项目):

template 
class Finder >, PizzaChiliFinder>
    : public Finder >, Default>
{
    typedef Finder >, Default> TBase;
    // …
}

不要介意有趣的名字.这里重要的一点是继承链使用类型参数来实现编译时多态.不幸的是,这些模板的嵌套级别非常高.因此,缩写对于可读性和可维护性至关重要.

推荐阅读
贴进你的心聆听你的世界
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有