web-dev-qa-db-ja.com

プライベート/パブリックヘッダーの例?

誰かがパブリックヘッダーとプライベートヘッダーがどのように機能するかの例を教えてもらえますか?ネットでいくつか読んだことがありますが、サンプルコードではあまり役立つ情報を見つけることができません。静的ライブラリを作成するには、コードのパブリック部分とプライベート部分を分離するためにプライベートヘッダーを使用するようにアドバイスされました。いくつか読んだ後、私はそれがどのように機能するかについての一般的な考えを持っていますが、私を始めるための良い例を本当に感謝します。具体的には、インターフェイスファンクションをパブリックヘッダーに配置し、プライベート変数/関数をプライベートヘッダーに配置する方法がよくわかりません。ありがとう!

編集:

多分私は私の質問を正しく言葉にしていないかもしれませんが、私が意味したことは、例えば、myMath.hとmyMath.cppがあり、myMath.hは:

class myMath{
public:
    void initialise(double _a, double _b);
    double add();
    double subtract();

private:
    double a;
    double b;
};

そして、myMath.cppには関数の実装があります。 myMath.hに3つのパブリック関数のみが含まれ、プライベート変数が別のファイル(例:myMath_i.h)で定義され、これら3つのファイルが静的ライブラリを作成した後、ユーザーにはmyMath.hのみが必要です。これは、myMath.hが#include myMath_i.hを実行できないことも意味します。したがって、次のようなもの:

myMath.h:

class myMath{
public:
    void initialise(double _a, double _b);
    double add();
    double subtract();
}

およびmyMath_i.h:

class myMath{
private:
    double a;
    double b;
}

もちろん、クラスmyMathを再定義するので、それは不可能です...

29
chocobo_ff

2つのヘッダーファイルMyClass.hおよびMyClass_p.hと1つのソースファイルMyClass.cppがあります。

それらの中身を見てみましょう:

MyClass_p.h:

// Header Guard Here
class MyClassPrivate
{
public:
    int a;
    bool b;
    //more data members;
}

MyClass.h:

// Header Guard Here
class MyClassPrivate;
class MyClass
{
public:
    MyClass();
    ~MyClass();
    void method1();
    int method2();
private:
    MyClassPrivate* mData;
}

MyClass.cpp:

#include "MyClass.h"
#include "MyClass_p.h"

MyClass::MyClass()
{
    mData = new MyClassPrivate();
}

MyClass::~MyClass()
{
    delete mData;
}

void MyClass::method1()
{
    //do stuff
}

int MyClass::method2()
{
    return stuff;
}

MyClassPrivateにデータを保持し、MyClass.hを配布します。

23
erelender

ライブラリユーザーに公開するすべてのインターフェイスと定数を個別のヘッダーファイル(またはファイルのセット)で宣言し、それを「inc」サブディレクトリに配置できます。これらのヘッダーは「パブリック」になります。また、実装の詳細であるため、他のヘッダーファイルを使用して、公開したくないクラスやものを宣言します。これらのファイルは「src」サブディレクトリに配置します。これらは「プライベート」になります。

このようにして、ユーザーにはパブリックヘッダーのみを含める必要があるというヒントが与えられます-「inc」にあり、それらのヘッダーのみが本当に必要なものを含み、他のすべてのヘッダーは「プライベート」であり、興味がない実装を読みたくない場合を除きます。

ライブラリをバイナリとして公開する場合-静的または動的ライブラリ-"inc"の内容とコンパイル結果のみをコピーします-これらはユーザーにとって十分であり、この方法で実装ソースが表示されません。

10
sharptooth

実際、2ヘッダー1ソースのアプローチは脆弱であることがわかりました。 'private'ヘッダーを変更した後で 'public'ヘッダーを更新し忘れた場合、コードがコンパイルされ、実行時に別の場所でsegfaultされる可能性があります。私はこれを何度か経験したことがあるので、すべてが正しくないとコンパイルされないコードを書くことを好みます。

MyClass.cppは次のように実装されています。

#define MYCLASS_IMPL
#include "MyClass.h"

// Implementation follows
...

MyClass.hは興味深いビットです。

#ifdef MYCLASS_IMPL
#include everything needed for the private: section
#endif

#include everything needed for the public: section only

class MyClass
{
public:
    // Everything that's public

#ifdef MYCLASS_IMPL
private:

    // Implementation details

#endif
};

実装の詳細を非表示にすることを目的とする場合(たとえば、閉じたライブラリ)、2ヘッダーアプローチを使用する必要がある場合があります。クラスを使用するためだけに依存関係をドラッグしたくない場合は、シングルヘッダーアプローチがシンプルで堅牢なソリューションになります。


Artonの質問に対処するには:これを見てから久しぶりですが、問題はパブリックヘッダーに基づいてオブジェクトをインスタンス化し、プライベートヘッダーで異なるオブジェクトサイズを想定することに関係していると思います。実行時に、オブジェクトへのオフセットが一致しないため、メモリが破壊されます。エレンレンダーの答えは、パブリック/プライベートクラスのペアでこのケースをカバーしているようです。

3
Daniel Schuler

パブリックヘッダーは、ライブラリのユーザーが必要とするヘッダーです。プライベートヘッダーは、ライブラリのコンパイルに必要ですが、ライブラリユーザーには必要ありません。分割を実行するのはかなりトリッキーになる可能性があり、多くのライブラリは単に気にしないでください。

2
anon

主なプログラミング言語としてCからC++に切り替えているので、同じことを考えていました。最善の方法は、インターフェース(C++では抽象クラス)を使用することです。パブリックインターフェースを公開し、プライベート実装は、インターフェースを基本クラスとして使用するだけです。

0
Spidey