第二部分数组和引用(基于堆栈的计算器实现)(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
posted @ 2020-11-13 11:24  没尾巴的刺刺鱼  阅读(96)  评论(0编辑  收藏  举报