1. ホーム
  2. c++

スマートポインタで共変量戻り値を使用するには?

2023-08-27 10:59:41

質問

このようなコードを持っています。

class RetInterface {...}

class Ret1: public RetInterface {...}

class AInterface
{
  public:
     virtual boost::shared_ptr<RetInterface> get_r() const = 0;
     ...
};

class A1: public AInterface
{
  public:
     boost::shared_ptr<Ret1> get_r() const {...}
     ...
};

このコードはコンパイルできません。

ビジュアルスタジオでは、次のように表示されます。

C2555: 仮想関数の戻り値の型をオーバーライドすると、戻り値の型が異なり covariant

もし私が boost::shared_ptr を使わずに生のポインターを返すと、コードはコンパイルされます (これは 共変量戻り値型 によるものだと理解しています)。私は、この問題が boost::shared_ptrRet1 から派生したものではありません。 boost::shared_ptrRetInterface . しかし、私は boost::shared_ptrRet1 を他のクラスで使用するために、そうでなければ、私はリターンの後に返された値をキャストする必要があります。

  1. 私は何か間違ったことをしているのでしょうか?
  2. もしそうでないなら、なぜこのような言語になっているのでしょうか。このシナリオでスマートポインタ間の変換を処理するために拡張可能であるべきなのでしょうか。望ましい回避策はありますか?

どのように解決するのですか?

まず、これはC++で実際に動作する方法です。派生クラスにおける仮想関数の戻り値の型は、ベースクラスと同じでなければなりません。あるクラス X への参照/ポインタを返す関数を、X から派生したクラスへの参照/ポインタを返す関数でオーバーライドできるという特別な例外がありますが、ご指摘のとおり、これでは スマート ポインタのような shared_ptr のような)、単なるポインタのためです。

もしあなたのインターフェイスが RetInterface が十分に包括的であれば、呼び出し側のコードで実際に返される型を知る必要はないでしょう。一般に、それはいずれにせよ意味をなしません。 get_rvirtual へのポインタや参照を通して呼び出すことになるからです。 AInterface この場合、派生クラスがどのような型を返すか知ることはできません。もし、これを実際の A1 の参照でこれを呼び出す場合は、単に別の get_r1 の中に A1 という関数があり、これが必要なことを行ってくれます。

class A1: public AInterface
{
  public:
     boost::shared_ptr<RetInterface> get_r() const
     {
         return get_r1();
     }
     boost::shared_ptr<Ret1> get_r1() const {...}
     ...
};

あるいは、ビジターパターンや、私の ダイナミック・ダブル・ディスパッチ テクニックを使って、返されたオブジェクトにコールバックを渡し、正しい型を使ってコールバックを呼び出すこともできます。