読み込み中...

C++の全知識を解説!初心者向け10のサンプルコードで完全理解

C++を徹底解説するイメージ C++
この記事は約25分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

C++は多様性とパワフルな機能で知られ、幅広い用途に使用されています。

ここでは、C++の基本から応用まで、初心者でも理解できるよう丁寧に解説していきます。

この記事を読むことで、C++の全体像を掴み、実際にコードを書く際に必要な知識を身につけることができるでしょう。

●C++とは

C++は、汎用プログラミング言語の一つで、中間レベルの言語です。

これは、ハードウェアに近い低レベルの操作と、抽象的な高レベルの操作の両方が可能であることを意味します。

C++は、C言語の拡張版として1983年に登場しました。

オブジェクト指向プログラミングのサポート、データ抽象化、メモリ管理の柔軟性など、C言語にはない多くの特徴を持っています。

○C++の歴史と特徴

C++は、1980年代初頭にBjarne Stroustrupによって開発されました。

彼は、C言語のシンプルさと効率性を維持しつつ、クラスやオブジェクトなどのオブジェクト指向機能を加えることを目指しました。

これにより、ソフトウェアの設計と保守がより容易になり、大規模開発に適した言語となりました。

また、C++は多重継承、テンプレート、例外処理など、他の多くのプログラミング言語にはない高度な機能を提供しています。

○C++でできること

C++は非常に多様な用途に使用されています。

システムプログラミング、アプリケーション開発、ゲーム開発、リアルタイムシステム、組み込みシステム、高性能サーバー、クライアントアプリケーションなど、幅広い領域で利用されています。

その性能の高さと効率性により、要求が厳しいシステムや、リソースが限られた環境での開発にも適しています。

また、科学技術計算やデータ分析などの分野でも、その処理速度と柔軟性が重宝されています。

●C++の基本文法と構造

C++は、柔軟性と強力な機能を兼ね備えたプログラミング言語です。

その文法と構造を理解することは、C++で効果的にプログラミングするための第一歩です。

ここでは、C++の基本的な文法の要素と構造について、初心者でも理解しやすいように解説します。

○変数とデータ型

C++プログラミングの基本となるのが変数です。

変数はデータを格納するためのコンテナであり、データ型によって格納できるデータの種類が決まります。

C++では、様々なデータ型が用意されており、主なものにはint(整数)、double(浮動小数点数)、char(文字)、string(文字列)などがあります。

各データ型は、メモリ使用量や扱えるデータの範囲が異なります。

例えば、整数を格納する変数を宣言するには、下記のように記述します。

int number;
number = 10;

ここで、intは整数型を表し、numberは変数名です。

変数numberに10という値を代入しています。

○演算子と制御構造

C++では、様々な演算子を使用してデータの操作や条件に基づく処理が行えます。

算術演算子(+-*/)、比較演算子(==!=<>)、論理演算子(&&||!)などが一般的です。

また、制御構造を用いて、プログラムの流れを制御できます。

代表的な制御構造には、if文(条件分岐)、for文(繰り返し)、while文(条件に基づく繰り返し)などがあります。

例えば、ある条件下で特定の処理を行う場合は、if文を使用します。

int number = 10;
if (number > 5) {
    std::cout << "numberは5より大きいです。";
}

このコードでは、numberが5より大きい場合にのみ、メッセージを表示しています。

○関数の定義と使用

関数は、特定のタスクを実行するためのコードの塊です。

関数を定義することで、コードの再利用性を高め、プログラムの構造を明確にすることができます。

C++では、関数を定義する際に戻り値の型、関数名、引数のリストを指定します。

例えば、2つの数を加算する関数は下記のように定義できます。

int add(int a, int b) {
    return a + b;
}

この関数addは、2つの整数abを引数として受け取り、その和を戻り値として返します。

関数の使用例は下記の通りです。

int result = add(5, 3);
std::cout << "結果: " << result; // 結果: 8

ここでは、add関数を呼び出して5と3を加算し、結果をresultに格納しています。

●C++でのオブジェクト指向プログラミング

C++は、オブジェクト指向プログラミング(OOP)を強力にサポートする言語です。

オブジェクト指向プログラミングは、データとそのデータを操作する手続きを組み合わせた「オブジェクト」としてプログラムを構築する方法です。

このパラダイムは、プログラムの再利用性、モジュール性、保守の容易さを向上させます。

○クラスとオブジェクトの基礎

C++におけるオブジェクト指向プログラミングの中心的な概念は「クラス」と「オブジェクト」です。

クラスはオブジェクトの設計図であり、オブジェクトはそのクラスのインスタンスです。

クラスはデータメンバ(属性)とメンバ関数(メソッド)で構成されます。

例えば、車を表すクラスを下記のように定義することができます。

class Car {
public:
    string brand;
    int year;
    void displayInfo() {
        std::cout << "ブランド: " << brand << "、年式: " << year << std::endl;
    }
};

ここでCarクラスには、ブランドと年式を表すデータメンバbrandyear、そして車の情報を表示するメンバ関数displayInfoがあります。

○継承、ポリモーフィズム、カプセル化

継承は、あるクラス(基底クラス)のプロパティやメソッドを別のクラス(派生クラス)が引き継ぐ機能です。

これにより、既存のコードの再利用と拡張が容易になります。

ポリモーフィズムは、同じインターフェースや基底クラスを持つ異なるオブジェクトが、異なる方法でそれらのインターフェースやメソッドを実装する能力を指します。

これは、プログラムの柔軟性を高めます。

カプセル化は、オブジェクトのデータ(属性)と方法(メソッド)を一つの単位にまとめ、データの直接的なアクセスを制限することです。

これにより、データの整合性と安全性が保たれます。

例えば、Carクラスを基底クラスとして、特別な種類の車を表す派生クラスを作ることができます:

class ElectricCar : public Car {
public:
    int batteryLife;
    void displayBatteryLife() {
        std::cout << "バッテリー寿命: " << batteryLife << "時間" << std::endl;
    }
};

ここでElectricCarクラスはCarクラスから継承されており、新たな属性としてbatteryLifeと新たなメソッドdisplayBatteryLifeを持っています。

●C++におけるメモリ管理

C++プログラミングにおける重要な側面の一つがメモリ管理です。

メモリ管理の適切な理解と使用は、効率的かつ安全なプログラムを作成するために不可欠です。

C++では、メモリの確保と解放をプログラマが直接制御することが多く、これには特に注意が必要です。

○ポインタと参照

C++では、ポインタと参照を用いてメモリアドレスにアクセスします。

ポインタはメモリアドレスを格納する変数であり、参照はあるオブジェクトを別の名前で参照するためのものです。

ポインタの基本的な使用方法は下記の通りです。

int var = 10;
int *ptr = &var;
std::cout << "varの値: " << var << std::endl;
std::cout << "ptrが指す値: " << *ptr << std::endl;

ここで、&varは変数varのアドレスを意味し、ptrはそのアドレスを保持するポインタです。

*ptrを用いてポインタが指す値にアクセスします。

参照は、別名を定義する際に使用されます。

int var = 10;
int &ref = var;
ref = 20;
std::cout << "varの値: " << var << std::endl; // varの値も20に変わる

このコードでは、refvarの参照(別名)として機能し、refを変更するとvarの値も変わります。

○動的メモリ割り当てと解放

C++では、newdelete演算子を使用して動的にメモリを割り当てたり解放したりすることができます。

動的メモリ割り当ては、実行時に必要なメモリ量を決定し、そのメモリを確保するプロセスです。

例えば、整数の動的割り当ては下記のように行います。

int *ptr = new int(5);
std::cout << "*ptr: " << *ptr << std::endl; // 出力: *ptr: 5
delete ptr; // 割り当てられたメモリを解放

ここで、new int(5)は整数を保持するためのメモリを動的に割り当て、そのメモリアドレスをptrに保存します。

delete ptrは割り当てられたメモリを解放します。

●C++の標準ライブラリとその利用

C++は、強力な標準ライブラリを持っており、これによってプログラマは様々な共通タスクを簡単に処理できます。

標準テンプレートライブラリ(STL)は、データ構造、アルゴリズム、関数オブジェクトなど、多くの有用な機能を提供します。

C++の標準ライブラリの理解は、効率的でモダンなC++プログラミングの基礎となります。

○STL(Standard Template Library)の概要

STLは、コンテナ、アルゴリズム、イテレータ、関数オブジェクトなどを含むライブラリです。

コンテナはデータ構造の一種で、ベクター(動的配列)、リスト、セット、マップなど様々な種類があります。

アルゴリズムは、ソート、検索、変換などの操作をコンテナに適用するための関数です。

イテレータは、コンテナ内の要素を指し示し、順序を持ってアクセスするための手段を提供します。

例えば、ベクターを使って整数のリストを作成し、それをソートするには下記のようにします。

#include <vector>
#include <algorithm>
#include <iostream>

int main() {
    std::vector<int> vec = {4, 1, 3, 5, 2};
    std::sort(vec.begin(), vec.end());
    for (int i : vec) {
        std::cout << i << " ";
    }
}

このコードは、ベクターに整数を格納し、std::sort関数を使って昇順にソートしています。

○ファイル入出力

C++の標準ライブラリには、ファイル入出力を行うための機能も含まれています。

<fstream>ヘッダーを使用することで、テキストファイルやバイナリファイルの読み書きが可能です。

例えば、テキストファイルから文字列を読み込むには下記のようにします。

#include <fstream>
#include <iostream>
#include <string>

int main() {
    std::ifstream file("example.txt");
    std::string line;
    while (std::getline(file, line)) {
        std::cout << line << std::endl;
    }
    file.close();
}

このコードでは、example.txtファイルを開き、ファイルの終わりまで一行ずつ読み込んでいます。

○例外処理

例外処理は、プログラム中のエラーを安全に処理するためのメカニズムです。

C++ではtrycatchthrowキーワードを使用して例外を処理します。

例外が発生すると、throwによって例外が投げられ、対応するcatchブロックで捕捉され処理されます。

例えば、ゼロによる除算を試みると例外を投げるような関数は下記の通りです。

#include <iostream>
#include <stdexcept>

int divide(int numerator, int denominator) {
    if (denominator == 0) {
        throw std::invalid_argument("分母が0です");
    }
    return numerator / denominator;
}

int main() {
    try {
        std::cout << divide(10, 0) << std::endl;
    } catch (const std::invalid_argument& e) {
        std::cerr << "エラー: " << e.what() << std::

endl;
    }
}

この例では、分母が0の場合にstd::invalid_argument例外を投げ、catchブロックで捕捉してエラーメッセージを表示しています。

●C++の応用例とサンプルコード

C++はその柔軟性と強力な機能により、さまざまな応用が可能です。

具体的なサンプルコードを通じて、C++の応用例を具体的に見ていきましょう。

これらの例は、C++の基本的な概念を理解し、実際のプログラミングに応用する際の参考になるでしょう。

○サンプルコード1:基本的な入出力

C++での基本的な入出力の例を見てみましょう。

下記のコードは、ユーザーからの入力を受け取り、それを画面に出力する簡単なプログラムです。

#include <iostream>
using namespace std;

int main() {
    string name;
    cout << "名前を入力してください: ";
    cin >> name;
    cout << "こんにちは、" << name << "さん!" << endl;
    return 0;
}

このプログラムは、cinを使用してユーザー入力を受け取り、coutを使用してそれを出力します。

<<オペレータは出力に、>>オペレータは入力に使用されます。

○サンプルコード2:簡単な計算プログラム

次に、基本的な数学的計算を行う簡単なプログラムの例を見てみましょう。

下記のコードは、2つの数値をユーザーから受け取り、その和を計算して出力しています。

#include <iostream>
using namespace std;

int main() {
    int num1, num2;
    cout << "2つの数値を入力してください: ";
    cin >> num1 >> num2;
    int sum = num1 + num2;
    cout << "合計: " << sum << endl;
    return 0;
}

このプログラムでは、cinを使用して2つの整数を入力し、それらの和を計算してcoutを使用して出力しています。

C++では、このように標準入出力を利用して対話的なプログラムを簡単に作成することができます。

○サンプルコード3:クラスとオブジェクトの使用例

C++でのクラスとオブジェクトの使用例を見てみましょう。

ここでは、簡単な「Car」クラスを定義し、そのインスタンス(オブジェクト)を作成して使用する方法を紹介します。

#include <iostream>
using namespace std;

class Car {
public:
    string brand;
    int year;

    Car(string b, int y) {
        brand = b;
        year = y;
    }

    void displayInfo() {
        cout << "車のブランド: " << brand << "、年式: " << year << endl;
    }
};

int main() {
    Car car1("Toyota", 2020);
    car1.displayInfo();
    return 0;
}

このコードでは、Carクラスにブランドと年式の情報を持たせ、それらのデータを表示するdisplayInfoメソッドを定義しています。

main関数内でCarクラスのインスタンスを作成し、そのメソッドを呼び出しています。

○サンプルコード4:ファイル操作

C++におけるファイル操作の基本を表すサンプルコードを紹介します。

この例では、テキストファイルを読み込み、その内容を画面に出力します。

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
    ifstream inputFile("example.txt");
    string line;

    if (inputFile.is_open()) {
        while (getline(inputFile, line)) {
            cout << line << endl;
        }
        inputFile.close();
    } else {
        cout << "ファイルを開けませんでした。" << endl;
    }

    return 0;
}

このプログラムでは、ifstreamオブジェクトを使用してファイルを開き、getline関数を用いてファイルの内容を一行ずつ読み込み、画面に出力しています。

ファイルが正常に開かなかった場合のエラーメッセージも表示しています。

○サンプルコード5:例外処理

C++における例外処理は、プログラム実行中に予期しないエラーが発生した際にこれを捉えて適切に対応するための仕組みです。

下記のサンプルコードでは、除算を行う際に0で割るという例外を捕捉し、エラーメッセージを表示する方法を表しています。

#include <iostream>
using namespace std;

int main() {
    int a = 10, b = 0, c;
    try {
        if (b == 0) {
            throw "ゼロ除算エラー";
        }
        c = a / b;
        cout << "結果は " << c << endl;
    } catch (const char* msg) {
        cerr << "エラー: " << msg << endl;
    }
    return 0;
}

このコードでは、throwキーワードを使用して例外を発生させ、catchブロックでそれを捕捉しています。

これにより、ゼロ除算の際にプログラムがクラッシュすることなく、エラーメッセージを出力できます。

○サンプルコード6:STLの使用例

C++の標準テンプレートライブラリ(STL)は、データ構造やアルゴリズムなどを提供する強力なライブラリです。

下記のサンプルコードでは、STLのvectorを使用して動的配列を操作する方法を表しています。

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> vec;
    for (int i = 0; i < 5; i++) {
        vec.push_back(i);
    }

    cout << "ベクターの内容: ";
    for (int i = 0; i < vec.size(); i++) {
        cout << vec[i] << " ";
    }
    cout << endl;

    return 0;
}

このコードでは、vector<int>を使用して整数の動的配列を作成し、push_backメソッドで要素を追加しています。

そして、配列の内容をループを使って出力しています。

STLのvectorはサイズが動的に変更でき、配列のように要素にアクセスすることができます。

○サンプルコード7:メモリ管理

C++におけるメモリ管理は、プログラムのパフォーマンスと安定性を高めるために重要な要素です。

下記のサンプルコードでは、動的メモリ割り当てとその解放の方法を表しています。

#include <iostream>
using namespace std;

int main() {
    int* p = new int(5);
    cout << "割り当てられたメモリの値: " << *p << endl;
    delete p;
    return 0;
}

このコードでは、newキーワードを使って整数のメモリを動的に割り当て、その後deleteを使用して割り当てられたメモリを解放しています。

動的メモリ割り当てを行う際には、不要になったメモリを確実に解放することが重要です。

○サンプルコード8:マルチスレッドプログラミング

マルチスレッドプログラミングは、複数のタスクを並行して実行することでプログラムの効率を高める手法です。

下記のサンプルコードでは、C++11のスレッド機能を使用してマルチスレッドプログラムを作成します。

#include <iostream>
#include <thread>
using namespace std;

void threadFunction() {
    for (int i = 0; i < 5; i++) {
        cout << "スレッドからの出力: " << i << endl;
    }
}

int main() {
    thread t(threadFunction);
    t.join();
    return 0;
}

このコードでは、std::threadクラスを使用して新しいスレッドを作成し、そのスレッドでthreadFunction関数を実行しています。

joinメソッドはメインスレッドが新しいスレッドの処理が完了するまで待機することを保証します。

○サンプルコード9:ネットワークプログラミング

ネットワークプログラミングは、C++での応用例の中でも特に強力な分野の一つです。

下記のサンプルコードは、基本的なTCPソケットを使用したクライアントとサーバー間の通信を行う例です。

#include <iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
using namespace std;

void startServer() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};

    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(8080);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    read(new_socket, buffer, 1024);
    cout << "Message from client: " << buffer << endl;
    close(new_socket);
    close(server_fd);
}

int main() {
    startServer();
    return 0;
}

このコードはサーバー側の実装で、クライアントからの接続を待ち受け、受信したメッセージを表示します。

○サンプルコード10:グラフィックスとGUI

C++はグラフィックスとGUIの開発にも広く用いられています。

下記のサンプルコードは、SFMLライブラリを使用して基本的なウィンドウを作成する例です。

#include <SFML/Graphics.hpp>
using namespace sf;

int main() {
    RenderWindow window(VideoMode(800, 600), "SFML window");
    while (window.isOpen()) {
        Event event;
        while (window.pollEvent(event)) {
            if (event.type == Event::Closed)
                window.close();
        }

        window.clear();
        // ここに描画処理を追加
        window.display();
    }

    return 0;
}

このコードは、800×600ピクセルのウィンドウを作成し、ウィンドウが閉じられるまで表示し続けます。

グラフィックスの描画処理は、window.clear()window.display()の間に記述します。

●C++の注意点と対処法

C++プログラミングにはいくつかの注意点があります。

最も一般的な問題はメモリ管理の誤りに関連しています。

例えば、未初期化の変数の使用、メモリリーク、野生のポインタなどがあります。

これらの問題は、プログラムの予期しない動作やクラッシュの原因となります。

解決策としては、変数を適切に初期化し、動的に割り当てられたメモリは必ず解放することが重要です。

また、ポインタを使用する際には、常に有効なメモリ領域を指していることを確認し、使用後はnullptrに設定することが推奨されます。

○一般的なエラーとその解決策

C++でよく見られるエラーには、データ型のミスマッチ、範囲外の配列アクセス、無限ループなどがあります。

これらのエラーは、注意深いコーディングとテストによって防ぐことができます。

例えば、データ型のミスマッチは、型変換を慎重に行うことで回避できます。

範囲外の配列アクセスを防ぐためには、配列のサイズを超えないようにループの条件を設定する必要があります。

無限ループは、ループの終了条件を正しく設定することで防げます。

○効率的なコードの書き方

効率的なC++コードを書くためには、いくつかの原則を守る必要があります。

まず、不必要なコピーを避けるために参照を使用します。

次に、関数やクラスの責任を明確にし、各関数やクラスが一つのことをうまく行うようにします。

また、不必要な再計算を避けるために、計算結果をキャッシュします。

さらに、アルゴリズムの選択に注意を払い、データ構造を適切に選ぶことも重要です。

最後に、コードのプロファイリングを行い、ボトルネックとなっている部分を特定し、最適化します。

●C++のカスタマイズと高度なテクニック

C++におけるカスタマイズと高度なテクニックには、独自のライブラリの作成やアルゴリズムの最適化などが含まれます。

これらの技術は、C++の機能を最大限に活用し、より効率的で柔軟なコードを実現するために不可欠です。

○ライブラリの作成と利用

独自のライブラリを作成することは、共通の機能を一箇所に集約し、再利用可能なコードベースを作る上で有効です。

ライブラリは、関数、クラス、テンプレートなど、再利用される可能性のあるコードの集合です。

これにより、プロジェクト全体のコードの重複を減らし、メンテナンスを容易にします。

ライブラリの作成には、適切なインターフェースの設計が重要で、ユーザーが簡単に使用でき、かつ柔軟性が保たれるようにする必要があります。

○パフォーマンス最適化

C++のパフォーマンス最適化には、多くの技術があります。

重要なのは、プログラムのボトルネックを特定し、その部分を最適化することです。

例えば、ループの最適化、不要なコピーの排除、メモリアロケーションの最適化などが挙げられます。

また、並列処理やマルチスレッドを利用することで、プログラムの実行速度を向上させることも可能です。

最適化は、プログラムの要件と目的に基づいて慎重に行う必要があります。

まとめ

この記事では、C++の基礎から応用に至るまでの知識を幅広くカバーしました。

メモリ管理、オブジェクト指向プログラミング、標準ライブラリの利用、例外処理、そして高度なテクニックまで、C++プログラミングの全面的な理解を支援するための情報を紹介しました。

この記事が、C++を深く理解し、効率的で安全なコードを書くためのガイドとなることを願っています。