1

dynamic_castingに少し問題があります。実行時にオブジェクトのタイプを判別する必要があります。これがデモです:

#include <iostream>
#include <string>

class PersonClass
{
  public:
  std::string Name;
  virtual void test(){}; //it is annoying that this has to be here...
};

class LawyerClass : public PersonClass
{
  public:
  void GoToCourt(){};
};

class DoctorClass : public PersonClass
{
  public:
  void GoToSurgery(){};
};

int main(int argc, char *argv[])
{

  PersonClass* person = new PersonClass;
  if(true)
  {
    person = dynamic_cast<LawyerClass*>(person);
  }
  else
  {
    person = dynamic_cast<DoctorClass*>(person);
  }

  person->GoToCourt();


  return 0;
}

上記をやりたいと思います。私がそれを行うために見つけた唯一の合法的な方法は、事前にすべてのオブジェクトを定義することです。

  PersonClass* person = new PersonClass;
  LawyerClass* lawyer;
  DoctorClass* doctor;

  if(true)
  {
    lawyer = dynamic_cast<LawyerClass*>(person);
  }
  else
  {
    doctor = dynamic_cast<DoctorClass*>(person);
  }

  if(true)
  {
    lawyer->GoToCourt();
  }

これに関する主な問題は(使用されないオブジェクトの束を定義する必要があることを除いて)、「person」変数の名前を変更する必要があることです。もっと良い方法はありますか?

(クラス(Person、Lawyer、またはDoctor)は、私のコードを使用する人々が持っているライブラリの一部であり、変更したくないため、変更することはできません)。

ありがとう、

デイブ

4

5 に答える 5

1

サブクラスに動的にキャストしてから、結果をスーパークラスへのポインターに割り当てることは役に立ちません。実際には、最初の場所に戻ります。動的キャストの結果を格納するには、サブクラスへのポインターが必要です。また、オブジェクトの具体的なタイプがである場合、PersonClassそれをサブクラスにダウンキャストすることはできません。動的キャストは、スーパークラスへのポインターがあるが、ポイントされたオブジェクトが実際にはサブクラスのインスタンスであることがわかっている場合にのみ機能します。

他の人も指摘しているように、最良のオプションは、クラス階層を再設計して、メソッドを実際に多態的にすることです。これにより、ダウンキャストの必要がなくなります。これらのクラスには触れられないため、ダウンキャストが必要です。これを使用する一般的な方法は次のようになります

PersonClass* person = // get a Person reference somehow

if(/* person is instance of LawyerClass */)
{
  LawyerClass* lawyer = dynamic_cast<LawyerClass*>(person);
  lawyer->GoToCourt();
}
else
{
  DoctorClass* doctor = dynamic_cast<DoctorClass*>(person);
  doctor->GoToSurgery();
}

更新:後でサブクラスインスタンスを使用する場合は、次のように実行できます。

PersonClass* person = // get a Person reference somehow
...
LawyerClass* lawyer = NULL;
DoctorClass* doctor = NULL;

if(/* person is instance of LawyerClass */)
{
  lawyer = dynamic_cast<LawyerClass*>(person);
}
else if(/* person is instance of DoctorClass */)
{
  doctor = dynamic_cast<DoctorClass*>(person);
}
...
if(lawyer)
{
  lawyer->GoToCourt();
}
else if (doctor)
{
  doctor->GoToSurgery();
}

このコードは、以前のバージョンよりも複雑でエラーが発生しやすいことに注意してください。私は間違いなくそのようなコードをリファクタリングして、以前のバージョンのように見せようと思います。YMMV。

于 2010-05-28T21:00:21.067 に答える
1

それらがポリモーフィック関数でない場合(Davidの回答で定義されているように)、これを行うことは非常に困難になります。

ラッパークラスをお勧めします。

class PersonWrapper {
    PersonClass* person;
    virtual void DoWork() = 0;
};
class DoctorWrapper : public PersonWrapper {
    DoctorClass* doc;
    virtual void DoWork() { doc->GoToSurgery(); }
};
class LawyerWrapper : public PersonWrapper {
    LawyerClass* lawyer;
    virtual void DoWork() { lawyer->GoToCourt(); }
};

もちろん、これにより、正しい条件でポインターを割り当てるなど、実装の詳細を定義する必要があり、ヒープの醜い使用法になります。ただし、多形機能を提供する必要があります。

PersonWrapper* wrap = new LawyerWrapper(new LawyerClass());
wrap->DoWork();

あなたが本当に必死である場合にのみ、私はこの種の解決策を使用することを検討します。

于 2010-05-28T21:19:57.490 に答える
0

dynamic_castより正確に型指定された参照または特定の型のオブジェクトへのポインタを取得できます。

オブジェクトのタイプを変更することはできません。構築されたオブジェクトのタイプは、C++では変更できません。新しいオブジェクトを作成する必要があります。

LawyerClass lawyer( person );

編集:サンプルをポリモーフィズムの大まかなデモに適合させるには、

  PersonClass* person = NULL;
  if(true)
  {
    person = new LawyerClass;
  }
  else
  {
    person = new DoctorClass;
  }

  if ( LawyerClass *lawyer = dynamic_cast< LawyerClass * >( person ) )
  {
    lawyer->GoToCourt();
  }

また、ではなく「空の」仮想デストラクタを使用する必要がありますvirtual void test() {}

于 2010-05-28T20:56:01.640 に答える
0

私はここでのポイントを完全に見逃しているかもしれませんし、あなたの例を誤解しているかもしれないので、私に知らせてくれれば私の投稿を削除します。

しかし、仮想メソッドを呼び出すdoJob(または同様のもの)と呼ばれるパブリックメソッドがあることは、より意味がありません。そうすれば、これを行うことができます。

#include <iostream> 
#include <string> 
using namespace std;

class PersonClass 
{ 
public: 
    std::string Name; 
    virtual void doWork(){}; //it is annoying that this has to be here... 
}; 

class LawyerClass : public PersonClass 
{ 
public: 
    void doWork(){GoToCourt();}
    void GoToCourt(){cout<<"Going to court..."<<endl;} 
}; 

class DoctorClass : public PersonClass 
{ 
public: 
    void doWork(){GoToSurgery();}
    void GoToSurgery(){cout<<"Doing surgery..."<<endl;}; 
}; 

int main(int argc, char *argv[]) 
{ 

    PersonClass* person; 
    if(true) 
    { 
        person = new LawyerClass(); 
    } 
    else 
    { 
        person = new DoctorClass(); 
    } 

    person->doWork(); 


    return 0; 
} 
于 2010-05-28T20:58:16.907 に答える
0

次のようなクラスにシムを追加することは可能ですか?

class Person
{
public:
    virtual void DoJob() = 0;
};

class Lawyer : public Person, public LawyerClass
{ 
public:
    virtual void DoJob()  { GoToCourt(); }
}; 

class Doctor : public Person, public DoctorClass
{ 
public:
    virtual void DoJob() { GoToSurgery(); }
}; 

void DoJob(Person& person)
{
    person.DoJob();
}

int main(int argc, char *argv[]) 
{
    Doctor doctor;
    Lawyer lawyer;
    DoJob(doctor); // Calls GoToSurgery();
    DoJob(lawyer); // Calls GoToCourt();
    return 0;
} 

このように、条件付きを使用する必要はありません。ただし、既存のライブラリコードを実際に変更できない場合、これは実際には「最後の手段」のソリューションであり、ユーザーはandの代わりにandを使用する必要DoctorLawyerありDoctorClassますLawyerClass

于 2010-05-28T21:05:43.097 に答える