5

C ++基本クラスをprotected継承に変更したところ、dynamic_cast動作が停止しました。

protectedの動作を変更するために継承を変更する必要があるのはなぜdynamic_castですか?

struct Base {
  static Base *lookupDerived(); // Actually returns a Derived * object.
};

struct Derived : protected /* Switch this to public to get it working */ Base {
 static void test() {
   Base *base = lookupDerived();

   if (dynamic_cast<Derived *>(base)) {
      std::cout << "It worked (we must be using public inheritance)." << std::endl;
   } else {
      std::cout << "It failed (we must be using protected inheritance)." << std::endl;
   }
};
4

3 に答える 3

7

外部ユーザーは、クラスの保護されたメンバーまたはプライベート メンバーにアクセスできません。同じことが、保護された継承またはプライベート継承にも当てはまります。クラスの作成者は、外部ユーザーが保護された/プライベートなメンバーにアクセスすることを望んでいる以上に、外部のユーザーが保護された/プライベートな親クラスにアクセスすることを望んでいません。

1 つの理由: 親クラスに非仮想デストラクタがあるとします。基底クラス ポインターからインスタンス派生クラスを削除すると、未定義の動作が発生します。親クラスを保護/非公開にすることは、これを行うことができないことを意味します (脚注を参照)。

別の理由: 問題のクラスの作成者が、外部ユーザーが親クラスのパブリック メンバーにアクセスできないようにしたいとします。パブリック継承 ( is-a ) を使用して、それらのパブリック インターフェイスを保護またはプライベートに降格することもできますが、これは Liskov 置換の原則に違反します。保護された継承またはプライベートな継承は、is-a関係ではありません。これらのパブリック メソッドは、保護された継承またはプライベートな継承によって保護またはプライベートになります。protected/private 継承はis-a ではないため、Liskov 置換に問題はありません。

脚注: これには醜い方法があります: C スタイルのキャストを使用します。外部ユーザーは、基本クラスにアクセスできない場合でも、派生クラス ポインターを基本クラス ポインターにキャストできます。私にとっては、それが でコンパイルするもう 1 つの理由-Wold-style-cast -Werrorです。

于 2012-10-07T01:40:16.790 に答える
2

継承を保護に変更すると、2つのクラス間の関係はオブジェクトの外部から隠されます。

于 2012-10-07T00:57:46.983 に答える
2

プライベート (またはプロテクト) 継承は、パブリック継承とは意味的に異なります。それは「is-a」関係ではなく、「~に関して実装された」関係です。

つまり、基本クラスを派生オブジェクトへのハンドルとして使用することはできません。

于 2012-10-07T00:59:18.447 に答える