45

C++ プログラムでディレクティブusing namespaceとディレクティブの両方が必要なのはなぜですか?include

例えば、

#include <iostream>

using namespace std;

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

#include <iostream>他のものをただ持っているだけ、またはただ持っていusing namespace stdて取り除くだけでは、なぜ十分ではないのでしょうか?

(Java との類推を考えています。ここでは、import java.net.*からすべてをインポートしjava.netます。他に何もする必要はありません。)

4

11 に答える 11

51

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

それが行うことは、型をコンパイラに認識させることです。例を含めるだけ<string>で、次を参照できるようになりますstd::string

#include <string>
#include <iostream>

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

現在、ディレクティブの使用importは Java のようなものです。それらは、名前が表示されるスコープで名前を表示できるようにするため、名前を完全に修飾する必要はもうありません。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

于 2008-12-23T21:30:24.380 に答える
44

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

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

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

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

于 2008-12-23T20:10:42.217 に答える
15

C++#includeで、usingさまざまな機能があります。

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

これは、モジュールの概念がない C++ に由来します。

C++ の名前空間は開いていることに注意してください。つまり、異なるファイルが同じ名前空間の異なる部分を定義できることを意味します (.NET の部分クラスのようなものです)。

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

//b.h
namespace eg {
    void bar();
}
于 2008-12-23T20:12:17.127 に答える
8

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

使用することで、使いやすくなっています。

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

書くことで名前空間の使用を避けることができます。

std::cout << "Hello World";
于 2008-12-23T20:13:00.090 に答える
4

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

using キーワードは、名前空間の名前を現在の宣言領域で使用できるようにします。完全修飾名を常に使用する必要がないように、主に便宜上のものです。このページでは少し詳しく説明しています。

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

于 2008-12-23T20:22:55.093 に答える
4

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

using namespace std;必ずしも悪い考えではありませんが、すべての名前空間に使用すると、すべての利点が失われます。名前空間は、他のモジュールとの名前の衝突に関係なくモジュールを記述できるようにするために存在し、using namespace this; using namespace that;あいまいさを作成できます。

于 2008-12-23T21:34:02.733 に答える
4

他の答えは要点が少し欠けていると思います。C++、Java、および C# のすべてにおいて、using/importは完全にオプションです。だから違いはありません。

そして、3 つのプラットフォームすべてでコードを可視化するために何か別のことをしなければなりません。

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

C# では、他のアセンブリへの参照を追加する必要があります。これにより、includes および link 設定と同等の処理が行われます。

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

そのため、3 つのプラットフォームすべてで必要とされるものは非常に類似しており、using/ import(利便性) と実際のリンケージ解決 (要件) の分離は 3 つすべてで同じです。

于 2008-12-23T21:28:45.647 に答える
3

Stroustrupでさえ、この#includeメカニズムをややハックだと言っています。ただし、個別のコンパイルははるかに簡単になります(すべてのソースコードではなく、コンパイルされたライブラリとヘッダーを出荷します)。

問題は、実際には「なぜC ++は、すでに#includeメカニズムを備えていたのに、名前空間を追加したのか」ということです。

#includeなぜ十分でないのかについて私が知っている最良の例は、Sunからのものです。どうやらSunの開発者は、プロジェクトが実際に必要としたヘッダーを介して含まれているファイルから含まれている関数mktemp()と同じ署名を持つ関数を作成したため、製品の1つに問題があったようです。mktemp()

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

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

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

于 2008-12-23T22:20:55.743 に答える
3

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

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

于 2008-12-24T08:22:39.523 に答える
3

これを真に理解したい場合は、名前空間を理解する必要があります。

includeヘッダーファイルをインクルードしているだけです。

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

using namespace std;

あなたが使用するために、coutあなたはただ行うことができます

cout << "Namespaces are good Fun";

それ以外の:

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

そうしないと、ヘッダーが含まれていないため、宣言などで#include <iostream>no を使用できないことにstd::cout注意してください。cout

于 2008-12-23T20:13:25.627 に答える
2

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

于 2016-05-25T15:47:45.293 に答える