我目前正在处理一个a类,以及从该基类派生的其他三个类。基类本质上应该是抽象的,这样我就可以调用基类的虚拟函数,并让它执行派生类的预期函数。我的最终目标是做这样的事情:
class Car {
public:
virtual void drive() = 0; // Pure-virtual function
};
class Ford : public Car {
public:
virtual void drive() { std::cout << "driving Fordn"; }
};
这应该行得通。在一个空文件中,此设置确实有效。我的实现肯定是错误的,但c++编译器没有给我任何关于错误的好提示
目前,我正在使用一个函数来创建派生类,返回要在main中使用的基类。我已经试过了所有我能想到的:
- 传入退出后不会被销毁的指针
- 返回派生类并存储到基类中
- 将基类/指针投射到派生类中
- 将取消引用的基类指针设置为派生类
我只是无法让它在我的一生中工作。无论何时从基类变量运行,虚拟函数都会导致seg错误。以下是我正在测试的、我认为在当前状态下相关的所有代码。
说明.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;
}
解码.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;
导致对象切片。
相反,动态创建IType
对象并返回指向该对象的指针:
Instruction *decode(string binaryIn, map<string, string> registerSet, map<string, string> instructionSet)
{
return new IType(opcode, label, rs, rt, imm, registerSet);
}
请注意,instructionPointer
参数已不存在。
在decode
中,您将创建IType
作为局部变量,导致它在函数返回时被销毁。
更具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
(不会超过该函数的末尾,除非返回值。您知道基类返回类型应该是一个指针,而不是基类类型,以避免切片,但您需要某种方法来提供一个指向寿命足够长的对象的指针。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);