如何从 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 并存储到基数 class
- 将基数 class/pointer 转换为派生的 class
- 将取消引用的基 class 指针设置为派生的 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);
我目前正在使用一个 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 并存储到基数 class
- 将基数 class/pointer 转换为派生的 class
- 将取消引用的基 class 指针设置为派生的 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);