14

背景情報: これは Visual Studio 2008 で検出され、Visual Studio 2013 で再度確認されました。G++ はコードで叫びましたが、Visual はプライベート継承違反を黙って受け入れました。

したがって、Visual C++ では、次のコードがあります。

class Base {};
class Derived : Base {};      // inherits privately. Adding explicitly the
                              //    keyword private changes nothing

int main()
{
   std::auto_ptr<Base>(new Derived) ;   // compiles, which is NOT EXPECTED
   std::auto_ptr<Base> p(new Derived) ; // Does not compile, which is expected
}

最初の (一時的な) auto_ptr がコンパイルされるのはなぜですか? 私はデバッグでその中に行きました.パブリック継承で行うべきことを正確に行いました(正しいコンストラクタを呼び出すなど).

問題が auto_ptr の実装にあるのではないかと考えて (わかりません...)、次のスタンドアロン コードで問題を減らしました。

class Base {};
class Derived : Base {};

template <typename T>
class Ptr
{
   T * m_p;

   public :
      Ptr(T * p_p)
         : m_p(p_p)
      {
      }
} ;

int main()
{
   Ptr<Base>(new Derived) ;   // compiles, which is NOT EXPECTED
   Ptr<Base> p(new Derived) ; // Does not compile, which is expected
}

繰り返しますが、Derived は Base から非公開で継承されるため、コードがコンパイルされないことを期待していました。

しかし、一時的に作成すると機能します。

そして、それを std::auto_ptr のせいにすることはできません。

標準 (98 または 11 または 14) に見逃しているものはありますか、それともバグですか?

4

1 に答える 1

3

Derived*-to-へのBase*変換は、継承がプライベートであっても、C スタイルおよび関数型キャストで許可されます。いいえ、その場合は意味がありませんreinterpret_cast

これは標準では許可されていませんが、ほとんど許可されているよう見えるため、微妙なバグです。

5.2.3 明示的な型変換(関数表記)【expr.type.conv】

1 [...] 式リストが単一の式である場合、型変換式は対応するキャスト式 (5.4) と (定義されていて、意味が定義されている場合) 同等です。[...]

5.4 明示的な型変換(キャスト表記)【expr.cast】

4 によって実行される変換

  • const_cast(5.2.11) 、
  • static_cast(5.2.9) 、
  • a のstatic_cast後に a const_cast,
  • reinterpret_cast(5.2.10)、または
  • a のreinterpret_cast後に a const_cast,

明示的な型変換のキャスト表記を使用して実行できます。同じセマンティック制限と動作が適用されますが static_cast、次の状況で a を実行すると、基底クラスにアクセスできない場合でも変換が有効になります。

  • 派生クラス型のオブジェクトへのポインター、または派生クラス型の左辺値または右辺値は、明確な基本クラス型へのポインターまたは参照にそれぞれ明示的に変換できます。
  • [...]

あなたが得た状況では、コンパイラはそれをstatic_castfrom Derived*toとして解釈しauto_ptr<Base>、その中でstatic_cast、派生クラス型のオブジェクトへのポインターは、明確な基本クラス型のポインターに変換されます。したがって、標準で許可されているようです。

ただし、 からDerived*への変換は暗黙的であり、明示的な別の変換の一部としてBase*実行されるだけです。結局のところ、いいえ、標準では実際には許可されていません。

これをバグとして報告することをお勧めします。Csqのコメントから、関連するレポートがあり、明示的にstatic_castもこの変換が許可されていることがわかりますが、まったく同じではありません。その場合、 からDerived*への変換Base*は明示的ですが、ここでは暗黙的であり、Visual C++ は通常、暗黙的な変換でそれを拒否します。

複数の式を使用する関数型キャストでは、この誤解はあり得ないことに注意してください。コンパイラは次のものを正しく拒否します。

class Base { };
class Derived : Base { };

template <typename T>
class Ptr {
public:
  Ptr(T *a, T *b) { }
};

int main() {
  Ptr<Base>(new Derived, new Derived);
  // error C2243: 'type cast' : conversion from 'Derived *' to 'Base *' exists, but is inaccessible
}
于 2014-06-19T17:19:16.990 に答える