2016-09-10 7 views
0

私は最近、.hファイルにたくさんの関数定義を持つライブラリを作成していましたが、ライブラリがより相互依存するようになったので、関数エラーの複数の定義にうまくいくようになったので、リファクタリングを減らすために、インラインでの私の関数ですが、私は同じ.hファイルで定義されたクラスのために何も変更する必要がないのだろうかと思います。クラスも重複してはならないのですか?複数の定義エラーが発生することなく、.hファイルにクラスと関数を入れないのはなぜですか?

+3

クラス*定義*を作成していないため、クラス*宣言*を作成しています。 – EJP

+1

'.hファイルにたくさんの関数定義を持つライブラリを書いていました。それが問題です。ヘッダーは*定義*ではなく*宣言*を含んでいなければなりません。 'リファクタリングを減らすために、私はすべての関数をインラインで宣言しました。それはそれを"修正する "正しい方法ではありません。ヘッダーに関数*宣言*を残し、実装*をcppファイルに移動します。 – dxiv

+0

ありがとう@EJP、私はクラス内で定義された関数は、デフォルトでインラインとして定義されているので、なぜそれらを変更する必要がないのかを説明していると思います。 – zimzam

答えて

2

ヘッダーに変数、関数、クラスを宣言し、そのヘッダーを複数の翻訳単位に組み込むことができます。問題はありません。しかし、あなたがやっているのは、という定義のの機能です。

クラスは、あなたがそうでなければ、あなたのクラスは非常に有用ではないので、は限り各コピーの内容が正確に一致するよう —この特別なルールが重要であり、複数の翻訳単位でそれらを定義することという点で特殊です。 と宣言されているクラスは、すぐに使用することはできませんが、宣言されている関数はすぐに使用できます。

これは、2種類の種類の異なる性質の単なる結果です。

// Declarations 
extern int x; // variable 
void foo(); // function 
class T;  // class 

// Definitions 
int x;   // variable 
void foo() {} // function 
class T {}; // class 
+0

あなたは、宣言されたクラスだけをあまり使うことができない理由を詳しく述べることができますか? – zimzam

+0

@zimzam:宣言されているクラス(私たちはこれを「前方宣言」と呼んでいます)は、非常に限られた方法でしか使用できません。基本的にクラスの「サイズ」を知る必要がないもの、またはそのメンバーがその中にいるもの。だからクラス 'T'では' T * 'や' T& 'を使って何かを行うことができます(あるいはそれをテンプレートのパラメータとして使うこともできます)。 'T'をインスタンス化したい、あるいは値を返す関数を宣言することを含む値による返り値をコピーするか、そのメンバーのいずれかにアクセスしたい場合は、完全な定義が必要です。関数呼び出しでこれが当てはまることはありません –

+0

これは読んだので意味がありますが、クラスの定義が同一であることを確認するのが簡単ならば、関数定義で同じことをするのはなぜですか?両方の関数定義が同じ場合、コンパイル時エラーを報告するのはなぜですか?代わりに2つの同一の関数定義が警告を出すのは理にかなっていませんか? – zimzam

1

ファンクションは、.hファイルにも入れることができますが、ファンクション定義だけでも使用できます。宣言ではなく、がテンプレート関数である場合を除きます。基本的にクラスと同じルールですが、クラスでは、クイック・アンド・ダーティなやり方でクラス内にすべてを入れ、定義と宣言を組み合わせます。これは本当に良い習慣ではありません。

ので:

これは.hファイルに行く:

int DoSomething(double x, double y); 

そして、これは、.cppファイル

int DoSomething(double x, double y) 
{   
    return static_cast<int>(x+y); 
} 

に行きながら、この(あなたがテンプレートを心配している場合、そうでありませんこれを無視してください)、のみ .hファイルに移動します。

template <typename T> 
int DoSomething(T x, T y) 
{   
    return static_cast<int>(x+y); 
} 

このすべてのことは楽しいものではありません。それには非常に正当な理由があります。なぜなら、.hファイルはAPIを表し、.cppファイルはの実装を表します。理想的には、APIは、事前に計画しており変更することはありません。一方、バグを修正するために、実装を更新することができます。

cppファイルをダイナミックリンクライブラリ(dll)または共有ライブラリにコンパイルすることができます。このライブラリは、APIを変更せずに更新できます。したがって、あなたのプログラムでは、同じAPIを.hファイルに含めて、と別の実装にリンクすることができます。

質問:テンプレートがファイル.hにのみ含まれる理由は、コンパイル済みのものは事前定義されたタイプである必要があるからです。どのような型であるのか知らなくても、何かをコンパイルすることはできません。

話はページに行くことができます...しかし、これは基本(私が願って)を説明するのに十分だと思います。

+0

私はこのレベルの説明のためにテンプレートを全く言及しませんでしたが、あなたがそうしたいのであれば、これは "これは.hファイルにしか行かない"というのは価値がないかもしれません。これは、通常、関数テンプレート_useful_を作成する唯一の方法です。 –

+0

@LightnessRacesinOrbitそれを有用にするとどういう意味ですか?どうしたらうまくいくのでしょうか?説明してください。 –

+2

'.cpp'ファイルに関数テンプレートを定義できます。しかし、別の翻訳単位で得られたスペシャライゼーションを使用したい場合、あなたは固執しています。そのため、私たちは通常、プログラム全体でテンプレートを使用できるようにするために、あるいは少なくとも複数の場所でテンプレートを使用できるようにするため、ヘッダー(またはヘッダーに含まれるファイル)に入れていました。 –

関連する問題