如何在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'
... 以及每个其他纯虚函数的相同。
答
您的定义需要有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;
}
你从来没有说过什么都行不通。 – Puppy 2011-12-14 22:42:17
这并不明显,为什么不行。你遇到什么问题(编译器错误?) – antlersoft 2011-12-14 22:44:28
在Java中,“自我边界类型”没有用处。你的代码与`public interface Game` –
newacct
2014-05-09 21:59:14