web-dev-qa-db-ja.com

C ++はヘッダーファイルを削除する必要がありますか?

Java、C#などの多くの言語は、宣言と実装を分離していません。 C#には部分クラスの概念がありますが、実装と宣言は同じファイルに残ります。

C++に同じモデルがないのはなぜですか?ヘッダーファイルがある方が実用的ですか?

私はC++標準の現在および今後のバージョンを参照しています。

69
Sasha

私は日常的にC#とC++を切り替えていますが、C#にヘッダーファイルがないことは私の最大の悩みの種の1つです。クラスを実装するコードのページをたどる必要なしに、ヘッダーファイルを見て、クラスについて知る必要があるすべて(メンバー関数の呼び出し、呼び出し構文など)を学ぶことができます。

はい、部分クラスと#regionsについては知っていますが、同じではありません。クラス定義は複数のファイルに分散しているため、部分クラスは実際には問題を悪化させます。 #regionsに関する限り、現在行っている方法で拡張されることはないようです。そのため、ビューが正しくなるまで、これらの小さなプラスを拡張するために時間を費やす必要があります。

おそらく、VisualStudioのインテリセンスがC++でより適切に機能する場合、.hファイルを頻繁に参照する必要があるという説得力のある理由はありませんが、VS2008でも、C++のインテリセンスはC#に触れることができません。

22
Marc Bernier

下位互換性-ヘッダーファイルは下位互換性を損なうため、削除されません。

75
Gavin Miller

ヘッダーファイルにより、独立したコンパイルが可能になります。ファイルをコンパイルするために、実装ファイルにアクセスしたり、実装ファイルを用意したりする必要はありません。これにより、分散ビルドが容易になります。

これにより、SDKを少し簡単に実行することもできます。ヘッダーといくつかのライブラリのみを提供できます。もちろん、他の言語が使用するこれを回避する方法があります。

33
Steve Rowe

Bjarne Stroustrup でさえ、ヘッダーファイルを応急修理と呼んでいます。

しかし、必要なメタデータ(Javaクラスファイル、または.Net PEファイルなど)を含む標準のバイナリ形式がないと、この機能を実装する方法がわかりません。削除されたELFまたは。 outバイナリには、抽出する必要のある情報があまりありません。また、情報がWindowsXCOFFファイルに保存されることはないと思います。

31
Max Lybbert

C++の設計と進化 では、Stroustrupはもう1つの理由を示しています...

同じヘッダーファイルに2つ以上の実装ファイルを含めることができ、ソース管理システムを必要とせずに、複数のプログラマーが同時に作業することができます。

これは最近奇妙に思えるかもしれませんが、C++が発明されたときは重要な問題だったと思います。

18
Abhay

Cはコンパイラを簡単に書けるように作られました。それはその1つの原則に基づいてたくさんのことをします。ポインタは、ヘッダーファイルと同様に、コンパイラの記述を容易にするためにのみ存在します。 C++に引き継がれるものの多くは、コンパイラーの記述を容易にするために実装されたこれらの機能との互換性に基づいています。

実際には良い考えです。 Cが作成されたとき、CとUnixは一種のペアでした。 CはUnixを移植し、UnixはCを実行しました。このようにして、CとUnixはプラットフォーム間ですばやく拡散できましたが、アセンブリに基づくOSは、移植するために完全に書き直す必要がありました。

あるファイルでインターフェイスを指定し、別のファイルで実装を指定するという概念はまったく悪い考えではありませんが、それはCヘッダーファイルとは異なります。これらは、コンパイラがソースコードを通過する必要のあるパスの数を制限し、ファイル間のコントラクトを制限して抽象化して通信できるようにする方法にすぎません。

これらのアイテム、ポインタ、ヘッダーファイルなどは、他のシステムに比べて実際には何の利点もありません。コンパイラにさらに力を入れることで、まったく同じオブジェクトコードへのポインタと同じくらい簡単に参照オブジェクトをコンパイルできます。これがC++が現在行っていることです。

Cは素晴らしくシンプルな言語です。機能セットは非常に限られており、手間をかけずにコンパイラを作成できました。それを移植することは一般的に簡単です!私はそれが悪い言語か何かだと言っているのではありません。Cが作成されたときの主な目標は、現在は多かれ少なかれ不要な言語の残骸を残す可能性があるということですが、互換性のために残されます。


CがUnixを移植するために書かれたと本当に信じていない人もいるようですので、ここで:( from

UNIXの最初のバージョンはアセンブラー言語で書かれていましたが、Thompsonの意図は、高級言語で書かれることでした。

トンプソンは1971年に最初にPDP-7でFortranを使用しようとしましたが、初日以降はあきらめました。それから彼はBと呼ばれる非常に単純な言語を書き、それをPDP-7で使用しました。動作しましたが、問題がありました。まず、実装が解釈されたため、常に遅くなりました。第二に、ワード指向のBCPLに基づいたBの基本的な概念は、新しいPDP-11のようなバイト指向のマシンには適切ではありませんでした。

リッチーはPDP-11を使用してBに型を追加しました。これはしばらくの間、「新しいB」の場合はNB)と呼ばれ、その後、コンパイラーの作成を開始しました。 Cのフェーズは、実際にはこれらの2つのフェーズであり、最初に、Bからのいくつかの言語の変更、実際には、構文をあまり変更せずに型構造を追加し、コンパイラーを実行しました」とRitchie氏は述べています。

「第2段階は遅かった」と彼はCでUNIXを書き直すことについて語った。トンプソンは1972年の夏に始まったが、2つの問題があった。つまり、基本的なコルーチンを実行する方法、つまり制御を1つのプロセスから別の;また、元のバージョンのCには構造がなかったため、適切なデータ構造を取得するのが困難でした。

「これらの組み合わせにより、ケンは夏の間あきらめた」とリッチー氏は語った。 「1年にわたって、私は構造を追加し、おそらくコンパイラコードをいくらか良くしました-より良いコード-そして次の夏に、私たちは協調して努力し、実際にCでオペレーティングシステム全体をやり直しました。」


これが私の言いたいことの完璧な例です。コメントから:

ポインタはコンパイラの記述を容易にするためだけに存在しますか?いいえ。ポインターは、間接参照の概念を可能な限り単純に抽象化したものであるために存在します。 – Adam Rosenfield(1時間前)

あなたが正しいです。間接参照を実装するために、ポインターは実装するのに最も簡単な抽象化です。決して、それらを理解または使用するのが可能な限り簡単ではありません。配列ははるかに簡単です。

問題?配列をポインターと同じくらい効率的に実装するには、コンパイラーに膨大な量のコードを追加する必要があります。

ポインタなしでCを設計できなかった理由はありませんが、次のようなコードを使用します。

int i=0;
while(src[++i])
    dest[i]=src[i];

明示的なi + srcおよびi + destの追加を除外し、これが作成するのと同じコードを作成するようにするには、(コンパイラー側で)多くの労力が必要になります。

while(*(dest++) = *(src++))
    ;

事後にその変数「i」を因数分解するのは難しいです。新しいコンパイラはそれを行うことができますが、当時はそれが不可能であり、その安っぽいハードウェアで実行されているOSはそのような最適化をほとんど必要としませんでした。

現在、そのような最適化を必要とするシステムはほとんどありません(私は、最も遅いプラットフォームの1つであるケーブルセットトップボックスで作業しています。ほとんどのものはJavaで作成されています)。まれに、新しいCコンパイラが必要になる場合があります。自分でその種の変換を行うのに十分賢いはずです。

15
Bill K

ヘッダーファイルのないC++が必要な場合は、朗報です。

それはすでに存在し、Dと呼ばれます( http://www.digitalmars.com/d/index.html

技術的には、DはC++よりもはるかに優れているようですが、現時点では多くのアプリケーションで使用するには十分な主流ではありません。

14
Jeroen Dirks

C++の目標の1つは、Cのスーパーセットになることであり、ヘッダーファイルをサポートできない場合はCのスーパーセットにすることは困難です。また、拡張機能として、ヘッダーファイルを削除する場合は、CPP(プラスプラスではなくプリプロセッサー)を完全に削除することを検討することもできます。 C#とJavaは、標準でマクロプリプロセッサを指定していません(ただし、場合によっては、これらの言語でも使用でき、使用されることもあります)。

現在C++は設計されているため、外部関数とクラスを参照するコンパイル済みコードを静的にチェックするには、Cと同様にプロトタイプが必要です。ヘッダーファイルがない場合は、使用する前にこれらのクラス定義と関数宣言を入力する必要があります。 C++でヘッダーファイルを使用しない場合は、Javaのimportキーワードなどをサポートする機能を言語で追加する必要があります。これは大きな追加であり、変更されます。それが実用的であるかどうかというあなたの質問に答えるために:私はそうは思いません-まったくありません。

8
Peter

多くの人がヘッダーファイルの欠点を認識しており、C++にさらに強力なモジュールシステムを導入するアイデアがあります。 Modules in C++(Revision 5) by DaveedVandevoordeをご覧ください。

8
Piotr Dobrogost

実装ファイルとは別のコンポーネントでクラスインターフェイスを定義することには価値があります。

それはインターフェースで行うことができますが、その道を進むと、実装とコントラクトを分離するという点でクラスが不十分であると暗黙のうちに言っています。

Modula 2には、正しいアイデア、定義モジュール、および実装モジュールがありました。 http://www.modula2.org/reference/modules.php

Java/C#の答えは、同じものの暗黙の実装です(オブジェクト指向ですが)。

ヘッダーファイルは実装の詳細(プライベート変数など)を表すため、ヘッダーファイルは厄介です。

JavaおよびC#に移行すると、言語でIDE開発のサポート(クラスブラウザでパブリッククラスインターフェイスをナビゲートできるようにする)が必要な場合)、それなら、これはおそらく、コードが特に読みやすいというそれ自体のメリットに立っていないというステートメントです。

インターフェースと実装の詳細の組み合わせは非常に恐ろしいと思います。

重要なのは、実装とは関係なく、パブリッククラスの署名を簡潔でコメントの多いファイルに文書化する機能がないことは、言語設計が保守の便宜ではなく、作成者の便宜のために書かれていることを示しています。さて、私は今JavaとC#についてとりとめのないです。

2
polyglot

この分離の利点の1つは、インターフェイスのみを簡単に表示できることです。 なし を必要とする 高度なエディター

2
Dimitri C.

まあ、C++自体は、下位互換性のためにヘッダーファイルを削除するべきではありません。しかし、私はそれらが一般的にばかげた考えだと思います。クローズドソースのlibを配布したい場合は、この情報を自動的に抽出できます。実装を見ずにクラスを使用する方法を理解したい場合は、それがドキュメントジェネレーターの目的であり、ドキュメントジェネレーターは非常に優れた仕事をします。

2
dsimcha

これが決して起こらない理由が必要な場合:既存のC++ソフトウェアのほとんどすべてが壊れてしまいます。 C++委員会の設計ドキュメントのいくつかを見ると、さまざまな代替案を調べて、コードがどれだけ壊れているかを確認しました。

Switchステートメントを中途半端なインテリジェントなものに変更する方がはるかに簡単です。それはほんの少しのコードを壊すでしょう。それはまだ起こらないでしょう。

新しいアイデアのために編集:

C++とJava C++ヘッダーファイルが必要になる)の違いは、C++オブジェクトが必ずしもポインターであるとは限らないことです。Javaでは、すべてのクラスインスタンスはポインターによって参照されますが、そのようには見えません。 .C++には、ヒープとスタックにオブジェクトが割り当てられています。つまり、C++には、オブジェクトの大きさ、およびデータメンバーがメモリ内のどこにあるかを知る方法が必要です。

1
David Thornley

ヘッダーファイルは言語の不可欠な部分です。ヘッダーファイルがないと、すべての静的ライブラリ、動的ライブラリ、ほとんどすべてのプリコンパイル済みライブラリが役に立たなくなります。ヘッダーファイルを使用すると、すべてを簡単に文書化でき、コードのすべてのビットを調べることなく、ライブラリ/ファイルのAPIを調べることができます。

また、プログラムの整理も簡単になります。はい、常にソースからヘッダーに切り替える必要がありますが、実装内で内部APIとプライベートAPIを定義することもできます。例えば:

MySource.h:

extern int my_library_entry_point(int api_to_use, ...);

MySource.c:

int private_function_that_CANNOT_be_public();

int my_library_entry_point(int api_to_use, ...){
  // [...] Do stuff
}

int private_function_that_CANNOT_be_public() {

}

#include <MySource.h>の場合、my_library_entry_pointを取得します。

#include <MySource.c>の場合、またprivate_function_that_CANNOT_be_publicを取得します。

パスワードのリストを取得する関数、暗号化アルゴリズムを実装する関数、OSの内部を公開する関数、または特権を無効にする関数がある場合、それが非常に悪いことになる可能性があることがわかります。等.

0
Élektra

ヘッダーファイルのない言語は存在しません。それは神話です。

Javaのプロプライエタリライブラリディストリビューションを見てください(私はC#の経験はありませんが、同じだと思います)。完全なソースファイルを提供するわけではありません。すべてのメソッドの実装が空白になっているファイルを提供します({}または{return null;}など)そして彼らが隠して隠れることで逃げることができるすべてのもの。ヘッダー以外は呼び出すことができません。

技術的な理由はありませんが、CまたはC++コンパイラが、ファイルが直接コンパイルされていない限り、適切にマークされたファイル内のすべてをexternとしてカウントできる理由はありません。ただし、CもC++も解析が高速ではないため、コンパイルのコストは莫大になります。これは非常に重要な考慮事項です。ヘッダーとソースをマージするより複雑な方法では、コンパイラーがオブジェクトのレイアウトを知る必要があるなどの技術的な問題がすぐに発生します。

0
coppro