4

私はつまりC++プログラマーであり、C++では次のようなことができます。

class SuperSuper
{
    virtual void newItem()=0;
}

class SubSuperA:public SuperSuper
{
     virtual void newItem()
     {
         //do something
     }
}

class SubSuperB:public SuperSuper
{
     virtual void newItem()
     {
         //do something different (disappear! :)
     }
}

template <class T>
class SubSub:public T
{
    virtual void newItem()
    {
         T::newItem();
         //do a third thing
    }
}

これをJavaでやりたいのですが、(少なくとも直接)それは不可能だと感じています。

次のように、Javaで最初の3つのクラスを簡単に設定します。

public abstract class SuperSuper
{
    abstract void newItem(Item item);
}

public class SubSuperA extends SuperSuper
{
    @Override void newItem(Item item)
    {
        //stuff
    }
}

public class SubSuperB extends SuperSuper
{
    @Override void newItem(Item item)
    {
        //other stuff
    }
}
//SubSuperC,D,etc

そして現在、そのように4番目を実装しています:

SubSuperA sa=new SubSuperA() {
    @Override public void newItem(Item item)
    {
        super.newItem(item);
        //A lot of stuff that will be changing constantly throughout development
    }
};

SubSuperB sb=new SubSuperB() {
    @Override public void newItem(Item item)
    {
        super.newItem(item);
        //A lot of stuff that will be changing constantly throughout development
    }
};

両方のオーバーライドが同じ機能であることに注意してください。それがどのSubSuper*に基づいているかに関係なく、置換newItem()は同一です。明らかに、これは維持するのに悪夢です。私はこのようなSubSubクラスを宣言できることを望んでいました

 public class SubSub<T> extends T {
    @Override public void newItem(Item item)
    {
        super.newItem(item);
        //A lot of stuff that will be changing constantly throughout development
    }
 }

このようにインスタンス化できます

 SubSub ss=new SubSub<SubSuperA>

など...しかし、Javaでのこのエラー:

"Cannot refer to the type parameter T as a supertype."

私はそのエラーに基づいて周りを見回し、Generic Supertypeからの拡張を見つけましたか?これは、私がやりたいことはその方法では不可能だと主張しています。

私が実際に行う必要があること:ツイートの受信や保存などを処理するだけのプラットフォームに依存しないTwitterクライアントがあります。さまざまな種類の列(SubSuper)に拡張できる抽象Columnクラス(SuperSuper)があります(ホームタイムライン、メンションなど)、それぞれがnewItem()に表示するツイートを除外します。さまざまなプラットフォーム用にさまざまなGUIをプラグインできるようにしたいので、クライアントがGUI固有の関数(SubSub)を呼び出して、個々のツイートをGUIライブラリに追加する処理を行う必要があります。任意のColumn派生クラスを拡張できるGUI固有のクラスを持つことが理想的なソリューションになります

どうやらこの直接実装はJavaでは不可能なので、かなり似たようなものを実現する構文上のトリックがあるのか​​、それともSuperSuperとSuperSub*によって保存および呼び出されるインターフェイスの作成をやめるべきなのか疑問に思います。 SubSubの代わりにGUIハンドラーによって実装されます。

4

3 に答える 3

2

テンプレートは、Javaのジェネリックを使用して可能です。ただし、Javaでは、インターフェイスは継承よりもはるかに一般的です。これは、Javaが多重継承をサポートしていないためです。

C ++では、複数のクラスを拡張できます。

class X : public A, public B, private C { }

C ++は仮想クラスと非仮想クラスを区別せず、仮想メンバーと非仮想メンバーのみを区別するため、仮想メソッドを持つクラスと持たないクラスを正式に区別することはできません。

一方、Javaには3つの異なるクラスタイプがあります。

  • 具体的(完全に非仮想、すべてのメソッドは具体的)
  • 抽象(部分的に仮想、部分的に非仮想)
  • インターフェイス(完全に仮想、具体的なメソッドなし)

Javaでは、仮想メソッドは抽象メソッドと呼ばれるので、ここではそれらを抽象メソッドと呼びます。

Javaにはジェネリックもあります。ジェネリックスは構文的にはテンプレートに似ていますが、実装の点で完全に異なります。実装調査はお任せします(検索で使用するキーワードは「消去」です)。

ジェネリックはクラスで宣言されます。たとえば、JavaのC++に相当するものvectorArrayListクラスです。その使用法は非常に似ています:

List<String> strs = new ArrayList<String>();

ここに、Listの一種のスーパータイプがありArrayListます。Listはインターフェースであり、それをArrayList実装します。Listそれ自体は、次のように宣言でジェネリック型を宣言します。

public interface List<E> ... {

    // ...

    E get(int index);

    // ...
}

getどのように戻るかに注意してくださいE。ここでEは、具体的に定義されていません。これはジェネリック型であり、この場合、その代わりに、、、、、独自のクラスなど、何でも使用できますStringObjectBoolean

ArrayListを実装Listし、ジェネリック型も宣言します。

public ArrayList<E> implements List<E>, ... {

    // ...

    public E get(int index) {
        // bounds check
        return elements[i];
    }

    // ...
}

タイプバウンディングを使用して、ジェネリックスのタイプを制限することもできます。必要なのは実際にはジェネリックではないため、これはこの範囲を少し超えています。インターフェイスが必要です。

あなたの例では、最初に。でインターフェースを宣言しますnewItem

public interface A {
    void newItem();
}

すべてのメソッドは、具体的な実装またはインターフェースから取得する必要があるため、このインターフェースが必要です。具体的には、このインターフェイスはと同等SuperSuperです。これは完全に仮想的なクラス(インターフェース)です。今あなたのクラスのために:

public class B implements A {
    @Override
    public void newItem() {
        // Do something
    }
}

public class C implements A {
    @Override
    public void newItem() {
        // Do something else
    }
}

最後に、C ++の経験があまりない私のような人には少し混乱がありますが、あなたが言っていることは、newItemメソッドを使用してテンプレート型を作成したいということだと思います。Javaでは、これはAインターフェースの別の実装であるか、BまたはCを拡張してそれらのメソッドをオーバーライドすることができます。

public class D extends B {
    @Override
    public void newItem() {
        // And yet another something else
    }
}

次に、メソッドで何かを使用するのnewItemは次のように簡単です。

A a = new B(); // or "new C()" or "new D()"
a.newItem();

あなたが言うことができるように

SuperSuper* a = new SubSuperA();

Javaでは、上記で行ったように、インターフェース、抽象クラス、および具象クラスで同じことを行うことができます。

ですから、インターフェースがあなたの問題の解決策だと思います。Javaでインターフェースがどのように使用されているかを読むことを強くお勧めします。多重継承がなく、強力なタイピングを提供します。いくつかのリンクがすぐに見つかります。

それらの助けを願っています。説明が必要な場合はお知らせください。

于 2012-09-18T02:13:11.230 に答える
1

できません。

C++ テンプレートは、実際にはソース コードの「テンプレート」です。テンプレート クラスまたは関数がある場合、型引数として使用される型ごとに、コンパイラはソース コードの個別のコピーを効果的に生成 ("インスタンス化") し、型パラメーターを実際の型引数に置き換えます。したがって、たとえば、vector<int>vector<string>は完全に別の型であり、それらの関数のコンパイル済みコードも同様に別である可能性があります (まるで別の型であるかのように)。

そのため、型パラメーターからの継承などを行うことができます。Tコンパイラにとっては、それが見えるすべての型引数を置き換えるだけです。結果のコードは有効であるため、機能します。

Java のジェネリックは大きく異なります。ジェネリック クラスまたはメソッドのコンパイル済みコードのコピーは 1 つだけです。コンパイルされたコードのその 1 つのバージョンは、同時に、その範囲内にある可能性のある型パラメーター (既存または将来) に対して機能する必要があります。

ですから、あなたが提案していることを実行できるとしたら、それが何を意味するかを考えてみてください。クラス のコンパイル済みコードのコピーが 1 つだけあり、それが何であれSubSub、それを継承します。したがって、すべての型Tを同時に継承する必要があります。そんなことがあるものか?クラスは、明確な親クラスを 1 つだけ持つことができます。

于 2012-09-25T05:23:06.860 に答える
0

Javaコードに基づいて、デコレータパターンが本当に必要だと思います。

public class SubSub<T extends SuperSuper> extends SuperSuper {

     private final Class<T> clazz;

     public SubSub(Class<T> clazz){
         this.clazz = clazz;
     }

     @Override
     public void newItem(Item item){
          T sup = clazz.newInstance();
          sup.newItem(item);
          // other stuff
     }
}

次のような呼び出しで:

SubSub<SubSuperA> foo = new SubSub<SubSuperA>(SubSuperA.class);

たとえば、クラスの名前をパラメータとして渡すだけの場合は、ジェネリックを完全に取り除くことができます。

public class SubSub extends SuperSuper {

     private final SuperSuper _super;

     public <T extends SuperSuper> SubSub(Class<T> clazz){
         _super = clazz.newInstance();
     }

     @Override
     public void newItem(Item item){
          _super.newItem(item);
          sup.newItem(item);
          // other stuff
     }
}

フォームのインスタンス化:

SubSub foo = new SubSub(SubSuperA.class);

また:

SubSub foo = new SubSub((Class<SuperSuper>) Class.forName("SubSuperA"));
于 2012-09-18T03:15:44.017 に答える