我正在将我用Java开发的卡片游戏应用程序移植到C ++中,其中卡片对象的等级和套装是通用的(能够使用多个特定的集合),并且卡片本身也是通用的(要打包使用扑克牌,塔罗牌等。
我在Dealer类(模板)中遇到编译错误,它使用CodeBlocks获取卡对象(另一个模板)13.12“codeblocks-13.12mingw-setup-TDM-GCC-481”
卡类(抽象但实现所有卡必须具有的共享功能)
#ifndef CARD_H
#define CARD_H
#include <iostream>
#include <fstream>
#include <cassert>
using namespace std;
enum BJRank
{
Ace,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Ten,
Jack,
Queen,
King,
END_OF_RANKS
};
enum GenericSuit
{
Clubs,
Diamonds,
Hearts,
Spades,
END_OF_SUITS
};
template <class U, class V>
class Card {
private:
U itsRank;
V itsSuit;
protected:
Card(U newRank = Jack, V newSuit = Spades):
itsRank(newRank), itsSuit(newSuit)
{
//s_numberPlayers++;
//cout<<"Number of cards available is: " << s_numberPlayers << "\n";
ofstream myfile ("C:/Temp/cardLogFile.txt", ios::app);
if (myfile.is_open())
{
myfile << "Card base object constructed\n";
}
}
public:
virtual ~Card()
{
ofstream myfile ("C:/Temp/cardLogFile.txt", ios::app);
if (myfile.is_open())
{
myfile << "Card base object destroyed\n";
myfile.close();
}
// if (s_numberPlayers > 0)
// s_numberPlayers--;
// cout<<"Number of cards available is: " << s_numberPlayers << "\n";
}
virtual void setRank(U newRank)
{
this->itsRank = newRank;
}
virtual void setSuit(V newSuit)
{
this->itsSuit = newSuit;
}
virtual const U getRank()
{
return this->itsRank;
}
virtual const V getSuit()
{
return this->itsSuit;
}
};
#endif
一张卡派生类(扑克牌)
#ifndef POKERCARD_H
#define POKERCARD_H
#include "Card.h"
template <class U, class V>
class PokerCard : virtual public Card <U, V> {
public:
PokerCard(): Card <U, V>() {}
PokerCard(U newRank, V newSuit): Card <U, V>(newRank, newSuit) {}
~PokerCard() {}
protected:
virtual void setRank(U newRank)
{
Card <U, V> ::setRank(newRank);
}
virtual void setSuit(V newSuit)
{
Card <U, V> ::setSuit(newSuit);
}
virtual const U getRank()
{
Card <U, V> ::getRank();
}
virtual const V getSuit()
{
Card <U, V> ::getSuit();
}
const int getValue(){return 1;}
};
#endif // POKERCARD_H
经销商抽象类(将从中衍生出众议院和玩家)
#ifndef DEALER_H
#define DEALER_H
#include <fstream>
#include <cassert>
#include <vector>
#include "PokerCard.h"
#include "TarotCard.h"
template < template <class U, class V> class T>
class Dealer
{
public:
Dealer() {}
Dealer(Card<U, V>* cardType) {}
virtual ~Dealer() {}
virtual const vector <Card<U, V>*> getHand()=0;
};
#endif // DEALER_H
最后,Dealer派生类(创建指向扑克牌对象的卡指针)
#ifndef DEALERHOUSE_H
#define DEALERHOUSE_H
#include "Dealer.h"
template < template <class U, class V> class T>
class DealerHouse : virtual public Dealer <T> {
private:
vector <Card<U, V>* > dealerDeck;
Card <U, V> *card;
public:
DealerHouse(): Dealer<T>()
{
for (int suitInt = Clubs; suitInt != END_OF_SUITS; suitInt++)
{
for (int rankInt = Ace; rankInt != END_OF_RANKS; rankInt++)
{
card = new T((U)rankInt, (V)suitInt);
if (card != NULL)
dealerDeck.push_back(card);
else
cout <<"ERROR, card object not created in HEAP" << "\n";
}
}
ofstream myfile ("C:/Temp/dealerLogFile.txt", ios::app);
if (myfile.is_open())
{
myfile << "Default Dealer base object constructed:" << "\n";
}
}
DealerHouse(Card<U, V>* cardType): Dealer<T>(cardType)
{
dealerDeck.push_back(cardType);
ofstream myfile ("C:/Temp/dealerLogFile.txt", ios::app);
if (myfile.is_open())
{
myfile << "Parameterized Dealer base object constructed:" << "\n";
}
}
virtual ~DealerHouse()
{
if (!dealerDeck.empty())
{
dealerDeck.clear();
}
if (card != NULL)
{
delete card;
card = NULL;
}
ofstream myfile ("C:/Temp/dealerLogFile.txt", ios::app);
if (myfile.is_open())
{
myfile << "Dealer object destroyed:" << "\n";
myfile.close();
}
}
protected:
virtual const vector <Card<U, V>*> getHand()
{
return dealerDeck;
}
};
#endif // DEALERHOUSE_H
我在Dealer.h中遇到此编译错误,“Dealer(Card * cardType){}”行: CardGame \ Dealer.h | 16 |错误:在此范围内未声明'U' CardGame \ Dealer.h | 16 |错误:在此范围中未声明'V'|
所以我猜我搞砸了Dealer.h模板参数的声明 “模板&lt;模板类T&gt;类经销商”,以及DealerHouse.h中的那些,遵循相同的语法。
请帮忙吗?我已经检查了类似问题的答案 Template parameters in C++ templates c++ template to template parameter how to declare template of template class
但是当我在其中尝试建议的声明时,我在DealerHouse.H中得到错误,即“card = new T((U)rankInt,(V)suitInt)”中无法识别“T”类型;“。
我很感激任何帮助,我真的很难...
答案 0 :(得分:0)
您误解了模板模板参数的含义。你在这里不需要它们。您只希望Dealer
和DealerHouse
有两个类型参数,就像Card
一样。
答案 1 :(得分:0)
您实际上并未在U,V
或Dealer
内使用DealerHouse
,因此您不需要使用模板Card
或PokerCard
作为参数像Card<U,V>
这样的具体类,它只是T
。因此:
template <class T>
class Dealer
{
// "Card<U,V>" -> "T" everywhere
};
和
template <class T> DealerHouse : public Dealer <T>
{
// "Card<U,V>" -> "T" everywhere
};
您在U,V
中使用DealerHouse
的唯一一点是行
card = new T((U)rankInt, (V)suitInt);
可以只是
card = new T(rankInt, suitInt);
如果int
可以隐式转换为U,V
(普通enum
就是这种情况),或者T
有T(int,int)
形式的构造函数1}}否则。
如果您在内部确实需要U,V
,例如Dealer
(或DealerHouse
),一种方法是将它们作为T
内的特征提供,例如
template <class U, class V>
class Card
{
// ...
public:
using rank = U;
using suit = V;
};
然后可以从T
中的Dealer
“提取”它们
using U = typename T::rank;
using V = typename T::suit;
另一种方法是专门化Dealer
:
template <class T>
class Dealer;
template <template<class, class> class CARD, class U, class V>
class Dealer<CARD<U,V> >
{
using T = CARD<U,V>;
// ...
};
此时您再次拥有所有类型T,U,V
。这适用于CARD
Card
,PokerCard
或其他任何内容。U,V
这个更接近您的定义,但也包含virtual
作为模板参数,您没有,因此您的编译器找不到。
还有几点:
据我所知,您不需要A : public B
继承,所以只需说A : virtual public B
而不是Card
。
如果他们只是调用基类PokerCard
方法,则不需要在Card
等派生类中重新定义{{1}}的虚方法。这是自动完成的。
您真的需要保护setter / getter方法背后的数据吗?