第二部分数组和引用(基于堆栈的计算器实现)(C++ In Action 学习总结)
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\n";
    } else if (token == tokNumber)
    {
        if (_stack.IsFull())
        {
            std::cout << 'Stack is full\n';
        } else
        {
            _stack.Push(input.Number());
            status = true;
        }
    } else
    {
        // 约定: Input不能产生任何其它符号
        assert(token == '+' || token == '-' || token == '*' || token == '/');
        if (_stack.IsEmpty())
        {
            std::cout << "Stack is empty\n";
        } 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\n";
            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
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号