222

私のコーディング スタイルには、次のイディオムが含まれます。

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 は C# だけでなく Java にも実装されています (私が間違っていない限り、"base" と呼ばれています)。しかし、C++ にはこのキーワードがありません。

だから、私の質問:

  • このtypedefの使用は、使用するコードで非常に一般的/まれ/決して見られませんか?
  • この typedef super の使用は OK ですか?
  • 「スーパー」は良いことなのか、C++である程度標準化されるべきなのか、それともtypedefを介したこの使用はすでに十分なのか?

編集: Roddy は、typedef は非公開にする必要があるという事実に言及しました。これは、派生クラスがそれを再宣言しないと使用できないことを意味します。しかし、それはまた、super::super 連鎖を防ぐことになると思います (しかし、誰が泣くのでしょうか?)。

編集 2: "super" を大量に使用してから数か月が経ちましたが、Roddy の見解に心から同意します。「super」はプライベートであるべきです。私は彼の答えに2回賛成しますが、できないと思います。

4

19 に答える 19

173

Bjarne Stroustrup はDesign and Evolution of C++super、C++ が初めて標準化されたときに ISO C++ 標準委員会によってキーワードとして検討されたことについて言及しています。

Dag Bruck はこの拡張機能を提案し、基本クラスを「継承」と呼んでいます。提案では多重継承の問題に言及しており、あいまいな使用法にフラグを立てていました。Stroustrup でさえ確信していました。

議論の後、Dag Bruck (はい、提案を行ったのと同じ人物) は、提案は実装可能であり、技術的に健全であり、大きな欠陥がなく、多重継承を処理したと書いています。一方で、費用対効果が十分ではなく、委員会はより厄介な問題を処理する必要があります。

Michael Tiemann は遅れて到着し、この投稿で質問されたのと同じ手法を使用して、型定義されたスーパーが問題なく機能することを示しました。

いいえ、これはおそらく標準化されることはありません。

コピーを持っていない場合、Design and Evolutionはカバー価格の価値があります。使用済みのコピーは約 10 ドルで入手できます。

于 2008-10-07T22:00:31.997 に答える
112

スーパーではなく、常に「継承」を使用してきました。(おそらくDelphiのバックグラウンドが原因です)、「継承された」がクラスから誤って省略されたが、サブクラスがそれを使用しようとした場合の問題を回避するために、私は常にそれをprivateにしています。

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

新しいクラスを作成するための標準の「コード テンプレート」には typedef が含まれているため、誤ってそれを省略する機会はほとんどありません。

チェーン化された「super::super」の提案は良い考えではないと思います。そうしている場合、おそらく特定の階層に非常に固く結び付けられており、それを変更するとひどく壊れる可能性があります。

于 2008-10-07T22:00:36.537 に答える
39

これに関する 1 つの問題は、派生クラスの 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 を public または protected ではなく private にすることで解消できます。)

于 2008-10-07T21:59:03.797 に答える
21

FWIW Microsoftは、コンパイラに__superの拡張機能を追加しました。

于 2008-10-07T22:51:55.153 に答える
15

Super (または継承) は非常に優れた機能です。なぜなら、Base と Derived の間に別の継承レイヤーを挿入する必要がある場合は、1.「class Base: foo」と 2. typedef の 2 つを変更するだけでよいからです。

私の記憶が正しければ、C++ 標準委員会はこれにキーワードを追加することを検討していました... Michael Tiemann がこの typedef トリックが機能することを指摘するまで。

多重継承に関しては、プログラマーの制御下にあるため、好きなことを行うことができます。たとえば、super1 と super2 などです。

于 2008-10-07T22:00:46.397 に答える
14

これは前に見た記憶がありませんが、一目で気に入りました。Ferruccioが指摘しているように、MI の前ではうまく機能しませんが、MI はルールというよりも例外であり、有用であるためにどこでも使用可能である必要があると言うものは何もありません。

于 2008-10-07T21:54:17.877 に答える
13

別の回避策を見つけました。今日私を悩ませたtypedefアプローチには大きな問題があります。

  • typedef には、クラス名の正確なコピーが必要です。誰かがクラス名を変更しても typedef を変更しない場合、問題が発生します。

そこで、非常に単純なテンプレートを使用して、より良い解決策を思いつきました。

template <class C>
struct MakeAlias : C
{ 
    typedef C BaseAlias;
};

だから今、代わりに

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

あなたが持っている

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

この場合、BaseAliasはプライベートではなく、他の開発者に警告する型名を選択することで、不注意な使用を防ごうとしました。

于 2011-04-11T14:22:32.767 に答える
10

このイディオムが多くのコード ベースで採用されているのを見てきました。また、Boost のライブラリのどこかで見たことがあると確信しています。ただし、私が覚えている限り、最も一般的な名前はではなくbase(またはBase) ですsuper

このイディオムは、クラス テンプレートを操作する場合に特に役立ちます。例として、次のクラスを考えてみましょう (実際のプロジェクトから):

template <typename TText, typename TSpec>
class Finder<Index<TText, PizzaChili<TSpec>>, MyFinderType>
    : public Finder<Index<TText, MyFinderImpl<TSpec>>, Default>
{
    using TBase = Finder<Index<TText, MyFinderImpl<TSpec>>, Default>;
    // …
}

継承チェーンは、型引数を使用してコンパイル時のポリモーフィズムを実現します。残念ながら、これらのテンプレートのネスト レベルは非常に高くなります。したがって、完全な型名の意味のある省略形は、読みやすさと保守性にとって非常に重要です。

于 2008-10-08T09:17:16.953 に答える
4

このtypedefの使用は、使用するコードで非常に一般的/まれ/決して見られませんか?

私が使用している C++ コードでこの特定のパターンを見たことはありませんが、それが存在しないという意味ではありません。

この typedef super の使用は OK ですか?

多重継承は許可されていません (とにかくきれいに)。

「スーパー」は良いことなのか、C++である程度標準化されるべきなのか、それともtypedefを介したこの使用はすでに十分なのか?

上記の理由(多重継承)のため、いいえ。リストした他の言語で「スーパー」と表示される理由は、それらが単一継承のみをサポートしているためであり、「スーパー」が何を指しているのかについて混乱はありません。確かに、これらの言語では便利ですが、C++ データ モデルでは実際には場所がありません。

参考までに、C++/CLI はこの概念を「__super」キーワードの形でサポートしています。ただし、C++/CLI も多重継承をサポートしていないことに注意してください。

于 2008-10-07T21:59:53.670 に答える
4

ベースが複雑なテンプレート型である場合に、super_t として使用されることがよくあります (boost::iterator_adaptorたとえば、これを行います)。

于 2008-10-07T21:52:59.143 に答える
3

スーパークラスに typedef を使用するもう 1 つの理由は、オブジェクトの継承で複雑なテンプレートを使用している場合です。

例えば:

template <typename T, size_t C, typename U>
class A
{ ... };

template <typename T>
class B : public A<T,99,T>
{ ... };

クラス B では、A の typedef を持つことが理想的です。そうしないと、A のメンバーを参照したいすべての場所でそれを繰り返すことになります。

これらの場合、多重継承でも​​機能しますが、「super」という名前の typedef はなく、「base_A_t」などと呼ばれます。

--ジェフク++

于 2008-10-07T22:22:43.247 に答える
2

昔、Turbo Pascal から C++ に移行した後、同じように機能する Turbo Pascal の "inherited" キーワードに相当するものを用意するために、これを行っていました。しかし、数年間 C++ でプログラミングした後、やめました。私はそれをあまり必要としないことに気づきました。

于 2008-10-07T21:56:49.867 に答える
1

私は時々これを使用します。基本クラスの型を数回入力していることに気付いたときに、それをあなたのものと同様の typedef に置き換えます。

いい使い方ができると思います。あなたが言うように、基本クラスがテンプレートであれば、入力を節約できます。また、テンプレート クラスは、テンプレートの動作方法に関するポリシーとして機能する引数を取る場合があります。ベースのインターフェースが互換性を保っている限り、ベース タイプへのすべての参照を修正する必要なく、ベース タイプを自由に変更できます。

typedef での使用はもう十分だと思います。とにかく、多重継承は多くの基底クラスが存在する可能性があることを意味するため、それが言語にどのように組み込まれるかわかりません。そのため、論理的に最も重要な基底クラスであると感じるクラスに適合するように型定義できます。

于 2008-10-07T21:57:45.887 に答える
1

珍しいかどうかはわかりませんが、確かに同じことをしたことがあります。

指摘されているように、言語自体のこの部分を作成することの難しさは、クラスが多重継承を利用する場合です。

于 2008-10-07T21:55:39.513 に答える
0

これは、typedef の代わりにマクロを使用する方法です。これが C++ のやり方ではないことはわかっていますが、階層の最も下にある基本クラスのみが継承されたオフセットに作用している場合に、継承によって反復子を連鎖させる場合に便利です。

例えば:

// some header.h

#define CLASS some_iterator
#define SUPER_CLASS some_const_iterator
#define SUPER static_cast<SUPER_CLASS&>(*this)

template<typename T>
class CLASS : SUPER_CLASS {
   typedef CLASS<T> class_type;

   class_type& operator++();
};

template<typename T>
typename CLASS<T>::class_type CLASS<T>::operator++(
   int)
{
   class_type copy = *this;

   // Macro
   ++SUPER;

   // vs

   // Typedef
   // super::operator++();

   return copy;
}

#undef CLASS
#undef SUPER_CLASS
#undef SUPER

私が使用する一般的なセットアップにより、コードが重複しているが、戻り値の型が現在のクラスと一致する必要があるため、オーバーライドする必要がある継承ツリー間での読み取りとコピー/貼り付けが非常に簡単になります。

Java で見られる動作を再現するために小文字を使用することもできますsuperが、私のコーディング スタイルでは、マクロにはすべて大文字を使用します。

于 2016-02-15T23:18:08.030 に答える
0

__super キーワードを使用します。しかし、それはマイクロソフト固有のものです:

http://msdn.microsoft.com/en-us/library/94dw1w7x.aspx

于 2008-10-08T09:12:20.863 に答える