Search code examples
c++pointerssegmentation-faultderived-classabstraction

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


I am currently working with a a class, and three other classes that derive from that base class. The base class is supposed to be essentially abstract, so that I can call the virtual function of a base class, and have it do the expected function of the derived class. My end goal is to do something like this:

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

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

This should work. In an empty file, this setup does work. My implementation must be wrong, but the c++ compiler doesn't give me any good hints on what the error is.

Currently, I am using a function to create the derived class, returning the base class to be used in main. I've tried all I could think of:

  • Passing in a pointer that won't be destroyed after you exit
  • Returning the derived class and storing into the base class
  • Casting a base class/pointer into the derived class
  • Setting a dereferenced base class pointer to a derived class

I just could not get it to work for the life of me. The virtual function just causes a seg fault whenever run from a base class variable. Here is all of the code that I believe is relevant, in its current state, as I am testing.

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();

Solution

  • There are multiple problems with the code you show.

    One is that you attempt to dereference the uninitialized instructionPointer variable.

    Another is that *instructionPointer = ins; leads to object slicing.

    Instead create the IType object dynamically and return a pointer to that object:

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

    Note that the instructionPointer argument is no longer there.