2011-12-14 8 views
0

TicTacToe、Othello、Checkersなどの複数のターンベースのゲームをプレイするJavaのアルゴリズムは、ジェネリックス(自己境界型)は、ゲームごとに特別に変更することなく、同じアルゴリズムを使用できるようにします。自己境界型を使用する理由はここでは示されていませんが、評価関数には必要です。Javaジェネリックスと同等の機能を実装する方法C++テンプレート内の自己バインド型

public interface Game<GAME extends Game<GAME>> { 
    GAME copy(); 
    int getCurPlayer(); 
    ... 
} 

public class TicTacToe implements Game<TicTacToe> { 
    ... 
    @Override 
    public TicTacToe copy() { 
     ... 
    } 
    @Override 
    public int getCurPlayer() { 
     ... 
    } 
    ... 
} 

今日、学習のために、C++テンプレートを使用してJavaコードをC++に移動しようとしました。

これは私のアプローチであり、明らかに動作しませんでした。

Game.h

template <typename T> 
class Game 
{ 
    public: 
     virtual T copy() const = 0; 
     virtual int cur_player() const = 0; 
     ... 
}; 

TicTacToe.h

class TicTacToe : public Game<TicTacToe> 
{ 
public: 
    virtual TicTacToe copy() const; 
    virtual int cur_player() const; 
    ... 
}; 

TicTacToe.cpp

TicTacToe TicTacToe::copy() { 
    ... 
} 

int TicTacToe::cur_player() { 
    ... 
} 

私がコンパイルしようとすると、私が得るエラーは以下のとおりです。

out-of-line definition of 'copy' does not match any declaration in 'TicTacToe' 

out-of-line definition of 'cur_player' does not match any declaration in 'TicTacToe' 

... など、その他の純粋仮想関数のそれぞれについて同じです。

+1

動作しなかったことは決して言わないでください。 – Puppy

+0

それがうまくいかない理由は明白ではありません。あなたが抱えている問題は何ですか?(コンパイルエラー?) – antlersoft

+0

Javaでは「自己境界型」を使用していません。あなたのコードは 'public interface Game ' – newacct

答えて

5

あなたの定義にもconstが適用されている必要があります。 C++で知られているCRTP(Curiously Recurring Template Pattern)は完全に有効なC++です。

ただし、ここではvirtualは必要ありません。CRTPは静的に機能をディスパッチし、機能を自動的に実装するために使用されます。この場合には、派生クラスがないを行うこと

template <typename T> 
class Game 
{ 
    T& crtp_cast() { return *static_cast<T*>(this); } 
    const T& crtp_cast() const { return *static_cast<const T*>(this); } 
public: 
    T copy() const { return crtp_cast(); } 
    int cur_player() const { return crtp_cast().cur_player(); } 
    ... 
}; 

注コピーコンストラクタが自動的に「コピー」によって呼び出されますよう、「コピー」機能を実装する必要があります。しかし、一般的なケースでは、テンプレートがダック型であるため、このようなことは不要で、通常は標準テンプレートを使用します。 JavaのGenericsとは異なり、C++のテンプレートは継承とは全く関係がありません。インスタンス化できる型は共通のインタフェースから継承する必要はありません。あなたが本当にする必要がある場合

template<typename Game> void f(const Game& g) { 
    std::cout << g.cur_player(); 
} 
class X { 
public: 
    int cur_player() const { return 1; } 
}; 
class Y { 
public: 
    int cur_player() const { return 2; } 
}; 
int main() { 
    f(X()); 
    f(Y()); 
} 
+0

と同様に動作します。ありがとうございました!あなたは正しかった、私はちょうど定義で 'const'を欠いていた。 –

+0

キャストは安全ではありません。 – newacct

1

むしろジェネリック/テンプレートを使用するよりも、私は、ポインタ・ツー・ゲームのコピーやダウンなどして、動的キャスト、それを周りから渡します。例えば

Game.h:

class Game 
{ 
public: 
    virtual Game* copy() const = 0; 
    virtual int cur_player() const = 0; 
    ... 
}; 

TicTacToe.h:

class TicTacToe : public Game 
{ 
public: 
    virtual Game* copy() const; 
    virtual int cur_player() const; 
    ... 
}; 

三目並べ。CPP:

TicTacToe* ttt = dynamic_cast<TicTacToe*>(game); 
ttt->TTTSpecificMethod(); 
+1

生のnewとdeleteは本当に悪いですし、 'static_cast'がダウンしているので、実際には' dynamic_cast'でしょう。 – Puppy

+0

提案していただきありがとうございます。私はC++の新機能です。私はJava、Python、Rubyを3〜5年間やっていますが、C言語は少ししかしません。私は割り当てられたメモリを掃除することに注意します。あなたのアプローチは良いと思います。 'static_cast (game)'のようなダウンキャストで仕事を終えることができるのであれば、テンプレートを使う価値はないかもしれません。 –

+0

DeadMGが提案したように、おそらくdynamic_castを使用するべきです。あなたができるなら、私は間違いなくテンプレートなしでこれをすべて行うでしょう! :) –

0

自己:あなたはどちらか、三目並べ特定のメソッドを呼び出して、ゲームに追加、またはダウンキャストしようとする必要がある場合は

TicTacToe ttt; 
Game* game = &ttt; 
Game* nextGame = game->copy(); // this will call TicTacToe::copy 

Game* TicTacToe::copy() 
{ 
    ... 
} 

int TicTacToe::cur_player() 
{ 
    ... 
} 

はこのようにあなたのゲームを作成します。バウンディングジェネリックス(Java)は、Curiously recurringテンプレートパターン(C++)といくつかの変更を加えて同等です。

template <class T> 
class A 
{ 
private: 
    explicit A(A *temp) {} 

public: 
    explicit A() : A(static_cast<T*>(this)) {} 
    virtual A* function(T *parameter) = 0; 
}; 

class B final : public A<B> 
{ 
public: 
    B* function(B *parameter) { return new B(); } 
}; 

class C final 
{ 
}; 

class D final : public A<C> 
{ 
public: // It occurs compile-time-error 
    D* function(C *parameter) { return new D(); } 
}; 

class E final : public A<E> 
{ 
public: //"override" specifier will not be accepted due to signature does not match! 
    E* function(E *parameter) override { return new E(); } 
}; 

class F final : public A<B> 
{ 
public: //You can also assign another relative type but type-self 
    F* function(B *parameter) { return new F(); } 
}; 

int main() 
{ 
    return 0; 
} 
関連する問題