2

次のようなものがあるとしましょう:

a.hpp:

class B;

class A
{
private:
  std::unique_ptr<B> b_;
}

a.cpp:

#include <something_complicated.hpp>

struct B
{
  something_complicated x;
}

something_complicated& A::get_complicated() { return b_->x; }

残念ながら、この場合、「get_complicated()」は A のメソッドではないため、a.cpp はコンパイルに失敗します。

したがって、これを試すことができます:

a.hpp:

class B;

class A
{
private:
  std::unique_ptr<B> b_;
  something_complicated& A::get_complicated();
}

しかし、something_complicated が定義されていないため、a.hpp はコンパイルに失敗します。

クラスの場合は something_complicited を前方宣言できますが、おそらく typedef であるため、それはできません。

b_ public を作成せず、a.hpp に something_complicited.hpp を含めずにこれを行う唯一の方法は次のとおりです。

a.cpp:

#include <something_complicated.hpp>

struct B
{
  something_complicated x;
}

#define get_complicated ((b_->x))

この問題を回避するためにマクロを定義する必要はありませんか? 代替案はありますか?

4

6 に答える 6

2

最も簡単な解決策は、複雑な型への参照をクラスでラップし、それを で前方宣言しa.hpp、 で定義することですsomething_complicated.hpp

a.hpp:

class B;
class complicated_ref;

class A
{
public:
  complicated_ref get_complicated();
private:
  std::unique_ptr<B> b_;
};

複雑な.hpp:

// ... complicated definitions ...
typedef whatever something_complicated;

struct complicated_ref
{
    complicated_ref(something_complicated & thing) : ref(thing) {}
    something_complicated & ref;
};

現在a.cpp、複雑な型を使用する必要があるものはすべてヘッダーを含める必要がありますが、使用したいだけのものclass Aは必要ありません。

Aこれは、一部のクライアントが複雑なものにアクセスする正当な理由があるが、すべての人がアクセスできないことを前提としていますBB必要に応じてアクセスを許可し、それを介して複雑なものにアクセスする方が簡単です。

于 2011-04-04T12:27:55.200 に答える
1

どうしたの:

a.hpp:

class B;

class A
{
private:
  std::unique_ptr<B> b_;
public:
  B& get_B();
}

クライアントがBから何か複雑なものを取得したい場合は、それらを許可します#include <something_complicated.hpp>

于 2011-04-04T13:28:27.503 に答える
1

something_complicatedinへの参照は避けてくださいa.hpp

get_complicated1 つの解決策は、メンバー関数をフリー関数または別のクラスの静的メソッドに置き換えることです。

.h :

class A_impl_base {
    A_impl_base() {}

    friend class A_impl; // all instances of A_impl_base are A_impl
}; // this stub class is the only wart the user sees

class A
{
private:
    std::unique_ptr< A_impl_base > b_; // this is not a wart, it's a pimpl

    friend class A_impl;
}

.cpp :

class A_impl : A_impl_base {
     static A_impl &get( A &obj ) { return * obj.b_; }
     static A_impl const &get( A const &obj ) { return * obj.b_; }
};
于 2011-04-04T12:09:06.183 に答える
1

何がクラスに属し、何がクラスに属さないかについて誤解があると思います。

クラスの内部で動作するすべてのメソッドがクラス メソッドである必要はありません。結局のところ、friend関数は既に存在します。多くの人がヘルパーメソッドをプライベート関数として宣言していることは知っていますが、そうすると不要な依存関係 (コンパイル時) とfriends の可視性の問題が発生します。

PIMPL を扱うときは、プライベート関数を使用しない傾向があります。代わりに、次の選択肢があります。

  • Impl(あなたBの場合)独自の検証ロジックと真のAPIを備えた真のクラスにする
  • static無料関数 (または匿名名前空間で宣言された関数) の使用

どちらも良いので、最も適切と思われる方を使用してください。すなわち:

  • メソッド: 検証の問題に対処する場合
  • フリー関数: 前述の方法で表現できる計算用

クラスの不変条件を台無しにする可能性があるのはこれらのメソッドだけであり、不変条件が維持されるという確信が持てるようになるためです。

あなたの場合、どのアプローチがあなたに最も適しているかを決めるのはあなた次第です。

実際に:

a.cpp

#include <something_complicated.hpp>

struct B
{
  something_complicated x;
}

static something_complicated& get_complicated(B& b) { return b_.x; }

// or anonymous namespace instead
namespace {
  something_complicated& get_complicated(B& b) { return b_.x; }
}

あなたが持っていたものとそれほど違いはありませんね。

注: 私は匿名の名前空間よりも静的関数を好みます。名前空間はスコープを導入し、ファイルをふるいにかけるときにスコープは簡単には見られません。走行距離は異なる場合がありますが、どちらも同じ機能を提供します (機能について)。

于 2011-04-04T19:33:12.003 に答える
0

制御する場合something_complicated.hpp、標準ライブラリが行うことを行うことができます: something_complicated_fwd.hpptypedef である場合とそうでない場合がある型を含む、適切な前方宣言を持つ を作成します。

于 2011-04-04T14:10:22.290 に答える
0

クラスの場合は something_complicited を前方宣言できますが、おそらく typedef であるため、それはできません。

これはまさにあなたがしなければならないことです。そして、typedef が前方宣言を除外する方法がわかりません。

于 2011-04-04T12:11:16.220 に答える