如何在C++模板中实现相当于Java泛型自我界限的类型

如何在C++模板中实现相当于Java泛型自我界限的类型

问题描述:

我有一个用于演奏多个基于回合的游戏的小型Java算法集合,例如TicTacToe,Othello,Checkers等。我使用Java泛型(self-bound类型)能够使用相同的算法,而不必为每个游戏专门更改它们。我使用自界限类型的原因未在此处显示,但评估函数是必需的。如何在C++模板中实现相当于Java泛型自我界限的类型

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 2011-12-14 22:42:17

+0

这并不明显,为什么不行。你遇到什么问题(编译器错误?) – antlersoft 2011-12-14 22:44:28

+0

在Java中,“自我边界类型”没有用处。你的代码与`public interface Game ` – newacct 2014-05-09 21:59:14

您的定义需要有const也适用于他们。 CRTP在C++(奇怪的循环模板模式)中是已知的,它是完全有效的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的泛型不同,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()); 
} 

而不是使用泛型/模板,我只想通过围绕一个指针到游戏从副本,这样,然后动态转换下来,如果你真的需要。

例如:

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:

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

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

创建你的游戏是这样的:

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

如果您需要调用井字游戏的具体方法,或者将它们添加到游戏,或尝试向下转型:

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

自我通过一些修改,边界泛型(Java)与奇怪的循环模板模式(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; 
}