在子类中设置变量

Setting a variable in a child class

本文关键字:变量 设置 子类      更新时间:2023-10-16

我目前正在开发一个非常基本的汇编程序。汇编程序需要接收汇编指令并输出16位二进制指令,以便与我们正在制作的计算机一起使用。

我的设计策略是创建一个Command类,它有3个子类。每种类型的命令都有一个:A命令、C命令和L命令。为了确定我使用的命令类型,我包含了一个字符串command_type,该字符串分别为"a"、"C"或"L"。

编辑:

我仍然很难弄清楚如何正确地派生这些类。基本上,A和L命令应该有一个"symbol"字符串,表示需要转换的整数值,而C命令有"dest"、"comp"answers"jump"值,这些值也必须访问,但它们没有"symbol"值。

命令.h

#include <fstream>
#include <string>
class Command {
    std::string command_type = "";
protected:
    void set_commandType(std::string x){command_type = x;}
public:
    Command();
    virtual ~Command();
    std::string commandType() const {return command_type;}
};
class A_COMMAND : public Command
{
    std::string symbol;
public:
    A_COMMAND(std::string s);
    std::string get_symbol(){return symbol;}; //Returns the symbol or decimal Xxx of the current command @Xxx or (Xxx) . Should be called only when commandType() is A_COMMAND or L_COMMAND.

};
class C_COMMAND : public Command
{
    std::string comp;
    std::string dest;
    std::string jump;
public:
    C_COMMAND(std::string s, std::string d, std::string j);
    std::string get_comp(){return comp;}; //Returns the comp mnemonic in the current C-command (28 possibilities). Should be called only when commandType() is C_COMMAND.
    std::string get_dest(){return dest;}; //Returns the dest mnemonic in the current C-command (8 possibilities). Should be called only when commandType() is C_COMMAND.
    std::string get_jump(){return jump;}; //Returns the jump mnemonic in the current C-command (8 possibilities). Should be called only when commandType() is C_COMMAND.
};
class L_COMMAND : public Command
{
    std::string symbol;
public:
    L_COMMAND(std::string s);
    std::string get_symbol(){return symbol;}; //Returns the symbol or decimal Xxx of the current command @Xxx or (Xxx) . Should be called only when commandType() is A_COMMAND or L_COMMAND.
};

Command.cpp

#include "Command.h"
//---------------------------------------------
//A-Command functions
Command::Command(){}
A_COMMAND::A_COMMAND(std::string s) : symbol(s)
{
    set_commandType("A");
}

//---------------------------------------------
//C-Command functions
C_COMMAND::C_COMMAND(std::string c, std::string d, std::string j) : comp(c), dest(d), jump(j)
{
    set_commandType("C");
}
//---------------------------------------------
//L-Command functions
L_COMMAND::L_COMMAND(std::string s) : symbol(s)
{
    set_commandType("L");
}

我有一个Parser.cpp和Parser.h,它们处理输入并负责创建一组命令:

Parser.h

#include "Command.h"
#include <vector>
#include <deque>

class Parser {
private:
    std::deque<Command> commands;
public:
    Parser(std::vector<std::string>);
    bool hasMoreCommands() //are there more commands in the input?
    {
        if(commands.size() != 0)
            return true;
        else
            return false;
    }
    void advance(){commands.pop_front();} //move to next command, should only work if hasMoreCommands returns false}
    Command currentCommand(){return commands.front();}
    std::vector<std::string> translateCommands(); //convert commands into binary strings
};

Parser.cpp

#include "Parser.h"
#include "Command.h"
#include <vector>
#include <iostream>
#include <string>
#include <unordered_map>
bool inList(std::string& str, std::vector<std::string> list) //check if a given string contains one of the elements in the comp, dest, jump vectors. if so extract string for use in constructor
{
    for(auto i = list.begin(); i!=list.end(); ++i)
    {
        std::size_t found = str.find(*i);
        if(found!=std::string::npos)
        {
            return true;
        }
    }
    return false;
}

Parser::Parser(std::vector<std::string> input) {
    std::vector<std::string> dest_list = {"","M","D","MD","A","AM","AD","AMD"}; //all possible dests
    std::vector<std::string> comp_list = {"0","1","D","A","!D","!A","-D","-A","D+1","A+1","D-1","A-1","D+A","D-A","A-D","D&A","D|A","M","!M","-M","M+1","M-1","D+M","D-M","M-D","D&M","D|M"}; //all possible comps
    std::vector<std::string> jump_list = {"","JGT","JEQ","JGE","JLT","JNE","JLE","JMP"}; //all possible jumps
    std::string dest, comp, jump;
    std::deque<Command> commands;
    for(std::vector<std::string>::const_iterator i = input.begin(); i != input.end(); ++i)
    {
        std::string line = *i;
        if(*line.begin()=='@') //A-command
        {
            A_COMMAND command(line.substr(1));
            std::cout << "Command type: " << command.commandType() << "n";
            std::cout << "symbol: " << command.get_symbol() << "n";
            commands.push_back(command);
        }
        else if(*line.begin()=='(' && *line.rbegin() == ')' && line.size() > 2) //L-command
        {
            L_COMMAND command(line.substr(1, line.size() - 2));
            std::cout << "Command type: " << command.commandType() << "n";
            std::cout << "symbol: " << command.get_symbol() << "n";
            commands.push_back(command);        }
        else
        {
            std::string rhs = line;
            std::string dest_string = "";
            std::string comp_string = "";
            std::string jump_string = "";
            size_t equals_pos = line.find('='); //position of = in string, if present
            size_t semi_pos = line.find(';');   //position of ; in string, if present
             if(equals_pos != line.npos) //if there is an = then we have a dest
             {
                 dest_string = line.substr(0,equals_pos);
                 rhs = line.substr(equals_pos+1);
             }
             if(semi_pos != line.npos) //jump
             {
                 comp_string = rhs.substr(0,semi_pos);
                 jump_string = rhs.substr(semi_pos+1);
             }
             else //no jump
             {
                 comp_string = rhs;
             }
             //now confirm if inputs are valid
             if(inList(dest_string, dest_list))
                 dest = dest_string;
             else
                 std::cout << "invalid dest n";
             if(inList(comp_string, comp_list))
                 comp = comp_string;
             else
                 std::cout << "invalid comp n";
             if(inList(jump_string, jump_list))
                 jump = jump_string;
             else
                 std::cout << "invalid jump n";
             C_COMMAND command(comp, dest, jump);
             std::cout << "Command type: " << command.commandType() << "n";
             std::cout << "dest: " << command.get_dest() << "n";
             std::cout << "comp: " << command.get_comp() << "n";
             std::cout << "jump: " << command.get_jump() << "n";
             commands.push_back(command);
        }
    }
}

我的main.cpp加载输入,并将其传递给解析器。我遇到的问题是,我无法对输入做任何事情。

我试着写一个这样的函数:

string translateLine(Command command, Code code) //Code is a table for translating the command
{
    string output;
    if(command.commandType() == "A")
    {
        string symbol = parser.currentCommand().get_symbol();
        cout << symbol << endl;
        //perform binary conversion
    }
    /*else if(command.commandType() == "C")
    {
        string dest = command.get_dest();
    }*/
     //shouldn't be any L commands in symbol-less version
    else
    {
        std::cout << "unexpected command value n";
    }
    return output;
}

但是,一旦我调用get_symbol(),编译器就无法识别该函数。我知道这是因为基本命令没有get_symbol()函数,但我不知道如何正确地将函数添加到基类并将它们派生到较低的3。我不能只是让纯虚拟的,因为并不是所有的函数都在每个类中使用。我怎样才能正确地做到这一点?

首先,如果translateLine()应该能够接受A_COMMANDC_COMMANDL_COMMAND对象,那么它需要接受Command*参数,而不是Command参数。指向基类的指针可以包含指向从该基类派生的类的指针,但基类的对象不能包含派生对象。

其次,即使使用真正指向A_COMMAND对象的Command指针,也不能在不执行dynamic_cast的情况下调用属于A_COMMAND的函数。dynamic_cast可以在运行时将指针从Command*转换为A_COMMAND,并且如果所指向的对象实际上不是A_COMMAND对象,则返回NULL

基本问题是您正在重新创建运行时类型信息。您不需要将"command_type=A"添加到class A_COMMAND。如果至少有一个虚拟方法,C++已经知道对象的类型。看起来你的类需要一个虚拟析构函数。