0

In Setting a variable in a child class, I was trying to figure out how to correctly derive variables in polymorphic classes. After some help, I found out that I needed to use a dynamic_cast on a pointer to correctly access the information I need. I am having some trouble with this.

This is the function I am currently working on.

void translateLines(Parser parser, Code code)
{
    while(parser.hasMoreCommands())
    {
        vector<Command>::const_iterator it = parser.currentCommand();
        if(it->commandType() == "A")
        {
            //SubType* item = dynamic_cast<SubType*>(*the_iterator);
            A_COMMAND* a_command = dynamic_cast<A_COMMAND*>(*it); //line that is throwing the error
            //string symbol = a_command->get_symbol();
            //cout << "symbol: " << symbol << endl;
            //perform binary conversion
        }
        /*else if(command.commandType() == "C")
        {
            string dest = command.get_dest();
        }*/
         //shouldn't be any L commands in symbol-less version
        else
        {
            std::cout << "unexpected command value \n";
        }
        parser.advance();
    }

}

This is my Parser.h, which has the relevant information regarding the iterator for the vector.

#include "Command.h"
#include <vector>


class Parser {
private:
    std::vector<Command> commands;
    std::vector<Command>::const_iterator command_it = commands.begin();
public:
    Parser(std::vector<std::string>);
    bool hasMoreCommands() //are there more commands in the input?
    {
        if(command_it != commands.end())
            return true;
        else
            return false;
    }
    void advance(){std::next(command_it);} //move to next command, should only work if hasMoreCommands returns false}
    std::vector<Command>::const_iterator currentCommand(){return command_it;}
    std::vector<std::string> translateCommands(); //convert commands into binary strings

};

Here is the error I am receiving:

g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -o Assembler.o "..\\Assembler.cpp" 
..\Assembler.cpp: In function 'void translateLines(Parser, Code)':
..\Assembler.cpp:32:55: error: cannot dynamic_cast 'it.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator*<Command*, std::vector<Command> >()' (of type 'class Command') to type 'class A_COMMAND*' (source is not a pointer)
    A_COMMAND* a_command = dynamic_cast<A_COMMAND*>(*it);
                                                       ^

Any clue what's wrong here?

EDIT: So I see now that I can't use a vector of Commands, rather I need pointers to the commands. I already have changed Parser.h to handle vector<Command*> rather than vector<Command>. For the input I tried something like this:

A_COMMAND command();
commands.push_back(&command);

But this isn't quite working for me, as the vector is expecting pointers and not references. What would be the easiest way to create a pointer to the memory and push it into the vector?

Community
  • 1
  • 1
  • The error message suggest that `Command` is a class name. This means your whole idea is doomed. `dynamic_cast` to a derived class will always fail because your vector only contains precisely `Commands`, not any objects of derived type. If you want the container to 'contain' objects of different type sharing a common base class, the container must be a container of pointers – M.M Mar 28 '16 at 01:17
  • Well crap, thanks. – Stalemate Of Tuning Mar 28 '16 at 01:23

3 Answers3

3

You have a vector of Commands. You cannot cast a Command to an A_COMMAND*. It's important to note that a vector<Command> cannot possibly contain a A_COMMAND. If you want to do runtime polymorphism in C++, you have to use pointers or references. In this case your Parser::commands would need to be a std::vector<Command*> (or some type of smart pointer like std::vector<std::shared_ptr<Command>>).

Take for example this code:

std::vector<Command> commands;
A_COMMAND a_command;
commands.push_back(a_command);

commands does not contain an A_COMMAND object. It contains a Command object that is a copy of a_command. It more-or-less equivilant of this:

std::vector<Command> commands;
A_COMMAND a_command;
Command temp(a_command);
commands.push_back(temp);

Remember, in C++ a variable is an object, not a reference to an object like in some other languages (Java or C# for instance). Objects will never change type, but you can have a reference or pointer of one type that points to an object of a derived type:

std::vector<Command*> commands;
A_COMMAND a_command;
commands.push_back(&a_command);

In this case commands[0] is a Command*, but it points to an A_COMMAND object.

RE your edit:
You are adding a pointer. &some_variable returns a pointer to some_variable, BUT you should absolutely never, ever do something like that. As soon as command goes out of scope, it will be destroyed and any access to it will result in undefined behavior. You will need to use dynamic memory allocation with new. It would probably be best to use a smart pointer class like std::shared_ptr<Command> to hold your dynamically allocated objects so you don't have to worry about deleteing them later.

If you use raw pointers then something like this will work:

A_COMMAND* command = new A_COMMAND;
commands.push_back(command);

If you go with that approach, you'll need to delete all of your commands when you're done with them (probably Parser's destructor):

for(Command* command : commands) {
    delete command;
}

It would be better to use std::shared_ptrs though. Declare commands as std::vector<std::shared_ptr<Command>> commands;, then:

std::shared_ptr<A_COMMAND> command = std::make_shared<A_COMMAND>();
commands.push_back(command);

Then your objects will all get automatically deleteed when the last shared_ptr to them goes out of scope. If you use smart pointers you'll need to cast them slightly differently though. Look into std::dynamic_pointer_cast.

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52
  • Then how should I go about this? I need to be able to determine what kind of Command the iterator is accessing. – Stalemate Of Tuning Mar 28 '16 at 01:12
  • You already know what type of command it is, because you've declared it to be an object of the type `Command`. It cannot possibly be any other type. – Miles Budnek Mar 28 '16 at 01:13
  • I thought the whole point of using a cast was to check to see what kind of derived class I had from a base class? The parser has a vector of commands of 3 different types (A_COMMAND, C_COMMAND, and L_COMMAND) that all derive from Command. You're saying that since I called a vector it's impossible for me to cast them to a subtype. Well in that case I guess I am screwed? – Stalemate Of Tuning Mar 28 '16 at 01:17
  • Oh, I thought that an iterator was the pointer I needed. You're saying that the vector itself needs to be pointers? – Stalemate Of Tuning Mar 28 '16 at 01:19
  • @Araganor Yes. A `vector` can only objects of class `Command`, not any derived class. A `vector` can hold any `Command*`, which can be pointers to objects from any class derived from `Command`. – Chris Mar 28 '16 at 01:21
  • All right thanks. I might be able to salvage this, but oh man this would have been nice to know 6 hours ago... – Stalemate Of Tuning Mar 28 '16 at 01:22
  • I added some more detail about how runtime polymorphism works in C++, hopefully that clears things up a bit. – Miles Budnek Mar 28 '16 at 01:25
  • Thanks that does help clear things up. So, assuming I can change my vector to be of type vector, how should the cast look? – Stalemate Of Tuning Mar 28 '16 at 01:37
  • In that case it would just be `A_COMMAND* a_command = dynamic_cast(*it);`. Make sure you check that the returned pointer is non-null. `dynamic_cast` will return a null pointer if the object pointed to isn't actually an `A_COMMAND`. – Miles Budnek Mar 28 '16 at 01:42
  • Thanks again. I'm currently trying to convert my commands vector into a pointer vector. Good to know I got something right at least. – Stalemate Of Tuning Mar 28 '16 at 01:45
  • I added one more small question. If one of you kind gentlemen could help me that would be greatly appreciated. – Stalemate Of Tuning Mar 28 '16 at 02:04
  • Updated to answer your edit (even though it should probably have been a separate question). – Miles Budnek Mar 28 '16 at 02:25
0

The real question is why use dynamic_cast at all. This is a job for virtual methods. If another class is derived, then your dynamic_cast will also need updating, with a virtual method you do not need to be concerned what the derived class is, only that it overrides the virtual method, which can be forced by using an interface class for the base (pure virtual methods, no state). This sounds like an application for the strategy pattern. https://en.wikipedia.org/wiki/Strategy_pattern.

dgsomerton
  • 105
  • 5
-1

try (it) instead of (*it) the iterator should be a pointer to the object allready so you need to omit the * as this would result in the actual data not the reference

SteVoi
  • 17
  • 5
  • 1
    The iteratir might not be a pointer; you would write `&*it` to guarantee a pointer – M.M Mar 28 '16 at 01:16