web-dev-qa-db-ja.com

C ++名前空間とインクルード

C++プログラムで名前空間とincludeディレクティブの両方を使用する必要があるのはなぜですか?

例えば、

#include <iostream>

using namespace std;

int main() {
 cout << "Hello world";
}

#includeを使用するか、「using namespace std」を使用して他を削除するだけでは不十分なのはなぜですか?

(私はJavaとの類推を考えています。Java.netをインポートすると、Java.netからすべてがインポートされます。他に何もする必要はありません。)

30
duli

C++概念は別々です。これは仕様によるものであり、便利です。

名前空間がないとあいまいになるものを含めることができます。

名前空間を使用すると、同じ名前を持つ2つの異なるクラスを参照できます。もちろん、その場合はusingディレクティブを使用しないか、必要な場合は、必要な名前空間内の他の要素の名前空間を指定する必要があります。

また、使用する必要がないことに注意してください。std:: coutなど、アクセスする必要があるものを使用できます。アイテムの前に名前空間を付けます。

28
Tim

ディレクティブの使用とプリプロセッサディレクティブのインクルードは、2つの異なるものです。 includeは、JavaのCLASSPATH環境変数、またはJava仮想マシンの-cpオプションにほぼ対応しています。

それが行うことは、コンパイラに型を知らせることです。たとえば、<string>を含めるだけで、std::stringを参照できるようになります。

#include <string>
#include <iostream>

int main() {
    std::cout << std::string("hello, i'm a string");
}

現在、ディレクティブの使用はJavaのimportに似ています。名前が表示される範囲で名前が表示されるため、完全に修飾する必要はありません。 Javaと同様に、使用される名前は、表示される前に既知である必要があります。

#include <string> // CLASSPATH, or -cp
#include <iostream>

// without import in Java you would have to type Java.lang.String . 
// note it happens that Java has a special rule to import Java.lang.* 
// automatically. but that doesn't happen for other packages 
// (Java.net for example). But for simplicity, i'm just using Java.lang here.
using std::string; // import Java.lang.String; 
using namespace std; // import Java.lang.*;

int main() {
    cout << string("hello, i'm a string");
}

ヘッダーファイルでusingディレクティブを使用することはお勧めできません。これは、それを含む他のすべてのソースファイルで、修飾されていない名前のルックアップを使用してそれらの名前が表示されるためです。 Javaとは異なり、インポート行が表示されるパッケージに名前を表示するだけですが、C++では、ファイルが直接または間接的に含まれている場合、プログラム全体に影響を与える可能性があります。

実装ファイルであっても、グローバルスコープで行う場合は注意してください。できるだけローカルで使用することをお勧めします。名前空間stdの場合、私はそれを使用しません。私や他の多くの人々は、名前の前に常にstd::を書くだけです。しかし、たまたまそうした場合は、次のようにします。

#include <string>
#include <iostream>

int main() {
    using namespace std;
    cout << string("hello, i'm a string");
}

名前空間とは何か、なぜ必要なのかについては、Bjarne Stroustrupが1993年にC++標準に名前空間を追加するという提案を読んでください。それはよく書かれています:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1993/N0262.pdf

C++では#includeとusingには異なる機能があります。

#includeは、インクルードされたファイルのテキストをソースファイルに入れます(実際には translation unit )。一方、名前空間は、別の人が「foo」オブジェクトを作成できるように一意の名前を付けるためのメカニズムにすぎません。

これは、C++がモジュールの概念を持っていないためです。

C++の名前空間はオープンであること、つまり、異なるファイルが同じ名前空間の異なる部分(.NETの部分クラスのようなもの)を定義できることを覚えておいてください。

//a.h
namespace eg {
    void foo();
}

//b.h
namespace eg {
    void bar();
}
8
Motti

インクルードは、関数の存在を定義しています。

使用することで使いやすくなります。

iostreamで定義されているcoutは、実際には「std :: cout」という名前です。

ネームスペースの使用を避けることもできます。

std::cout << "Hello World";
6
James Curran

これらのキーワードは、さまざまな目的で使用されます。

Usingキーワードは、ネームスペースからの名前を現在の宣言領域で使用できるようにします。ほとんどの場合、完全修飾名を常に使用する必要がないようにするために便利です。これは page で詳細に説明されています。

#includeステートメントはプリプロセッサディレクティブであり、指定されたファイルのコンテンツを、ディレクティブが出現した時点でソースプログラムに現れたかのように扱うようにプリプロセッサに指示します。つまり、このステートメントは、インクルードされたファイルを現在のファイルにコピーすることと考えることができます。コンパイラは、あたかもすべてのコードを1つの大きなファイルに書き込んだかのように、ファイル全体をコンパイルします。

4

他の答えは少しポイントを欠いていると思います。すべてのC++、JavaおよびC#では、using/importは完全にオプションです。そのため、違いはありません。

そして、いずれにしても、3つのプラットフォームすべてでコードを表示するには、何か他のことを行う必要があります。

C++では、最低限それを現在の翻訳単位に含める必要があります(ベクトルや文字列などの多くの実装で十分です)。多くの場合、リンカーにも何かを追加する必要がありますが、一部のライブラリでは、インクルード(例:Windowsでビルドするときにブースト)。

C#では、他のアセンブリへの参照を追加する必要があります。これにより、インクルードとリンクの設定に相当するものが処理されます。

そしてJavaでは、関連するjarをそれに追加するなどして、コードがクラスパス上にあることを確認する必要があります。

したがって、3つのプラットフォームすべてで非常によく似たものが必要であり、using/import(便利)と実際のリンケージ解決(要件)の分離は、3つすべてで同じです。

4

これを真に理解したいのであれば、 namespaces を理解する必要があります。

includeを使用すると、ヘッダーファイルを含めるだけです。

using namespaceあなたは、coutなどを含む特定の名前空間を使用していることを宣言しています。したがって、これを行う場合:

using namespace std;

coutを使用するには

cout << "Namespaces are good Fun";

の代わりに:

std::cout << "Namespaces are Awesome";

しない場合は#include <iostream>どちらも使用できなくなりますstd::coutcoutも宣言に含めます。ヘッダーを含めないためです。

3
JohnIdol

指摘したように、C++とJavaは異なる言語であり、やや異なることを行います。さらに、C++はより「急成長した」言語であり、Java設計された言語の詳細。

using namespace std;は必ずしも悪い考えではありません。すべての名前空間に使用すると、全体的なメリットがなくなります。名前空間は、他のモジュールとの名前の衝突に関係なくモジュールを記述できるように存在し、using namespace this; using namespace that;はあいまいさを生み出す可能性があります。

3
David Thornley

C++では、includeディレクティブがヘッダーファイルをコピーして、前処理ステップでソースコードに貼り付けます。ヘッダーファイルには通常、名前空間内で宣言された関数とクラスが含まれていることに注意してください。たとえば、<vector>ヘッダーは次のようになります。

namespace std {
    template <class T, class Allocator = allocator<T> > class vector;
    ...
} 

メイン関数でベクトルを定義する必要がある場合、#include <vector>を実行すると、コードに上記のコードが含まれます。

namespace std {
    template <class T, class Allocator = allocator<T> > class vector;
    ...
}
int main(){
   /*you want to use vector here*/
}

コードでは、vectorクラスがまだstd名前空間にあることに注意してください。ただし、メイン関数はデフォルトのglobalネームスペースにあるため、ヘッダーを含めるだけではベクタークラスがglobalネームスペースに表示されません。 usingを使用するか、std::vectorのように接頭辞を付ける必要があります。

2
user2859314

Stroustrupも_#include_メカニズムをややハックと呼んでいます。ただし、個別のコンパイルがはるかに簡単になります(すべてのソースコードではなく、コンパイル済みのライブラリとヘッダーを出荷します)。

問題は、「C++はなぜ__#include_メカニズムをすでに持っているのに、名前空間を追加したのか」ということです。

_#include_が十分でない理由について私が知っている最良の例は、Sunからのものです。どうやらSunの開発者は、自分の製品の1つでいくつかの問題を抱えていました。なぜなら、これらのファイルから、mktemp()関数と同じシグネチャを持つmktemp()関数を作成したためです。プロジェクト自体が実際に必要とするヘッダー自体に含まれていました。

もちろん、2つの機能には互換性がなく、一方を他方の代替として使用することはできませんでした。一方、コンパイラとリンカーは、バイナリの構築時にこれを認識しませんでした。異なるファイルがコンパイルまたはリンクされた順序に基づいて、mktemp()が1つの関数を呼び出したり、別の関数を呼び出したりすることもありました。

この問題は、C++が元々はCと互換性があり、基本的にはその上にピギーバックされているという事実から生じます。Cにはグローバルネームスペースしかありません。 C++は、名前空間を介して、この問題をCと互換性のないコードで解決しました。

C#とJava(1)には名前空間メカニズムがあります(C#ではnamespace、Javaではpackage)、(2)は通常、開発者向けのバイナリを参照し、(3)独立した関数を許可しない(クラススコープは名前空間の一部であり、グローバル名前空間を汚染するリスクを軽減する)ため、この問題に対する別の解決策があります。ただし、どのメソッドを呼び出すかについて、あいまいさが残る可能性があります(たとえば、クラスが継承する2つのインターフェース間の名前の衝突)。その場合、3つの言語すべてで、プログラマが実際に探しているメソッドを明確に指定する必要があります。 、通常は親クラス/インターフェース名を先頭に追加します。

2
Max Lybbert

1つのライナー(これは何か新しいものではありません:)):

stdを使用を使用すると、std ::プレフィックスを省略できますが、iostreamを使用せずにcoutを使用することはできません。

2
PolyThinker