第五十一讲 Is_a还是Has_a?

回顾一下五十讲,其实没什么,主要就是那个留给大家思考的问题,为记得我们说的是跳棋,现在想想,跳棋我还真不会玩,不过原理还是差不多,就五子棋吧,嗯,就拿五子棋来说说,毕竟这些东西是相通的,一通百通,既然说到这里,我们来分析一下吧,简单些,主要是为了让大家更好明白,所以我们假设已经写好了一个关于棋子的class,那么我们现在要完成的是就是构造一张棋盘,别问我为什么我们不说棋子要说棋盘,因为接下来大家会明白,因为只有说棋盘才会把我们今天的话题带进来,好了好了,又扯远了,棋盘理应纵横交错,所以,很显然,我们可以这样来弄:

————————————–

//gamaboard.h
#include <iostream>
#include <string>
using namespace std;

class gamePiece;

//前向声明
namespace My_Code{

class gameboard{

public:

gameboard(int width = defaultWidth,int height = defaultWidth);


virtual ~gameboard();


gameboard(const gameboard&

);


gameboard operator=(const gameboard&

rhs);


void SetPiece(int x,int y,const gamePiece&

Piece);


const gamePiece&

GetPieceAt(int x,int y) const;


gamePiece&

GetPieceAt(int x,int y);


int GetHeight(){
return m_Height;

}

int GetWidth()
{
return m_Width;

}

static const
int defaultHeight = 10;


static const
int defaultWidth = 10;


private:

void copyFrom(const gameboard&

rhs);


int m_Height;


int m_Width;


gamePiece **mPiece;


};


}

————————————

嗯,这个看起来好像有些眼熟呢?是啊,如果大家还是心存怀疑的话,不妨回去看看我们的深入class那几讲,就会明白了,在那几讲里我们主要是通过一个电子表格来阐述的,现在我怎么觉得我们又绕回去了呢?好像不应该,车轮怎么会往后转?嗯,我们继续往下看,今天应该会有新鲜的玩意出来。

继续回到我们的主题,棋盘好比我们的电子表格,棋子好比我们的电子表格里面的数据,这么一说是不是更加明白了呢?大家可能会想,那棋盘和电子表格到底是什么关系呢?

我的回答是没啥关系,没啥关系到底是啥关系?简单点说,我们可以用电子表格创建出棋盘来,这就是C++里面的一种设计技术——根据某物实现出,嗯,这名字有些不好听,说实在的,我也是这么认为的,不过既然都这么叫,我们也就眨眨眼睛算了吧。

那么该怎么实现呢?以前我们学习过public继承,当时我们说那是is_a关系,is_a关系一种从属关系,就是什么是什么,所以,当我们决定要用public继承的话,就先来思考这个问题,看他们到底是不是有这种从属关系。

现在棋盘和电子表格可以说是八竿子打不着的事儿,所以就算我们想要从电子表格实现出棋盘来,也得三思是要用public继承呢还是……还是啥啊?好像其他的我们也还没说呢,這不是正打算来说吗?

在C++里面,有一种设计技术叫做复合,复合听起来也就这么回事了,可能我说出来有些同学不怎么能够听得懂,不过,大家应该还记得我们说过一种技术:让接口和实现彻底分离,如果不记得,继续回去看看深入class那几讲,里面说得有,所以这复合和那种技术差不多,如果,我们不妨将上面接口改一下:

—————————————

//gamaboard.h
#ifndef _GAMABOARD_H_
#define _GAMEBOARD_H_

#include <iostream>
#include <string>
#include "

SpreadsheetData.h"


using namespace std;

class gamePiece;


namespace My_Code{

class gameboard{

public:

gameboard(int width,int height);


virtual ~gameboard();


void SetPiece(int x,int y,const SpreadSheetCell&

Piece);


SpreadSheetCell&

GetPieceAt(int x,int y);


int GetHeight(){
return m_Height;

}

int GetWidth()
{
return m_Width;

}

private:

int m_Width;


int m_Height;


SpreadSheetData* member;


};


}
#endif

——————————————

嗯,看起来很简洁的样子,实现起来更简洁呢,哈哈,因为很多东西都是现成的,所以我们只要拉出来用就好,一个新的东西就出来了。

———————————————-

//gameboard.cpp
#include "

gameboard.h"


using namespace My_Code;


gameboard::gameboard(int width,int height):
m_Width(width),m_Height(height)
{

member = new SpreadSheetData(width,height);


}

gameboard::~gameboard()
{

delete member;
}


void gameboard::SetPiece(int x,int y,const SpreadSheetCell&

Piece)
{

member->SetCellAt(x,y,Piece);


}

SpreadSheetCell&

gameboard::GetPieceAt(int x,int y)
{

return member->GetCell(x,y);


}

————————————–

这样一来,一个棋盘就活灵活现的出现了,我们可以这样使:

——————————–

//Test.cpp

#include "

gameboard.h"

using namespace My_Code;

int main()

{


gameboard My_board(10,10);


My_Board.SetPiece(6,6,10);


cout<<My_board.GetPieceAt(6,6)<<endl;

return 0;

}

————————————-

当然,我们的这个只是作为测试用,不要说这怎么就是五子棋了呢?这黑乎乎的框里写的是啥玩意呢?其实不要看那些花花绿绿的界面,界面不过一层面纱而已,真正起作用的还是这些底层的东西。

第五十一讲 Is_a还是Has_a?

如果以前我们还不清楚什么是Is_a什么是Has_a,那么今天应该能够有所明白了吧,如果还不明白,那么我们接下来再看看什么是private继承。

大家注意的话我们的gameboard里面没有复制赋值等一系列函数,因为我觉得游戏没有复制没有赋值,不过要真正避免的话,我们应该把这两个函数声明为private,避免编译器自说自话的搞两个出来,那是很头疼的,不过没关系,这个就留给大家去做,是要还是留,根据大家的想法吧。

今天的重点,总结一下吧:

1)复合和public继承完全是两回事。

2)在应用里,复合意味着Has_a,在实现方面,复合就是根据某物实现出。

===================

回复D直接查看目录,有问题可以直接提问。

原文始发于微信公众号(

C/C++的编程教室

):第五十一讲 Is_a还是Has_a?

|

发表评论