第五十一讲 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?

|

第四十九讲 一个问题

 

 

 

今天不想写东西,所以我们的新东西今天先不说了,给大家留个题,以便检验一下这段时间以来大家对C++的了解:

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

#include <iostream>

using namespace std;

int main{

 

 

 

 

 

 

 

cout<<"

Hello World"

<<endl;

 

 

 

 

 

 

 

return 0;

}

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

 

 

 

 

 

 

我们都知道这个程序输出将会如下:

————————

Hello World

————————

 

 

 

 

 

 

现在我们的问题是怎么样才让在不改变main函数的情况下让他输出如下:

—————————–

start

Hello World

end

—————————-

 

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

回复D直接查看目录

原文始发于微信公众号(

C/C++的编程教室

):第四十九讲 一个问题

|

第五十讲 一个答案

 

 

 

昨天留给大家的问题看大家的回答,可以说是五花八门,很有意思,其实这个问题很简单的了,就是考大家的C++基础知识,回顾一下我们的原题:

—————————-

#include <iostream>

using namespace std;

int main{

 

 

 

 

 

 

 

cout<<"

Hello World"

<<endl;

 

 

 

 

 

 

 

return 0;

}

—————————–

 

 

 

 

 

 

我们要在不改变main程序的情况输出:

——————————–

start

Hello World

end

——————————–

 

 

 

 

 

 

稍微注意一点,我们的main程序最多能够输出Hello World,但是我们想要在前后各输出一句,然而又不能修改mian,所以一部分人可能开始困惑了。

 

 

 

 

 

 

 

现在大家来思考一个问题,有什么东西是在main之前构造又是在程序结束之后销毁呢?如果大家基础知识过硬的话一定不难想到能够有次功能的当然是……

 

 

 

 

 

 

 

好吧,我们来看下面这个例子:

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

#include <iostream>

using namespace std;

const
int x=6;

int main{

 

 

 

 

 

 

 

cout<<"

Hello World"

<<endl;

 

 

 

 

 

 

 

return 0;

}

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

 

 

 

 

我们可以在int main这一行设一个断点,运行程序,当程序停下来的时候的时候我们看看x的值是多少:

第五十讲 一个答案

 

 

 

 

 

 

大家现在已经明白一个事实,那就是全局变量通常都是在最开始构造,同样在最后摧毁,那么现在大家是不是想起什么了呢?

 

 

 

 

 

 

构造一个对象需要用到构造函数,摧毁一个对象自然调用一个析构函数,所以我们只要在main前面添加一个class,只需要写两构造函数和析构函数即可,如下:

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

#include <iostream>

using namespace std;

class Test{
 

public:
 

 

 

 

 

 

 

 

 

Test(){cout<<"

Start"

<<endl;

}
 

 

 

 

 

 

 

 

 

 

 

~Test(){cout<<"

End"

<<endl;

}
 

};

Test  

test;

int main{

 

 

 

 

 

 

 

cout<<"

Hello World"

<<endl;

 

 

 

 

 

 

 

return 0;

}

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

 

 

 

 

 

现在,构造函数在最开始被执行,所以在进入main之前便打印出:

————–

start

—————

 

 

 

 

 

 

接着进入main,打印出:

———————–

Hello World

————————

 

 

 

 

 

 

当程序退出时执行全局变量的析构函数,于是打印出:

—————–

end

——————-

 

 

 

 

 

 

Ok,今天的任务完成了,那么再留给大家一个任务:

 

 

 

 

 

 

 

用我所学的知识来写一个跳棋游戏。

 

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

回复D直接查看目录

 

原文始发于微信公众号(

C/C++的编程教室

):第五十讲 一个答案

|

第四十三讲 继承(1)

       上一讲中留给大家思考的问题想必大家都有一个结果了,本来是昨天开始谈继承的,但昨天电脑被老婆不知道怎么弄的,浏览器无法打开,各种修复无用,最终只好重新安装系统,所以,关于继承,今天我们也许只能给大家开一个头,不过开个头也算不错。
每个公司都有自己的人事系统,不过想想其实也是可以模拟的,一个人事系统管理着公司的员工,而每个员工不但有自己的姓名,同时还有公司的工号,还有相应的薪酬等等。我们可以如下实现:
———————————-
//employ.h
#pragma once
#include <iostream>#include <string>using namespace std;

namespace My_Code{
class employ
{
public:
employ();

virtual ~employ();

employ&

SetFirstName(const string Fir_Name);

employ&

SetLastName(const string Last_Name);

employ&

SetNumberID(const long Number);

virtual employ&

SetSalary(const long Salary);

const string&

GetFistName() const;

const string&

GetLastName() const;

const long&

GetNumberID() const;

virtual const long&

GetSalary() const;

virtual
void Show_Employy_Info();

private:
                 employ(const employ&

);


                 employ&

operator=(const employ&

);


                 string m_firstname;

string m_lastname;

long m_NumberID;

long m_Salary;

};

}
——————————————-
然后我们来测试一下这个系统:
——————————————–
//test.cpp
#include “employ.h”
using namespace My_Code;

int main()
{
employ m_employ;

string str1,str2;

long num,salary;

cout<<“请输入员工名字:n”;

cin>>str1>>str2;

cout<<“请输入员工工号:n”;

cin>>num;

cout<<“请输入员工工资:n”;

cin>>salary;

m_employ.SetFirstName(str1).SetLastName(str2).SetNumberID(num).SetSalary(salary).Show_Employy_Info();

return 0;

}
—————————————-
我们来测试一下:
第四十三讲 继承(1)
目前看来,我们的这个东西还是可行的,但是我想问大家这样做就够了吗?一个公司不但有普通员工,还有管理,管理又分经理和总监等等,不同级别的员工的工资水平当然不一样,那么我们该怎么做呢?我想大家可能注意到了,今天我们的界面里的多了一个奇怪的关键字:virtual,我们为什么要添加这个关键词呢?大家今天思考一下吧。明天我们再来细说这个关键字。
 

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

原文始发于微信公众号( C/C++的编程教室 ):第四十三讲 继承(1)|