3

次のコードは、g++ 4.6.1 でコンパイルできません。

template<class Base>
struct GetBase {
  Base * getBase() {
    return static_cast<Base *>(this);
  }
};

template<class Derived>
struct Parent : private GetBase<Derived> {
  using GetBase<Derived>::getBase;
  int y() {
    return getBase()->x();
  }
};

struct Child : public Parent<Child> {
  int x() {
    return 5;
  }
  int z() {
    return y();
  }
};

エラーで

In member function ‘Base* GetBase<Base>::getBase() [with Base = Child]’:
    instantiated from ‘int Parent<Derived>::y() [with Derived = Child]’
    instantiated from here
error: ‘GetBase<Child>’ is an inaccessible base of ‘Child’

static_cast を reinterpret_cast に変更すると、コードがコンパイルされ、この場合は機能しますが、これがすべての場合に受け入れられる解決策であるかどうか疑問に思っていますか? つまり、基本クラスへのポインターがこれと同じでない場合はありますか? 親にデータメンバーがある場合、多重継承でこれが発生する可能性があると思いますか? GetBase が最初のスーパークラスである場合、this ポインターは等しいことが保証されていますか?

4

2 に答える 2

3

これがすべての場合に許容できる解決策であるかどうか疑問に思っていますか?

いいえ (下記参照)

基本クラスへのポインタがこれと同じではないということはありますか?

はい。

  • 多重継承では、基本クラスが同じアドレスを持つことは期待できません。

  • コンパイラーによっては、vtableポインターを持つ派生クラスは、vtableポインターをthis持つ基本クラスと同じではない場合があります。

ベースに明示的にアップキャストする場合static_castは、適切なC++キャストです。

于 2012-01-23T21:21:07.327 に答える
1

良い質問です。について何か新しいことを学ばせてくれましたstatic_cast

次のコードはあなたが望むものを達成すると思います:this派生型にキャストするメンバー関数を持つ CRTP の基本クラスを提供しますが、この基本クラスの直接の子孫にのみアクセスできるようにします。GCC 4.3.4 ( ideone でテスト済み) および Clang (llvm.org でテスト済み) でコンパイルされます。申し訳ありませんが、紛らわしい名前を変更することに抵抗できませんでした。

#include <iostream>

template<class Derived>
class CRTP {
protected:
  Derived * derived_this() {
    return static_cast<Derived *>(this);
  }
};

template<class Derived>
struct Parent : public CRTP<Derived> {
private:
  using CRTP<Derived>::derived_this;
public:
  int y() {
    return derived_this()->x();
  }
};

struct Child : public Parent<Child> {
  int x() {
    return 5;
  }
  int z() {
    return y();
  }
};

int main() {
  std::cout << Child().z() << std::endl;
  return 0;
}

static_castこのバリアントは、継承が public であるため機能します。これにより、ポインタから派生クラスへのポインタから基本クラスへのポインタへの標準変換が可能になり、 CRTP が必要とする を使用した逆変換 (基本から派生へ) も可能になります。 . コード内のプライベート継承により、これが禁止されました。そこで、継承をパブリックにして、メソッドをプロテクトするように変更し、プライベートセクションに宣言をParent入れることでさらにアクセスを制限しました。using

于 2012-01-23T22:54:07.760 に答える