2016-03-28 2 views
0

Setting a variable in a child classには、多型クラスの変数を正しく引き出す方法を見つけようとしていました。いくつかの助けを借りて、必要な情報に正しくアクセスするためにポインタにdynamic_castを使用する必要があることが分かりました。私はこれにいくつか問題があります。動的キャストを正しく実行する

これは私が現在取り組んでいる機能です。

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

} 

これは、ベクトルのイテレータに関する関連情報を持っている私のParser.h、です。ここで

#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 

}; 

私が受けていますエラーです:

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

ここで間違っているものを任意の手掛かり?

EDIT:コマンドのベクトルを使用することができないので、コマンドへのポインタが必要です。私は既にvector<Command>ではなくvector<Command*>を処理するためにParser.hを変更しました。入力のために私はこのような何か試してみました:

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

をしかし、これはかなりのベクトルは、ポインタではなく参照を期待しているように、私のために働いていません。メモリへのポインタを作成してベクトルにプッシュする最も簡単な方法は何でしょうか?

+0

エラーメッセージは、 'Command'がクラス名であることを示唆しています。これは、あなたの全体的なアイデアが破滅したことを意味します。あなたのベクトルは派生型のオブジェクトではなく、正確に 'Commands'しか含んでいないので、派生クラスへの' dynamic_cast'は常に失敗します。コンテナに共通の基本クラスを共有する異なる型のオブジェクトを「含む」ようにするには、コンテナはポインタのコンテナでなければなりません –

+0

ありがとう、ありがとう。 – Araganor

答えて

3

vectorCommandsである。 CommandA_COMMAND*にキャストすることはできません。 vector<Command>にはA_COMMANDを含めることはできません。 C++でランタイムポリモーフィズムを実行する場合は、ポインタまたは参照を使用する必要があります。この場合、Parser::commandsstd::vector<Command*>(またはstd::vector<std::shared_ptr<Command>>のようなタイプのスマートポインタ)である必要があります。

例えば、このコードを取る:

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

commandsA_COMMANDオブジェクトが含まれていません。それにはa_commandのコピーであるCommandオブジェクトが含まれています。なおこの多かれ少なかれequivilant:

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

はCで、覚えて++変数は、オブジェクトではなく、いくつかの他の言語(例えば、JavaやC#)のようにオブジェクトへの参照です。オブジェクトの種類を変更することはありませんが、あなたは派生型のオブジェクトを指す一種類の参照やポインタ持つことができます。この場合

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

commands[0]Command*あるが、それはA_COMMANDオブジェクトを指します。

RE編集:
あなたはポインタを追加しています。 &some_variablesome_variableへのポインタを返しますが、決して決してこれほどのことはしないでください。commandが有効範囲外になるとすぐに、それが破棄され、そのアクセスが未定義の動作になります。 newで動的メモリ割り当てを使用する必要があります。おそらくdeleteを心配する必要がないように、動的に割り当てられたオブジェクトを保持するためにstd::shared_ptr<Command>のようなスマートポインタクラスを使用することが最善でしょう。

あなたは生のポインタを使用する場合、このような何かが動作します:

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

あなたはそのアプローチで行く場合は、あなたが彼らと一緒に完了したら、あなたはおそらく(deleteにあなたのすべてのコマンドが必要になりますParserデストラクタ):

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

しかしstd::shared_ptr Sを使う方が良いでしょう。それらへの最後のshared_ptrがスコープの外に出るとき

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

次に、あなたのオブジェクトはすべて自動的にdelete EDを取得します。その後、std::vector<std::shared_ptr<Command>> commands;としてcommandsを宣言します。スマートポインタを使用する場合は、少し異なる方法でキャストする必要があります。 std::dynamic_pointer_castをご覧ください。

+0

これについてどうすればいいですか?イテレータがどのような種類のコマンドにアクセスしているのかを判断できるようにする必要があります。 – Araganor

+0

あなたは 'Command '型のオブジェクトであると宣言しているので、どのタイプのコマンドであるかはすでに分かっています。おそらく他のタイプではありません。 –

+0

私は、キャストを使用することの全体的なポイントは、基本クラスからどのような種類の派生クラスがあるかを確認することでしたか?パーサーは、すべてCommandから派生した3種類のコマンド(A_COMMAND、C_COMMAND、L_COMMAND)のベクトルを持っています。あなたは私がベクトルをサブタイプにキャストすることは不可能だと言っています。まあ、その場合、私は嫌になったと思いますか? – Araganor

-1

試し(それ)これは実際のデータにつながるとして、代わりに(*それ) イテレータを使用すると、*省略する必要があるので、出回っオブジェクトへのポインタであるべきではないあなたが持っている参照

+1

iteratirはポインタではない可能性があります。あなたはポインタを保証するために '&* it'と書くでしょう –

0

本当の質問はなぜdynamic_castを使用するのかです。 これは仮想メソッドの仕事です。 別のクラスが派生している場合は、dynamic_castも更新する必要があります。仮想メソッドでは、派生クラスのことを気にする必要はなく、仮想メソッドをオーバーライドするだけです。ベース(純粋仮想メソッド、状態なし)。これは、戦略パターンのアプリケーションのように聞こえます。 https://en.wikipedia.org/wiki/Strategy_pattern

関連する問題