如何声明采用模板类参数的模板类

时间:2014-03-05 13:55:09

标签: c++ class templates

我正在将我用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”类型;“。

我很感激任何帮助,我真的很难...

2 个答案:

答案 0 :(得分:0)

您误解了模板模板参数的含义。你在这里不需要它们。您只希望DealerDealerHouse有两个类型参数,就像Card一样。

答案 1 :(得分:0)

您实际上并未在U,VDealer内使用DealerHouse,因此您不需要使用模板CardPokerCard作为参数像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就是这种情况),或者TT(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 CardPokerCard或其他任何内容。U,V这个更接近您的定义,但也包含virtual作为模板参数,您没有,因此您的编译器找不到。

还有几点:

  • 据我所知,您不需要A : public B继承,所以只需说A : virtual public B而不是Card

  • 如果他们只是调用基类PokerCard方法,则不需要在Card等派生类中重新定义{{1}}的虚方法。这是自动完成的。

  • 您真的需要保护setter / getter方法背后的数据吗?