如何从 C++ 中的基变量调用派生函数?

How do I call derived functions from base variables in C++?

我目前正在使用一个 class 和从该基础 class 派生的其他三个 classes。基 class 本质上应该是抽象的,这样我就可以调用基 class 的虚函数,并让它执行派生 class 的预期功能。我的最终目标是做这样的事情:

class Car {
public:
    virtual void drive() = 0;  // Pure-virtual function
};

class Ford : public Car {
public:
    virtual void drive() { std::cout << "driving Ford\n"; }
};

这应该有效。在空文件中,此设置确实有效。我的实现一定是错误的,但是 c++ 编译器没有给我任何关于错误是什么的好的提示。

目前,我正在使用一个函数来创建派生 class,返回要在 main 中使用的基数 class。我已经尝试了所有我能想到的:

我就是无法让它为我的生活工作。每当 运行 来自基本 class 变量时,虚函数只会导致段错误。 以下是我认为相关的所有代码,在我正在测试的当前状态下。

Instruction.h:

class Instruction {
    public:
        virtual void print(){};
        bool operator==(const int& rhs) const;
        void writeBack();
        void memory();
        virtual void execute(long registers[32], long dmem[32]){};
        unsigned int str2int(const char *str, int h);
        virtual ~Instruction(){};
};

ITypeInstruction.h:


class IType: public Instruction {
    private:
        int op;
        string label;
        string rs;
        string rt;
        string immediate;
        map<string, string> registerMap;

    public:
        IType(int op, string label);
        IType(int op, string label, string rs, string rt, string immediate, map<string, string> registerMap);
        virtual void print();
        void execute(long registers[32], long dmem[32]);
};

ITypeInstruction.cpp:

void IType::print()
{
    cout << "Instruction Type: I " << endl;
    cout << "Operation: " << label << endl;
    cout << "Rs: " << registerMap[rs] << " (R" << rs << ")" << endl;
    cout << "Rt: " << registerMap[rt] << " (R" << rt << ")" << endl;
    cout << "Immediate: 0x" << immediate << endl;
}

Decode.cpp:

Instruction *decode(string binaryIn, map<string, string> registerSet, map<string, string> instructionSet, Instruction *instructionPointer)
{
        IType ins = IType(opcode, label, rs, rt, imm, registerSet);
        Instruction i = IType(opcode, label, rs, rt, imm, registerSet);
        ins.print();
        *instructionPointer = ins;
        (*instructionPointer).print();
        return instructionPointer;
}

main.cpp

Instruction *instructionToExecute;
instructionToExecute = decode(instructionToDecode, registerSet, instructionSet, instructionToExecute);
instructionToExecute->print();

您显示的代码存在多个问题。

一个是您试图取消引用 未初始化 instructionPointer 变量。

另一个是*instructionPointer = ins;导致object slicing

而是创建 IType 对象 动态地 和 return 指向该对象的指针:

Instruction *decode(string binaryIn, map<string, string> registerSet, map<string, string> instructionSet)
{
    return new IType(opcode, label, rs, rt, imm, registerSet);
}

请注意,instructionPointer 参数已不存在。

decode 中,您正在创建 IType 作为局部变量,导致它在函数 returns.

时被销毁

更多的 C++ 风格,

std::unique_ptr<Instruction>
decode(string binaryIn, map<string, string> registerSet, map<string, string> instructionSet)
{
  std::unique_ptr<Instruction> ins = std::make_unique<IType>(opcode, label, rs, rt, imm, registerSet);
  ins->print();
  return ins;
}

auto instructionToExecute = decode(...);
instructionToExecute->print();

正确的做法:

#include <memory>

std::unique_ptr<Instruction> decode(
    string binaryIn,
    map<string, string> registerSet,
    map<string, string> instructionSet,
    Instruction *instructionPointer)
{
  return std::make_unique<IType>(opcode, label, rs, rt, imm, registerSet);
}

int main() {
    // ...
    auto instructionToExecute = decode(instructionToDecode, registerSet,
        instructionSet, instructionToExecute);
    instructionToExecute->print();
}

发生了什么:函数中定义的变量(未标记为 static)不会在该函数结束后继续存在,return 值除外。您知道 base class return 类型应该是指针而不是 base class 类型以避免切片,但是您需要某种方法来提供指向足够长的东西的指针使用。 std::make_unique 是最简单的方法。

出错的地方:

Instruction *decode(string binaryIn, map<string, string> registerSet, map<string, string> instructionSet, Instruction *instructionPointer)
{
        // OK, but the object "ins" lives only until the function returns.
        IType ins = IType(opcode, label, rs, rt, imm, registerSet);

        // Immediately slices to the base class, and isn't an IType any more.
        Instruction i = IType(opcode, label, rs, rt, imm, registerSet);

        // No problem.
        ins.print();

        // This uses the operator= of the base class Instruction.
        // It's probably not going to be able to handle assigning derived info
        // well, even if instructionPointer does in fact point at the same
        // derived type.       
        *instructionPointer = ins;

        (*instructionPointer).print();

        // This will be just the same pointer as the passed argument,
        // so doesn't really add any utility.
        return instructionPointer;
}

int main() {
    // ...

    // This pointer is an uninitialized value. Using it is as bad as
    // using the value of an uninitialized "int v;"...
    Instruction *instructionToExecute;

    // Uh oh. decode does *instructionToExecute = something;
    // But instructionToExecute is uninitialized and doesn't actually
    // point at any object to reassign! (Not even a base type object.)
    instructionToExecute = decode(instructionToDecode, registerSet,
        instructionSet, instructionToExecute);