This is my first experience with downcasting in C++ and I just can't understand the problem.
AInstruction
and CInstruction
inherit from AssemblerInstruction
.
Parser
takes the info in its ctor and creates one of those derived instruction types for its mInstruction
member (accessed by getInstruction
). In the program, a method of the base AssemblerInstruction
class is used, for happy polymorphism.
But when I want to test that the Parser
has created the correct instruction, I need to query the derived instruction members, which means I need to downcast parser.getInstruction()
to an AInstruction
or CInstruction
.
As far as I can tell this needs to be done using a bunch of pointers and references. This is how I can get the code to compile:
TEST(ParserA, parsesBuiltInConstants)
{
AssemblerInstruction inst = Parser("@R3", 0).getInstruction();
EXPECT_EQ(inst.getInstructionType(), AssemblerInstruction::InstructionType::A);
AssemblerInstruction* i = &(inst);
AInstruction* a = dynamic_cast<AInstruction*>(i);
EXPECT_EQ(a->getLine(), "R3");
}
Running this gives this error:
unknown file: error: SEH exception with code 0xc0000005 thrown in the test body.
And stepping through the code, when the debugger is on the final line of the function, a
is pointing to
0x00000000 <NULL>
.
I imagine this is an instance where I don't have a full enough understanding of C++, meaning that I could be making a n00b mistake. Or maybe it's some bigger crazy problem. Help?
Update
I've been able to make this work by making mInstruction
into a (dumb) pointer:
// in parser, when parsing
mInstructionPtr = new AInstruction(assemblyCode.substr(1), lineNumber);
// elsewhere in AssemblerInstruction.cpp
AssemblerInstruction* AssemblyParser::getInstructionPtr() { return mInstructionPtr; }
TEST(ParserA, parsesBuiltInConstants)
{
auto ptr = Parser("@R3", 0).getInstructionPtr();
AInstruction* a = dynamic_cast<AInstruction*>(ptr);
EXPECT_EQ(a->getLine(), "R3");
}
However I have trouble implementing it with a unique_ptr
:
(I'm aware that mInstruction
(non-pointer) is redundant, as are two types of pointers. I'll get rid of it later when I clean all this up)
class AssemblyParser
{
public:
AssemblyParser(std::string assemblyCode, unsigned int lineNumber);
AssemblerInstruction getInstruction();
std::unique_ptr<AssemblerInstruction> getUniqueInstructionPtr();
AssemblerInstruction* getInstructionPtr();
private:
AssemblerInstruction mInstruction;
std::unique_ptr<AssemblerInstruction> mUniqueInstructionPtr;
AssemblerInstruction* mInstructionPtr;
};
// in AssemblyParser.cpp
// in parser as in example above. this works fine.
mUniqueInstructionPtr = make_unique<AInstruction>(assemblyCode.substr(1), lineNumber);
// this doesn't compile!!!
unique_ptr<AssemblerInstruction> AssemblyParser::getUniqueInstructionPtr()
{
return mUniqueInstructionPtr;
}
In getUniqueInstructionPtr
, there is a squiggle under mUniqueInstructionPtr
with this error:
'std::unique_ptr<AssemblerInstruction,std::default_delete>::unique_ptr(const std::unique_ptr<AssemblerInstruction,std::default_delete> &)': attempting to reference a deleted function
What!? I haven't declared any functions as deleted or defaulted!