1,友元
1.1,访问控制
当一个类声明了一个友元时,则友元可以访问该类的私有数据(has-access-to),例如,StackSeq可以访问Stack的私有数据。
声明一个友元:friend class StackSeq
2,引用
2.1,定义
引用是其它值得别名,修改引用则会更改它所引用的值,读取引用,则读取的值为所引用的值。
2.2,创建
引用在创建时,必须初始化,或者在声明中完成,或者在构造函数中完成,或者在调用含有引用的方法时完成。
int a = 10;
int &b = a; // b为a的引用
2.3,特性
引用传递参数,不是和值传递一样,获得参数的拷贝,而是直接引用到该值,修改引用会直接修改引用的值,也就是说,引用和所引用的值是同步的。
常量引用可以用其它任何引用来初始化,非常量引用不能通过一个常量引用来初始化。
3,基于堆栈的计算器的实现
自顶向下进行设计。
功能:对输入的数字进行压入栈中,并且每次压栈后,将显示栈中的所有元素。对输入的运算符,则取出栈栈中的两个数字,并进行操作,然后将结果压入栈中,如果此时栈中只有一个值,则将该值进行自操作,即对相同的该值进行该运算符的操作。
Input类,定义获得输入,并且进行预处理。并将预处理结果,如果结果为数字,Number()方法则将其返回。
Stack类,定义堆栈的操作方式
StackSeq类,为堆栈的生成器。
Calculator类
bool Execute(Input const &input);方法对Input预处理后的结果,进行计算并进行栈操作。 int Calculate(int n1, int n2, int token) const;方法,对数据进行操作
3.1,堆栈定义和实现
// stack.h
/**
* 接口文件必须包括:
* 类的定义,
* 指定所有的数据成员
* 声明成员函数
*/
const int maxStack = 16;
class IStack
{
friend class StackSeq; // 友元可以访问当前对象中的数据
public:
IStack():_top(0){}
void Push(int i); // 将i压入堆栈
int Pop(); // 将堆栈顶上的元素弹出,并返回
int Size(); // 返回栈中元素
int Top(); // 返回栈顶元素,不返回
bool IsFull();
bool IsEmpty();
private:
int _arr [maxStack];
int _top;
};
// 声明堆栈生成器
class StackSeq
{
public:
StackSeq(IStack const &stack);
bool AtEnd() const; //是否完成
void Advance(); //移到下一项
int GetNum() const; //读取当前项
private:
IStack const & _stack; //常量引用stack,必须在构造函数前导中初始化
int _iCur; // stack 当前引用
};
// stack.cpp
#include "stack.h"
#include <cassert>
#include <iostream>
// 通过NDEBUG=1编译去掉断言
void IStack::Push(int i)
{
assert(_top < maxStack);
_arr[_top++] = i;
}
int IStack::Pop()
{
assert(_top > 0);
return _arr[--_top];
}
int IStack::Size()
{
return _top;
}
int IStack::Top()
{
assert(_top != 0);
return _arr[_top - 1];
}
bool IStack::IsFull()
{
return _top == maxStack;
}
bool IStack::IsEmpty()
{
return _top == 0;
}
// 堆栈序列生成器定义
StackSeq::StackSeq(const IStack &stack) : _iCur(0), _stack(stack)
{}
bool StackSeq::AtEnd() const
{
return _iCur == _stack._top;
}
void StackSeq::Advance()
{
assert(!AtEnd()); // 非结尾
++_iCur;
}
int StackSeq::GetNum() const
{
assert(!AtEnd());
return _stack._arr[_iCur];
}
3.2,输入/输出操作
// input.h
//
// Created by FLanWu on 2020/11/13.
//
// 条件编译指令,防止重复定义
# if !defined input_h
#define input_h
const int maxBuf = 100;
const int tokNumber = 1;
const int tokError = 2;
// 获取输入并进行预处理
class Input
{
public:
Input();
int Token() const
{
return _token;
}
int Number() const;
private:
int _token;
char _buf[maxBuf];
};
#endif
// input.cpp
#include <iostream>
#include <cctype> // 包含识别字符类型,isdigit宏,可以判断字符是否为数字
#include <cstdlib> // 包含atoi()将ascii转换为整数
#include <cassert>
#include "input.h"
Input::Input()
{
std::cin >> _buf;
// 判断输入的第一个字符是什么
int c = _buf[0];
if (std::isdigit(c))
{
_token = tokNumber;
} else if (c == '+' || c == '*' || c == '/')
{
_token = c;
} else if (c == '-') //允许输入负数
{
if (std::isdigit(_buf[1])) // 参照下一个字符
{
_token = tokNumber;
} else
{
_token = c;
}
} else
{
_token = tokError;
}
}
int Input::Number() const // 将缓冲器中的字符转换为字符串
{
assert(_token == tokNumber);
return std::atoi(_buf); //将字符串转换为整数
}
3.2,Calculator的定义和实现
// calc.h
//
// Created by FLanWu on 2020/11/13.
//
#include "input.h"
#include "stack.h"
class Calculator
{
public:
bool Execute(Input const &input);
// 让stack可以访问
IStack const & GetStack() const
{
return _stack;
}
private:
int Calculate(int n1, int n2, int token) const;
IStack _stack;
};
// calc.cpp
//
// Created by FLanWu on 2020/11/13.
//
#include <iostream>
#include <cassert>
#include "calc.h"
#include "stack"
#include "input.h"
bool Calculator::Execute(const Input &input)
{
// 对堆栈进行提出数字并将计算结果重新压入堆栈。
int token = input.Token();
bool status = false; // 状态初始为失败
if (token == tokError)
{
std::cout << "Unknown token
";
} else if (token == tokNumber)
{
if (_stack.IsFull())
{
std::cout << 'Stack is full
';
} else
{
_stack.Push(input.Number());
status = true;
}
} else
{
// 约定: Input不能产生任何其它符号
assert(token == '+' || token == '-' || token == '*' || token == '/');
if (_stack.IsEmpty())
{
std::cout << "Stack is empty
";
} else
{
int num2 = _stack.Pop();
int num1;
if (_stack.IsEmpty())
{
num1 = num2;
} else
{
num1 = _stack.Pop();
}
_stack.Push(Calculate(num1,num2,token));
status = true;
}
}
return status;
}
int Calculator::Calculate(int n1, int n2, int token) const
{
int result;
if(token == '+')
result = n1 + n2;
else if(token == '-')
result = n1 - n2;
else if(token == '*')
result = n1 * n2;
else if(token == '/')
{
if(n2 == 0)
{
std::cout << "Division by zero
";
result = 0;
} else
result = n1 / n2;
}
return result;
}
3.3,main函数测试
#include <iostream>
#include "calc.h"
using namespace std;
int main()
{
Calculator TheCalculator;
bool status;
do
{
std::cout <<">>>";
Input input;
status = TheCalculator.Execute(input);
if(status)
{
for(StackSeq seq(TheCalculator.GetStack()); !seq.AtEnd(); seq.Advance())
{
std::cout << " " << seq.GetNum() << std::endl;
}
}
}while (status);
return 0;
}
输出结果:
>>>1 1 >>>2 1 2 >>>3 1 2 3 >>>-1 1 2 3 -1 >>>+ 1 2 2 >>>+ 1 4 >>>- -3 >>>+ -6 >>>sjad Unknown token