C++はC言語の拡張として開発されたオブジェクト指向言語です
そのため、C言語の上位互換言語であり、Cで書かれたプログラムの大部分は、C++のコンパイラでもコンパイルできます
※ただし、完全に互換性があるわけではありません
C++を学習するにあたり、C言語とC++の違いについて、説明をしていきます
プログラミングの考え方の違い
C言語とC++の大きな違いの一つは、プログラムの設計思想です
C言語は手続き型プログラミング
という考え方で、処理の手順を順番に関数を組み合わせて記述する言語です
これは、プログラムが一連の手順や関数として構成され、上から順番に実行されるという考え方で、構造化プログラミングという、制御構造を明確にする考え方も取り入れられています
一方、C++はオブジェクト指向プログラミング
という考え方を取り入れています
C++で重要なオブジェクト指向プログラミングは、現実世界の物を「オブジェクト」として捉え、それらが持つ「データ」と「機能」をまとめて扱う考え方で、「クラス」と「オブジェクト」という概念があります
クラスは設計図のようなもので、オブジェクトはその設計図に基づいて作られた実体です
クラスを使うことで、関連するデータと機能をひとまとめにし(カプセル化)、プログラムをより整理しやすく、部品のように再利用しやすくできます
一方、C言語にはクラスの概念はありません
手続き型との違い
C言語のような手続き型プログラミングでは、プログラムは一連の処理手順として記述されますが、オブジェクト指向では、データとそれに関連する操作を一体化したオブジェクトを中心にプログラムが構成され、オブジェクト同士がメッセージをやり取りすることで処理が進みます
メモリ管理の方法
メモリの管理方法にも違いがあります
C言語では、プログラマーがmalloc
やfree
といった関数を使って、メモリの確保と解放を明示的に行う必要があります
一方、C++では、RAII(Resource Acquisition Is Initialization)という考え方や「スマートポインタ」(自動的にメモリを解放してくれるポインタ)を利用することで、メモリ管理をより安全かつ自動的に行うことができます
RAIIは、オブジェクトの生存期間とリソースのライフサイクルを関連付けることで、リソースの解放漏れを防ぐ考え方です
入出力の方法
標準入出力の方法も異なります。
C言語ではprintf
やscanf
といった関数を使いますが、C++ではiostream
ライブラリのcout
やcin
といった機能を利用します
C++の入出力は、間違った型のデータを入力しようとするとコンパイラがエラーを検出するような機能により、柔軟性と安全性が高いという特徴があります
豊富な標準ライブラリ
C++は、C言語に比べて非常に豊富な標準ライブラリを持っています
特にSTL(Standard Template Library)と呼ばれるライブラリには、vector(可変長配列)、list(連結リスト)、map(キーと値のペアを格納するデータ構造)など、様々なデータ構造やsort(ソート)、find(検索)などのアルゴリズムが用意されており、効率的なプログラミングを支援します
C言語の標準ライブラリは、C++に比べて機能が限定的です
C言語とC++の簡単なコード例を示し、ソースの比較をしてみたいと思います
・「Hello! World」の出力
// C言語
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
//C++
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
・C言語とC++における単純な関数
両方の言語で単純な関数(例:2つの数値を加算する)を示します
//C言語
#include <stdio.h>
int add(int a, int b) {
return a + b;
}
int main() {
int sum = add(5, 3);
printf("The sum is: %d\n", sum);
return 0;
}
// C++
#include <iostream>
int add(int a, int b) {
return a + b;
}
int main() {
int sum = add(5, 3);
std::cout << "The sum is: " << sum << std::endl;
return 0;
}
C++でのプログラムの書き方
C++で画面に文字列を出力するプログラムを以下に示します
#include <iostream> // std::coutのため
#include <cstdlib> // EXIT_SUCCESSのため
int main(){
// コンソールにHello Worldと出力
std::cout << "Hello World" << std::endl;
// 正常に終了
return EXIT_SUCCESS;
}
実行結果
Hello World
ヘッダファイル
まず1行目をみてみましょう
#include <iostream>
これは、標準で提供されている入出力機能
を有効にするための様々な機能がつまったというヘッダを読み込むという命令になります
C++の標準ライブラリは、C言語の標準ライブラリを包含しつつ、C++固有の機能に対応した新しいヘッダファイルを提供する必要があったため、拡張子.h
がつかないファイルが用意されました
参考:https://cpprefjp.github.io/reference/iostream.html
2行目
#include <cstdlib>
一般的なユーティリティ関数を定義しています
参考:https://cpprefjp.github.io/reference/cstdlib.html
ここでは、あとで記載するEXIT_SUCCESSを使用するために、定義しています
main()関数
C言語と同様にmain()という名前の関数は、一番はじめに実行される特別な関数です
起動時にコマンドライン・パラメータを渡す場合はC言語同様に、以下のように記述します
#include <iostream>
#include <cstdlib>
int main(int argc,char* argv[]){
// コンソールにHello Worldと出力
for (int i=0;i<argc;i++){
std::cout << "argv[" << i << "]=" << argv[i] << std::endl;
}
// 正常に終了
return EXIT_SUCCESS;
}
実行結果
admin@lenovo:~/work$ ./a.out 1 2 3
argv[0]=./a.out
argv[1]=1
argv[2]=2
argv[3]=3
また、main()関数を抜ける場合正常に終了したことを表すため、
return EXIT_SUCCESS;
を記述しています
コメント
// コンソールにHello Worldと出力
コメントは//
または/* */
の2通り書く方法があります
ストリーム
std::cout << "Hello World" << std::endl;
- std::cout
std は「標準 (standard)」という意味の名前空間 (namespace) です
参考URL:https://cpprefjp.github.io/reference/iostream/cout.html
C++の標準ライブラリの機能は、この std 名前空間の中で以下のように定義されています
namespace std {
extern ostream cout;
extern wostream wcout;
}
cout は std 名前空間の中にあるオブジェクトで、標準出力ストリーム (standard output stream) を表します
通常、標準出力はコンソールの画面に接続されています
ストリームとは、プログラムと入出力先(ファイル、ネットワーク、コンソールなど)との間でデータをやり取りする流れを抽象化した概念です
ストリームを利用することで、異なる入出力先に対しても統一的な方法でデータの読み書きを行うことができます
<<
は挿入演算子と呼ばれます
この演算子は、右側のデータを左側のストリームに「挿入」する役割を果たします
ここでは、文字列 “Hello World” を標準出力ストリーム std::cout に送る(表示する)という意味になります
挿入演算子<<
は、C++において左シフト演算子(<<
)を多重定義したものです
多重定義とは、同じ演算子を異なる型に対して異なる振る舞いをさせる機能です
整数型に対する <<
:
整数型(int、unsigned int など)のオペランドに対して使用された場合、<<
はビット単位の左シフト演算を行います
これは、左側のオペランドのビットを指定された数だけ左に移動させ、空いたビットには0を詰める操作です
ストリーム型に対する <<
:
std::ostream クラス(およびその派生クラスである std::cout など)のオブジェクトが左側のオペランドである場合、<<
は挿入演算子として機能します
右側のオペランド(様々なデータ型が可能)の内容をストリームに書き出す役割を果たします
以下は、ストリームと整数に対して演算子を使用したサンプルプログラムです
std::cout << "0x001 << 4 = " << (0x001 << 4) << std::endl;
実行結果
0x001 << 4 = 16
(0x001 << 4)
(0x001 << 4) の部分では、整数リテラル 0x001 (16進数の 1、2進数では 00000001) に対して、左シフト演算子 << が適用されています
4 ビット左にシフトすると、00010000 (16進数では 0x010、10進数では 16) になります
参考URL:https://ja.cppreference.com/w/cpp/language/operator_arithmetic
- “Hello World”
これは文字列リテラル (string literal) と呼ばれるもので、二重引用符 (“) で囲まれた一連の文字です
このプログラムでは、表示したいメッセージそのものです - << std::endl
再び挿入演算子 <<
が使われています
std::endl も std 名前空間にあるオブジェクトで、改行文字を出力し、さらに出力バッファをフラッシュ(強制的に出力)する役割を持ちます
改行文字を出力することで、カーソルが次の行の先頭に移動します
出力バッファのフラッシュは、プログラムが意図したタイミングで確実に出力が行われるようにするためのものですstd::endl
はマニピュレータの一つです
マニピュレータについて
マニピュレータ(manipulator)は、C++の ヘッダーで定義されている特殊な関数またはオブジェクトであり、ストリーム(入力 std::cin や出力 std::cout など)のフォーマットや動作を制御するために使用されます
マニピュレータは、ストリームへの挿入演算子 (<<) や抽出演算子 (>>) と組み合わせて使用され、あたかもデータを出力または入力するかのように記述できます
たとえば、整数を16進で表示するには以下のように記述します
std::cout << std::hex << 255 << std::endl;
実行結果
ff
std::hex
をストリームに挿入すると、それ以降に出力される整数値が16進形式で表示されるようになります
C++を実行するには
拡張子について
ソースファイルは、拡張子をcpp
として保存します
(.ccや.cxxなど複数の拡張子の種類が認められていますが、一般的にcppが使われるので、ここでの説明はcppとします)
また、ヘッダーファイルには .h
(C言語由来) や .hpp
(C++でよく使われる) などの拡張子があります
コンパイルについて
gccコンパイラがインストールされている場合、以下のように実行します
c++ ソースファイル名.cpp
ソースファイルと同じフォルダにa.out
が生成されるので下記のように実行します
./a.out
コメント