2

C++ での一般的な方法は、.h(または.hpp) 内の宣言と 内の実装を分離すること.cppです。

主な理由は 2 つあります (他にもあるかもしれません)。

  1. コンパイル速度 (1 つのファイルだけを変更する場合、すべてを再コンパイルする必要はありません。make事前にコンパイルされた.oファイルからリンクすることができます)
  2. 前方宣言が必要になる場合があります (class A依存のclass B実装とclass Bonの実装の場合class A ) ... しかし、私はこの問題を頻繁に抱えているわけではなく、通常は解決できます。

オブジェクト指向プログラミングの場合、次のようになります。

QuadraticFunction.h:

class QuadraticFunc{
    public:
    double a,b,c;
    double eval ( double x );
    double solve( double y, double &x1, double &x2 );
};

QuadraticFunction.cpp:

#include <math.h>
#include "QuadraticFunc.h"

double QuadraticFunc::eval ( double x ){ return c + x * (b + x * a ); };

double QuadraticFunc::solve( double y, double &x1, double &x2 ){ 
    double c_ = c - y;
    double D2 = b * b - 4 * a * c_;
    if( D2 > 0 ){
        double D = sqrt( D2 );
        double frac = 0.5/a;
        x1 = (-b-D)*frac;
        x2 = (-b+D)*frac;
    }else{  x1 = NAN; x2 = NAN; }
};

main.cpp:

#include <math.h>
#include <stdio.h>

#include "QuadraticFunc.h"

QuadraticFunc * myFunc;

int main( int argc, char* args[] ){

    myFunc = new QuadraticFunc();
    myFunc->a = 1.0d; myFunc->b = -1.0d; myFunc->c = -1.0d;

    double x1,x2;
    myFunc->solve( 10.0d, x1, x2 );
    printf( "soulution %20.10f %20.10f \n", x1, x2 );

    double y1,y2;
    y1 = myFunc->eval( x1 ); 
    y2 = myFunc->eval( x2 );
    printf( "check     %20.10f %20.10f \n", y1, y2 );

    delete myFunc;
}

makefile次に、次のようにコンパイルします。

FLAGS  = -std=c++11 -Og -g -w
SRCS   = QuadraticFunc.cpp main.cpp
OBJS   = $(subst .cpp,.o,$(SRCS))

all: $(OBJS)
    g++ $(OBJS) $(LFLAGS) -o program.x

main.o: main.cpp QuadraticFunc.h
    g++ $(LFLAGS) -c main.cpp

QuadraticFunc.o: QuadraticFunc.cpp QuadraticFunc.h
    g++ $(LFLAGS) -c QuadraticFunc.cpp

clean:
    rm -f *.o *.x

しかし、私はしばしば非常に不便だと思います

特に、コードを大幅に変更する場合 (たとえば、開発の初期段階で、プロジェクト全体の全体的な構造についてまだ確信が持てない場合)。

  1. クラス構造に大幅な変更を加える場合、コードの一部との間.cppを常に行き来する必要があります。.h
  2. エディターとプロジェクト フォルダーに 2 倍のファイルがあり、混乱しています。
  3. いくつかの情報 (関数ヘッダーや などQuadraticFunc::) を 2 回記述する必要があり、多くのタイプミスや不一致が発生する可能性があるため、コンパイラは常に文句を言います (私はそのような間違いを頻繁に行います)。
  4. 編集しなければならないクラスを追加/削除/名前変更するたびにMakefile、コンパイラ出力から追跡するのが難しい他の多くの間違いを犯します (たとえば、コードがすべての依存関係を再コンパイルするように Makefile を書くのを忘れることがよくあります)。編集 )

この観点から、私は Java の仕組みがより好きです。このため、すべてのコード (実装を含む) を に入れるだけで C++ プログラムを作成していました.h。このような:

#include <math.h>
class QuadraticFunc{
    public:
    double a,b,c;
    double eval ( double x ){ return c + x * (b + x * a ); }
    double solve( double y, double &x1, double &x2 ){ 
        double c_ = c - y;
        double D2 = b * b - 4 * a * c_;
        if( D2 > 0 ){
            double D = sqrt( D2 );
            double frac = 0.5/a;
            x1 = (-b-D)*frac;
            x2 = (-b+D)*frac;
        }else{  x1 = NAN; x2 = NAN; }
    };
};

次のようなユニバーサルデフォルトメイクファイルを使用します。

FLAGS  = -std=c++11 -Og -g -w

all : $(OBJS)
    g++ main.cpp $(LFLAGS) -w -o program.x

main.cpp同じままです)

しかし、より複雑なプログラムを書き始めると、常にすべてを再コンパイルする必要があるため、コンパイル時間が非常に長くなり始めます。

make(コンパイル時間の高速化)の利点を利用し、プログラム構造をJavaのような方法で整理.hする方法はありますか(別のandではなくクラス本体のすべて.cpp)、はるかに便利ですか?

4

4 に答える 4

5

しかし、より複雑なプログラムを書き始めると、常にすべてを再コンパイルする必要があるため、コンパイル時間が非常に長くなり始めます。

ヘッダーとクラス ファイルを分離する最良のポイントの 1 つは、すべてをコンパイルする必要がないことです。

class1.h、class1.cpp、class2.h、class2.cpp、...、classN.h、および classN.cpp がある場合、これらのヘッダーは各クラスのコンパイル済みオブジェクトにのみ含まれます。したがって、関数のロジックが class2 で変更され、ヘッダーが変更されない場合は、class2 をオブジェクト ファイルにコンパイルするだけで済みます。次に、実際の実行可能ファイルを生成するすべてのオブジェクト ファイルのリンクを行います。リンクは高速です。

大規模で複雑なプログラムを作成していて、ヘッダーの編集が問題であることがわかった場合は、アプリケーションを作成する前に設計することを検討してください。

于 2015-12-28T08:41:35.880 に答える
1

短い答え:いいえ。

長い答え: まだいいえ。

すべてのコードをヘッダー ファイルに入れるか、ヘッダーがインクルードされ、ソース ファイルが独自にコンパイルされる 2 つのファイルを使用します。

個人的には2つのファイルを使用しても問題ありません。ほとんどのエディターは「2 つのファイル ビュー」をサポートしており、そのほとんどは「定義へのジャンプ」もサポートしています。

すべての関数をクラス宣言内に配置すると、別の副作用も生じます。つまり、すべての関数がインラインでマークされるため、同じヘッダーが複数のソース ファイルに含まれている場合、出力バイナリで関数が複数回生成される可能性があります。

私の経験では、コンパイル時間は解析の結果ではなく、コンパイルのコード生成部分 (通常は .cpp ファイル) の結果であるため、いくつかの大きなヘッダーを含めても、おそらくそれほど問題にはなりません。 .

もちろんmake、プロジェクトをビルドするには、適切に定義された依存関係と共に [または類似のもの] を使用してください。

于 2015-12-28T08:40:40.263 に答える
1

C++ は C++ であり、Java は Java です。ソース コードを .h- ファイルと .cpp ファイルに分割することは、C++ の言語概念の一部です。気に入らないなら使うべきではありません。

すべてを 1 つのヘッダー ファイルに入れることは、実質的に .cpp ファイルを含めることと同じです (これは機能しますが、非常に不適切です)。次の場合は、これを行うべきではありません。

  • 標準クラス、関数などを書く...
  • 大きなプログラムでコード セクションを複数回使用する (それ以外の場合にすべてを main.cpp に含めると、再定義エラーが発生します)
  • 静的/動的ライブラリでプログラムの一部を外部委託したい。作成されたほとんどすべての利用可能なライブラリは、そのように機能します。

例: WindowsAPI (COM!!)、SFML、Boost (一部) (その他多数)

これは、次の場合に実行できます。

  • コードは非常に単純なことを行います。たとえば、ビット シフト操作 (カラー コードの作成)、文字列分析などです。

例:ブースト(一部)

次の場合にこれを行う必要があります。

  • ランタイムのコンパイル時に生成されるテンプレート クラスまたは関数の作成。これは .h/.ccp-concept の主な欠点の 1 つであり、最も議論されている欠点の 1 つです。

例: STL (C++ 標準テンプレート ライブラリ)

于 2015-12-28T09:13:50.700 に答える