3

FB Brokken(C ++ Annotationsの作者)による半年間のC ++コースでは、いわゆる実装ヘッダーの使用法を教えられました。これがフランクの慣習であることは知っていましたが、文字通り他の場所では見たことがありません。したがって、私はその概念を説明し、他の人々がこれをどのように作っているのか非常に興味があります。

アイデアは#include、クラスメンバーの実装の実装に必要なすべてのディレクティブ(クラス内の定義を記述していないと仮定)を1つのファイル、.ih実装ヘッダー、および#includeこのファイルをすべてのソースに配置することです。代わりにファイル。選択肢は、
1)#includeクラスヘッダー内のすべて、または
2)#includeすべてのソースファイル内のすべてのヘッダーです。

両方の選択肢の欠点は明らかです。1a)いくつかの追加を必要とするものを追加した後、このヘッダーを
使用してすべてのソースを再コンパイルする必要があります。 1b)クラスの明確なインターフェースであると思われるヘッダーファイルは、ユーザーが何に使用されているのかわからず、気にもしない大量のディレクティブで汚染されています。2a)各ソースファイルで何度も同じヘッダーを使用する必要があります。 2b)実装はこれらすべてによって汚染されており、少し乱雑に見えます。#include#include
#include#include
#include

ただ明確にします:

/* someclass.h(pp) */

#ifndef SOME_CLASS_H
#define SOME_CLASS_H

class SomeClass
{
    //some private data members
    public:
        SomeClass();
        void sayHi() const;
        // some more member functions
    private:
        // some private member functions
};

#endif

/* someclass.ih */

#include "someclass.h"
#include <iostream>
#include <vector>
using namespace std; 

// namespace is now only used in my implementations, other people
// including my headers won't accidentally import the entire std namespace.

/* sayhi.cc */

#include "someclass.ih"

void SomeClass::sayHi() const
{
     cout << "sayHi() says hi!\n";
}

繰り返しになりますが、問題は次のとおりです。そのようなコンベンションについて聞いたことがある人はいますか?私は誰かにそれを使い始めるように説得しましたか?私は個人的にそれが非常に有用な(明白でさえある)慣習であると思います、そして私はそれを他のどこにも見たことがないことに少し驚いています。

4

3 に答える 3

7

興味深い投稿。.ih ヘッダーに関する user1428839 (以下ではポスターと呼ばれます) のステートメントについてコメントすることから始めましょう。

まず、ポスターは次のように書いています。

...アイデアは、クラスメンバーの実装の実装に必要なすべての #include ディレクティブを配置するだけです... .ih 実装ヘッダーの 1 つのファイルに入れ、代わりにこのファイルをすべてのソースファイルに #include します。 .

定式化されたように、これは真実ではありません。混乱を避けるために、文の最後の部分は次のようにする必要があります。 ....ih ファイルが属するクラスのすべてのソース ファイル内。.ih アプローチでは、クラスヘッダーファイル (たとえば、someclass.h) はインターフェイスを提供するだけであり、宣言できるものだけを宣言する必要があります。したがって、SomeClassにクラス データ メンバがある場合std::ofstream *d_out、必要はありません#include <fstream>。代わりに、それで十分#include <iosfwd>です。これにより、クリーンなクラス インターフェイスが得られ、 に属していないが単にSomeClass.

次に、ポスターは次のように述べています。

1a) 追加の #include が必要なものを追加した後、このヘッダーを #include してすべてのソースを再コンパイルする必要があります。

それは本当ではありません。これは、追加ヘッダーによって宣言された機能が実際にインターフェイスで使用される場合にのみ必要です。そうでない場合、完全な再コンパイルは必要ありません。新しいデータ メンバーが追加された場合、または追加のヘッダーの要素がクラス インターフェイスで使用された場合 (ただし、インライン メンバーを使用している場合などはスタイルが悪い)、完全な再コンパイルが必要です。

ポスターが提起した次のポイント:

1b) クラスの明確なインターフェイスであるはずのヘッダー ファイルが、ユーザーが何に使用されているか分からず、気にも留めない大量の #include ディレクティブで汚染されます。

正解ですが、ここで重要な点は、クラス ヘッダーが太くなりすぎるということです。外部ソースにインクルードする必要があるたびにsomeclass.h、コンパイラは追加のヘッダーやそれらのヘッダーに含まれるヘッダーなどもすべて読み取る必要がありSomeClassます。ユーザーは必要のないものにお金を払う必要はないという格言があります。この場合、コンパイラーが (多くの場合) 役に立たない (多くの場合SomeClass) ヘッダー ファイルを読み取らなければならないために、追加のコンパイル時間が発生します。

poster によって提案された .ih 規則を使用する代わりの方法の 1 つは、必要なものを必要な場所に含めることです。実際、これは良い代替手段だと思いますが、多くの簿記と作業も必要になります。通常、クラス メンバーの実装には同じヘッダー ファイルが必要であり、それらを 1 つのファイルにまとめると、実装ヘッダーにはメンテナンスの 1 つのポイントを定義するという追加の利点があります。はい、コンパイラが特定のソースが必要としないヘッダーを読み取らなければならない場合、小さなオーバーヘッドが発生しますが、それは一度だけ発生します: クラスのコンパイル時で、(できれば、おそらく) たまにしか発生しません。

投稿者の投稿に対する反応のいくつかは、.ih アプローチの核となるポイントを少し誤解した結果であると思います。

  • クラスヘッダー自体は可能な限りスリムなままです
  • クラスを使用するソースは、厳密に必要とされるよりも長いコンパイル時間に悩まされることはありません
  • クラス開発者は、クラスのメンバーをコンパイルするために必要な一連のヘッダーを何度も含める必要はありません。代わりに、クラスの要件に合わせて調整されたヘッダーを 1 つだけ含める必要があります。

別の回答 (DeadMG による) は、すべてのソースを 1 つのソース ファイルにまとめることに焦点を当てていました。ある程度までは、これはスタイルの問題です。ある特定のプログラム用のソフトウェアを開発する場合、個人的な好みに合うのであれば、すべてのソースを 1 つのファイルに入れることもできます。個人的には、多くの関数のソースを並行して見たり操作したりするのが好きなので、これらのファイルを操作するのは非常に面倒で難しいと感じていますが、最終的にはもちろん好みの問題です。

ただし、後で別のプログラムで再利用する目的でソフトウェアを開発する場合、たとえば、ライブラリに追加することを念頭に置いてクラスを開発する場合は、間違いなく 1 関数 1 ファイル スキームを使用する必要があります。コンストラクターを検討してください。通常、クラスは一連のコンストラクターを提供し、コンテキストに合ったコンストラクターを選択します。クラスの実装が 1 つのソース ファイルに配置される場合、最終的なプログラムは過度に太くなります。リンカーは、コンストラクターを実装するオブジェクト ファイルと、そのプログラムに必要なオブジェクト ファイルをプログラムに追加する必要があるためです。などなど。したがって、完全に無意味に、非常に多くの追加のオブジェクトファイルにリンクされたプログラムになります。1 機能 1 ファイルの原則により、これが発生しなくなります。

于 2012-06-17T10:14:53.560 に答える
3

これがどこでも使われているのを見たことがありません。ほとんどのクラスでは、実装されているすべての関数が 1 つのファイルに含まれているため、必要なヘッダーを繰り返し指定しても問題はありません。

于 2012-06-16T13:15:06.550 に答える
1

理解できません。他のヘッダーからのクラス、ストラット、または typedef を使用するクラス メンバーまたはクラス メソッド パラメーターがあるとどうなりますか? そして、再コンパイルの問題を追加します...これは、レゲインのためのより多くの作業のようです。ヘッダーに必要なものだけをヘッダーに含め、実装に必要なものだけを impl に含める必要があります。それでおしまい。

于 2012-06-16T12:26:21.623 に答える