C++ チュートリアル
C ++を使い始める
サーチ…
備考
'Hello World'プログラムは、単にコンパイラとライブラリの存在を確認するために使用できる共通の例です。 <iostream>
std::cout
と一緒にC ++標準ライブラリを使用し、コンパイル時にユーザーエラーが発生する可能性を最小限に抑えるために、コンパイルするファイルは1つだけです。
C ++プログラムをコンパイルするプロセスは、コンパイラとオペレーティングシステムによって本質的に異なります。 「 コンパイルとビルド」のトピックには、さまざまなコンパイラのさまざまなプラットフォームでC ++コードをコンパイルする方法の詳細が含まれています。
バージョン
バージョン | 標準 | 発売日 |
---|---|---|
C ++ 98 | ISO / IEC 14882:1998 | 1998-09-01 |
C ++ 03 | ISO / IEC 14882:2003 | 2003年10月16日 |
C ++ 11 | ISO / IEC 14882:2011 | 2011-09-01 |
C ++ 14 | ISO / IEC 14882:2014 | 2014-12-15 |
C ++ 17 | 未定 | 2017-01-01 |
C ++ 20 | 未定 | 2020-01-01 |
こんにちは世界
このプログラムは、 Hello World!
プリントしHello World!
標準出力ストリームに出力します。
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
}
分析
このコードの各部分を詳しく調べてみましょう。
#include <iostream>
は、標準C ++ヘッダファイルiostream
内容を含むプリプロセッサディレクティブです。iostream
は、 標準の入力ストリームと出力ストリームの定義を含む標準のライブラリヘッダーファイルです 。これらの定義は、以下で説明するstd
名前空間に含まれています。標準入力/出力(I / O)ストリームは、プログラムが外部システム(通常は端末)から入出力を取得する方法を提供します。
int main() { ... }
は、main
という名前の新しい関数を定義します。慣例により、main
関数はプログラムの実行時に呼び出されます。 C ++プログラムにはmain
関数が1つしかなくてはならず、常にint
型の数値を返す必要があります。ここで、
int
は関数の戻り値型と呼ばれるものです。main
関数が返す値は終了コードです。規則によって、プログラム終了コード
0
またはEXIT_SUCCESS
は、プログラムを実行するシステムによって成功として解釈されます。その他の戻りコードはエラーと関連しています。return
文がない場合、main
関数(したがってプログラム自体)はデフォルトで0
を返します。この例では、return 0;
を明示的に書く必要はありませんreturn 0;
。void
型を返す関数を除く他のすべての関数は、戻り値の型に従って明示的に値を返す必要があります。まったく返さないでください。
std::cout << "Hello World!" << std::endl;
「こんにちは!」と表示されます。標準出力ストリームに出力します。::
std
は名前空間であり、::
は名前空間内の名前によるオブジェクトのルックアップを可能にするスコープ解決演算子です。多くの名前空間があります。ここでは、
::
を使用してstd
名前空間からcout
を使いたいことを示します。詳細については、 Scope Resolution Operator - Microsoft Documentationを参照してください。std::cout
は標準出力ストリームオブジェクトで、iostream
で定義され、標準出力(stdout
)に出力されます。<<
はこの文脈では、オブジェクトをストリームオブジェクトに挿入するために呼び出されるストリーム挿入演算子です。標準ライブラリは、特定のデータ型に対して出力ストリームにデータ挿入を実行する
<<
演算子を定義します。stream << content
content
をストリームに挿入し、同じで更新されたストリームを返します。これにより、ストリームの挿入を連鎖させることができます:std::cout << "Foo" << " Bar";
コンソールに "FooBar"を表示します。"Hello World!"
文字列リテラル 、または "テキストリテラル"です。文字列リテラルのストリーム挿入演算子は、ファイルiostream
定義されています。std::endl
、ファイルに定義された特別なI / Oストリームマニピュレータオブジェクト 、あるiostream
。マニピュレータをストリームに挿入すると、ストリームの状態が変更されます。ストリームマニピュレータ
std::endl
は2つのことを行います:最初に行末の文字を挿入し、ストリームバッファをフラッシュして、コンソールにテキストを表示させます。これにより、ストリームに挿入されたデータが実際にコンソールに表示されます。 (ストリームデータは通常、バッファに格納され、すぐにフラッシュする場合を除いて、バッチで「フラッシュ」されます)。フラッシュを避ける別の方法は次のとおりです。
std::cout << "Hello World!\n";
\n
は、改行文字のための文字エスケープシーケンスです。セミコロン(
;
)は、ステートメントが終了したことをコンパイラーに通知します。すべてのC ++ステートメントとクラス定義には、セミコロンの終了/終了が必要です。
コメント
コメントは、任意のテキストをソースコードの中に入れ、C ++コンパイラがそれを解釈することなく機能的な意味で解釈する方法です。コメントは、プログラムの設計や方法を理解するために使用されます。
C ++には2種類のコメントがあります:
1行コメント
二重フォワードスラッシュシーケンス//
は、改行がコメントになるまですべてのテキストをマークします:
int main()
{
// This is a single-line comment.
int a; // this also is a single-line comment
int i; // this is another single-line comment
}
Cスタイル/ブロックコメント
シーケンス/*
はコメントブロックの開始を宣言するために使用され、シーケンス*/
はコメントの終わりを宣言するために使用されます。テキストがそれ以外では有効なC ++構文であっても、開始シーケンスと終了シーケンスの間のすべてのテキストはコメントとして解釈されます。このコメント構文はC ++の先行言語であるC言語から継承されているため、これらは「Cスタイル」のコメントと呼ばれることがあります。
int main()
{
/*
* This is a block comment.
*/
int a;
}
どのブロックコメントでも、あなたは何かを書くことができます。コンパイラがシンボル*/
遭遇すると、ブロックコメントを終了します。
int main()
{
/* A block comment with the symbol /*
Note that the compiler is not affected by the second /*
however, once the end-block-comment symbol is reached,
the comment ends.
*/
int a;
}
上記の例は有効なC ++(およびC)コードです。ただし、ブロックコメントの中に/*
を追加すると、一部のコンパイラで警告が表示されることがあります。
ブロックコメントは、1行で開始および終了することもできます。例えば:
void SomeFunction(/* argument 1 */ int a, /* argument 2 */ int b);
コメントの重要性
すべてのプログラミング言語と同様に、コメントにはいくつかの利点があります。
- 読みやすく/保守しやすくするコードの明示的な文書化
- コードの目的と機能の説明
- コードの歴史または推論の詳細
- 著作権/ライセンス、プロジェクトノート、特別な感謝、貢献者クレジットなどをソースコードに直接配置する。
しかし、コメントにも欠点があります。
- コード内の変更を反映するためにそれらを維持する必要があります
- 過度のコメントは、コードを読みにくくする傾向があります
コメントの必要性は、明確で自己文書化的なコードを書くことによって減らすことができます。簡単な例は、変数、関数、および型に説明的な名前を使用することです。論理的に関連するタスクを個別の機能に分解することは、これと関連しています。
コードを無効にするコメントマーカー
開発時にコメントを使用して、コードの一部を削除せずにすばやく無効にすることもできます。これはテスト目的やデバッグ目的には便利ですが、一時的な編集以外のスタイルには適していません。これはしばしば「コメントアウト」と呼ばれます。
同様に、バージョン管理システムを使用してコードの履歴を調べるのと比較して、ファイルを混乱させ、価値を提供しないため、参照目的でコメントの古いバージョンをコメントに残すことは嫌です。
関数
関数は、一連のステートメントを表すコードの単位です。
関数は引数または値を受け入れ、単一の値を返すことができます。関数を使用するには、引数の値に関数呼び出しを使用し、関数呼び出し自体の使用を戻り値に置き換えます。
すべての関数に型シグニチャ(引数の型と戻り型の型)があります。
関数は、手続きと数学関数の概念からインスピレーションを受けています。
- 注:C ++関数は基本的に手続きであり、数学関数の正確な定義や規則に従わない。
関数は多くの場合、特定のタスクを実行することを意図しています。プログラムの他の部分から呼び出すことができます。関数は、プログラムのどこかで呼び出される前に宣言され、定義されなければなりません。
- 注意:一般的な関数定義は、他のインクルードファイルに隠されることがあります(便宜上、多くのファイルに再利用されることが多い)。これはヘッダーファイルの一般的な使用です。
関数宣言
関数宣言は、その名前と型シグネチャを持つ関数の存在をコンパイラに宣言します。構文は次のとおりです。
int add2(int i); // The function is of the type (int) -> (int)
上記の例では、 int add2(int i)
関数はコンパイラに対して次のように宣言しています。
- 戻り値の型は
int
です。 - 関数の名前は
add2
です。 - 関数への引数の数は1です:
- 最初の引数は
int
型です。 - 最初の引数は、関数の内容で、名前
i
ます。
- 最初の引数は
引数名はオプションです。関数の宣言は次のようにもなります。
int add2(int); // Omitting the function arguments' name is also permitted.
1 つの定義ルールでは、特定の型シグネチャを持つ関数は、C ++コンパイラに表示されるC ++コードベース全体で1回のみ宣言または定義できます。つまり、特定の型シグニチャを持つ関数を再定義することはできません。一度だけ定義する必要があります。したがって、以下は有効なC ++ではありません。
int add2(int i); // The compiler will note that add2 is a function (int) -> int
int add2(int j); // As add2 already has a definition of (int) -> int, the compiler
// will regard this as an error.
関数が何も返さない場合、その戻り値の型はvoid
として書き出されvoid
。パラメータがない場合、パラメータリストは空でなければなりません。
void do_something(); // The function takes no parameters, and does not return anything.
// Note that it can still affect variables it has access to.
関数呼び出し
関数は宣言された後に呼び出すことができます。たとえば、次のプログラムは、 main
の関数内で値2
add2
を呼び出します。
#include <iostream>
int add2(int i); // Declaration of add2
// Note: add2 is still missing a DEFINITION.
// Even though it doesn't appear directly in code,
// add2's definition may be LINKED in from another object file.
int main()
{
std::cout << add2(2) << "\n"; // add2(2) will be evaluated at this point,
// and the result is printed.
return 0;
}
ここで、 add2(2)
は関数呼び出しの構文です。
関数定義
関数定義 *は宣言と似ていますが、本体内で関数が呼び出されたときに実行されるコードも含まれています。
add2
関数定義の例は、次のようになります。
int add2(int i) // Data that is passed into (int i) will be referred to by the name i
{ // while in the function's curly brackets or "scope."
int j = i + 2; // Definition of a variable j as the value of i+2.
return j; // Returning or, in essence, substitution of j for a function call to
// add2.
}
関数のオーバーロード
同じ名前で異なるパラメータを持つ複数の関数を作成することができます。
int add2(int i) // Code contained in this definition will be evaluated
{ // when add2() is called with one parameter.
int j = i + 2;
return j;
}
int add2(int i, int j) // However, when add2() is called with two parameters, the
{ // code from the initial declaration will be overloaded,
int k = i + j + 2 ; // and the code in this declaration will be evaluated
return k; // instead.
}
どちらの関数もadd2
という同じ名前で呼び出されますが、呼び出される実際の関数は呼び出しのパラメータの量と型に直接依存します。ほとんどの場合、C ++コンパイラは呼び出す関数を計算できます。場合によっては、そのタイプを明示的に記述する必要があります。
デフォルトパラメータ
関数パラメータのデフォルト値は、関数宣言でのみ指定できます。
int multiply(int a, int b = 7); // b has default value of 7.
int multiply(int a, int b)
{
return a * b; // If multiply() is called with one parameter, the
} // value will be multiplied by the default, 7.
この例では、1つまたは2つのパラメータを指定しmultiply()
を呼び出すことができます。パラメータが1つだけ指定された場合、 b
デフォルト値は7になります。デフォルトの引数は、関数の後の引数に配置する必要があります。例えば:
int multiply(int a = 10, int b = 20); // This is legal
int multiply(int a = 10, int b); // This is illegal since int a is in the former
特別な関数呼び出し - 演算子
C ++には、 name_of_function(value1, value2, value3)
とは異なる構文を持つ特別な関数呼び出しが存在しname_of_function(value1, value2, value3)
。最も一般的な例は演算子の例です。
!
などのコンパイラによって関数呼び出しに還元される特定の特殊文字シーケンス!
、 +
、 -
、 *
、 %
、 <<
などがあります。これらの特殊文字は、通常、プログラミング以外の使用に関連付けられているか、または美学に使用されています(たとえば、 +
文字は一般にC ++プログラミングと初等数学の両方で加算記号として認識されます)。
C ++では、これらの文字シーケンスを特殊な構文で処理します。本質的には、演算子の各出現は関数呼び出しに還元されます。たとえば、次のC ++式は次のとおりです。
3+3
次の関数呼び出しと同じです。
operator+(3, 3)
すべての演算子関数名はoperator
始まります。
C ++の直前のC言語では、C ++では異なる型シグネチャを持つ追加定義を提供することによって、演算子関数名に異なる意味を割り当てることはできませんが、これは有効です。 1つのユニークな関数名の下に追加の関数定義を隠すことは、C ++での演算子のオーバーロードと呼ばれ、C ++では比較的一般的ですが普遍的ではありません。
関数のプロトタイプと宣言の可視性
C ++では、使用前にコードを宣言または定義する必要があります。たとえば、次のようにコンパイル時エラーが発生します。
int main()
{
foo(2); // error: foo is called, but has not yet been declared
}
void foo(int x) // this later definition is not known in main
{
}
これを解決するには2つの方法があります: foo()
定義または宣言をmain()
使用する前に置くことです。ここに1つの例があります:
void foo(int x) {} //Declare the foo function and body first
int main()
{
foo(2); // OK: foo is completely defined beforehand, so it can be called here.
}
しかし、関数の前に "プロトタイプ"宣言だけを置いて、関数本体を後で定義することによって関数を "前方宣言"することも可能です:
void foo(int); // Prototype declaration of foo, seen by main
// Must specify return type, name, and argument list types
int main()
{
foo(2); // OK: foo is known, called even though its body is not yet defined
}
void foo(int x) //Must match the prototype
{
// Define body of foo here
}
プロトタイプでは、戻り値の型( void
)、関数の名前( foo
)、および引数リストの変数types( int
)を指定する必要がありますが、引数の名前は不要です 。
これをソースファイルの編成に統合する一般的な方法の1つは、すべてのプロトタイプ宣言を含むヘッダーファイルを作成することです。
// foo.h
void foo(int); // prototype declaration
他の場所で完全な定義を提供してください:
// foo.cpp --> foo.o
#include "foo.h" // foo's prototype declaration is "hidden" in here
void foo(int x) { } // foo's body definition
コンパイルされたら、対応するオブジェクトファイルfoo.o
をコンパイルされたオブジェクトファイルにリンクします。ここで、リンクフェーズで使用されますmain.o
:
// main.cpp --> main.o
#include "foo.h" // foo's prototype declaration is "hidden" in here
int main() { foo(2); } // foo is valid to call because its prototype declaration was beforehand.
// the prototype and body definitions of foo are linked through the object files
関数プロトタイプと呼び出しが存在しても、関数本体が定義されていないと、 "未解決の外部シンボル"エラーが発生します。これらは、最終的なリンク段階までコンパイラがエラーを報告しないため、エラーを表示するためにコード内でジャンプする行がわからないため、解決するのが難しい場合があります。
標準のC ++コンパイルプロセス
実行可能なC ++プログラムコードは、通常、コンパイラによって生成されます。
コンパイラは、コードをプログラミング言語から別の形式に変換するプログラムです。この形式は、コンピュータで直接実行可能な(より多くの)形式です。コンパイラを使用してコードを翻訳することをコンパイルと呼びます。
C ++は、コンパイルプロセスのフォームを "親"言語Cから継承します。以下は、C ++でのコンパイルの4つの主要なステップを示すリストです。
- C ++プリプロセッサは、インクルードされたヘッダファイルの内容をソースコードファイルにコピーし、マクロコードを生成し、#defineを使って定義されたシンボル定数をそれらの値に置き換えます。
- C ++プリプロセッサによって生成された展開されたソースコードファイルは、プラットフォームに適したアセンブリ言語にコンパイルされます。
- コンパイラによって生成されたアセンブラコードは、プラットフォーム用の適切なオブジェクトコードにアセンブルされます。
- アセンブラによって生成されたオブジェクトコードファイルは、実行可能ファイルを生成するために使用されるライブラリ関数のオブジェクトコードファイルとリンクされています。
- 注:一部のコンパイル済みコードはリンクされていますが、最終的なプログラムは作成されません。通常、この「リンクされた」コードは、他のプログラムで使用できる形式にパッケージ化することもできます。この「パッケージ化された使用可能なコードの束」は、C ++プログラマがライブラリと呼ぶものです。
多くのC ++コンパイラでは、コンパイルプロセスの特定の部分をマージまたはアンマージして、容易にまたは追加の解析を行うこともできます。多くのC ++プログラマはさまざまなツールを使用しますが、すべてのツールは一般に、プログラムの制作に携わるときに一般化されたこのプロセスに従います。
以下のリンクは、このディスカッションを拡張し、役立つ素晴らしいグラフィックを提供します。 [1]: http : //faculty.cs.niu.edu/~mcmahon/CS241/Notes/compile.html
プリプロセッサ
それは、ソースコードを編集し、いくつかのビットを切り取り、他のものを変更し、他のものを追加します。
ソースファイルには、プリプロセッサディレクティブを含めることができます。これらのディレクティブは、プリプロセッサに特定のアクションを実行するよう指示します。ディレクティブは新しい行の#で始まります。例:
#define ZERO 0
あなたが満たす最初のプリプロセッサディレクティブはおそらく
#include <something>
指令。それが何をするかは、 something
をすべて取って、指示があったファイルに挿入します。 こんにちは世界のプログラムは、
#include <iostream>
この行は、標準の入力と出力を使用できるようにする関数とオブジェクトを追加します。
プリプロセッサも使用するC言語では、C ++言語と同じ数のヘッダファイルがありませんが、C ++ではすべてのCヘッダファイルを使用できます。
次の重要な指令はおそらく
#define something something_else
指令。これは、ファイルに沿って進むにつれて、 something
でsomething_else
発生したsomething
置き換えられるべきことを前処理プロセッサに伝えます。関数と似たようなものにすることもできますが、それはおそらく高度なC ++とみなされます。
something_else
は必要ありませんが、 something
を何も定義しないと、プリプロセッサのディレクティブの外側にsomething
すべての出現が消滅します。
これは実際にあるためで、便利です#if
、 #else
と#ifdef
ディレクティブ。これらの形式は次のとおりです。
#if something==true
//code
#else
//more code
#endif
#ifdef thing_that_you_want_to_know_if_is_defined
//code
#endif
これらのディレクティブは、真ビットにあるコードを挿入し、偽ビットを削除します。これは、コード全体を書き換えることなく、特定のオペレーティングシステムにのみ含まれるコードのビットを使用するために使用できます。