C++模板编程


889 浏览 5 years, 4 months

2.7 子类化模板类

版权声明: 转载请注明出处 http://www.codingsoho.com/

子类化模板类

可以编写模板类的子类。如果子类从模板本身继承,那么这个子类也必须为一个模板。此外,还可以编写一个子类继承模板类的某个特定实例,在这种情况下,这个子类不需要是模板。

下面列举前一种情况的一个例子,假设您认为通用的Grid类没有提供足够的棋盘功能。确切地讲,您想给棋盘添加一个move()方法,允许棋盘上的一个棋子从一个位置移动到另一个位置。

下面是这个GameBoard模板的类定义:

template <typename T>
class GameBoard : public Grid<T>
{
 public:
  GameBoard(size_t inWidth = Grid<T>::kDefaultWidth,
        size_t inHeight = Grid<T>::kDefaultHeight);
  void move(size_t xSrc, size_t ySrc, size_t xDest, size_t yDest);
};

这个GameBoard类子类化了Grid,因此继承了Grid模板的所有功能。

不需要重写setElementAt()、getElementAt()以及其他任何方法。也不需要添加一个复制构造函数、operator=或析构函数,因为在GameBoard中没有任何动态分配的内存。Grid超类中动态分配的内存由Grid的复制构造函数、operator=和析构函数处理。

继承的语法和普通继承一样,区别在于超类是Grid<T>,而不是Grid。设计这个语法的原因是GameBoard模板并没有真正地子类化通用的Grid模板。相反,事实上是GameBoard模板对特定类型的每个实例化都是Grid对那个类型实例化的子类。

例如,如果使用ChessPiece类型实例化一个GameBoard,那么编译器也会生成Grid<ChessPiece>的代码。

“:public Grid<T>”语法表明这个类是Grid对任何类型参数T有意义的实例化的子类。

注意 C++模板继承的名称查找规则要求您指定kDefaultWidth和kDefaultHeight声明在超类Grid<T>中,因而依赖于超类Grid<T> 。

下面是构造函数和move()方法的实现。同样,要注意调用超类构造函数时Grid的使用。此外,尽管很多编译器并没有强制要求使用this指针引用超类中的数据成员和方法,但名称查找规则要求使用this指针:

template <typename T>
GameBoard<T>::GameBoard(size_t inWidth, size_t inHeight) :
  Grid<T>(inWidth, inHeight)
{
}

template <typename T>
void GameBoard<T>::move(size_t xSrc, size_t ySrc, size_t xDest, size_t yDest)
{
  this->mCells[xDest][yDest] = this->mCells[xSrc][ySrc];
  this->mCells[xSrc][ySrc] = T(); // default construct the src cell
}

从以上代码中可以看出,move()使用了前面描述的语法T() 。

GameBoard模板的使用示例如下:

int main()
{
    GameBoard<ChessPiece> chessBoard;
    ChessPiece pawn;
    chessBoard.setElementAt(0, 0, pawn);
    chessBoard.move(0, 0, 0, 1);
    return 0;
}