C++/CからC++への移行
はじめに
編集C++は、C言語の強力な基盤の上にオブジェクト指向プログラミングやその他の高レベルな機能を追加した言語です。特にモダンC++(C++11以降の標準)は、コードの安全性、効率性、生産性を向上させる数多くの新機能を提供しています。この章では、C言語のプログラマがC++へ移行する際に役立つ情報を提供し、C++の利点とその新機能を紹介します。
基本的な違い
編集C++では、プログラムの構造化や名前の衝突を避けるために、名前空間が導入されています。C++の標準ライブラリは、すべてstd
という名前空間に含まれています。
#include <iostream> namespace MyNamespace { void hello() { std::cout << "Hello from MyNamespace!" << std::endl; } } auto main() -> int { MyNamespace::hello(); return 0; }
この例では、MyNamespace
という名前空間を定義し、その中にhello
関数を配置しています。これにより、名前の衝突を避けることができます。
プログラミングスタイルの変化
編集C++はオブジェクト指向プログラミング(OOP)をサポートし、データと関数をクラスという単位でまとめることができます。これにより、コードの再利用性や保守性が向上します。
class MyClass { public: void sayHello() { std::cout << "Hello, World!" << std::endl; } }; auto main() -> int { MyClass obj; obj.sayHello(); return 0; }
この例では、MyClass
というクラスを定義し、その中にsayHello
というメンバ関数を持たせています。main
関数では、MyClass
のインスタンスobj
を作成し、sayHello
を呼び出しています。
メモリ管理とスマートポインタ
編集C言語では、malloc
やfree
を使って手動でメモリ管理を行いますが、C++ではnew
とdelete
を使って動的メモリを管理します。さらに、C++11以降ではスマートポインタが導入され、メモリ管理が簡単かつ安全になりました。
#include <memory> void useSmartPointer() { std::unique_ptr<int> p1(new int(5)); std::shared_ptr<int> p2 = std::make_shared<int>(10); // メモリは自動的に解放される }
std::unique_ptr
は単一の所有権を持つポインタで、std::shared_ptr
は複数の所有権を共有するポインタです。これにより、メモリリークやダングリングポインタのリスクが減少します。
標準ライブラリの利用
編集C++の標準ライブラリ(STL: Standard Template Library)は、データ構造やアルゴリズムを提供します。これにより、効率的で再利用可能なコードを簡単に書くことができます。
#include <vector> #include <algorithm> #include <iostream> auto main() -> int { std::vector<int> vec = {1, 5, 6, 4, 3}; std::sort(vec.begin(), vec.end()); for (int n : vec) { std::cout << n << " "; } return 0; }
この例では、std::vector
を使って整数のリストを作成し、std::sort
でソートしています。
関数の強化
編集C++では、関数のオーバーロードやデフォルト引数がサポートされており、同じ名前の関数を異なる引数リストで定義できます。また、C++11以降ではラムダ式が導入され、簡潔に関数を定義できます。
#include <iostream> #include <functional> void print(int x) { std::cout << "int: " << x << std::endl; } void print(double x) { std::cout << "double: " << x << std::endl; } auto main() -> int { print(10); // int: 10 print(10.5); // double: 10.5 auto lambda = [](int x) { return x * 2; }; std::cout << lambda(5) << std::endl; // 10 return 0; }
型安全と型推論
編集C++では型安全性が重要視されており、auto
キーワードを使ってコンパイラに型を推論させることができます。また、decltype
を使って式の型を取得できます。
#include <iostream> auto main() -> int { auto x = 5; // int auto y = 5.5; // double decltype(x) z = 10; // int std::cout << x << ", " << y << ", " << z << std::endl; return 0; }
モダンC++の機能
編集モダンC++の特徴的な機能として、ムーブセマンティクスと右辺値参照があります。これにより、リソースの効率的な管理が可能となります。
#include <iostream> #include <vector> void processVector(std::vector<int>&& vec) { std::cout << "Processing vector of size " << vec.size() << std::endl; } auto main() -> int { std::vector<int> myVec = {1, 2, 3, 4, 5}; processVector(std::move(myVec)); // ムーブセマンティクスを利用 return 0; }
この例では、std::move
を使ってmyVec
を右辺値参照として渡し、リソースを効率的に移動しています。
例外処理
編集C++では例外処理を利用して、エラーが発生した際にプログラムの安全な終了を図ることができます。
#include <iostream> #include <stdexcept> void mayThrow(bool shouldThrow) { if (shouldThrow) { throw std::runtime_error("An error occurred!"); } } auto main() -> int { try { mayThrow(true); } catch (const std::runtime_error& e) { std::cerr << "Caught an exception: " << e.what() << std::endl; } return 0; }
この例では、mayThrow
関数がstd::runtime_error
を投げ、それをtry-catch
ブロックで捕捉しています。
コンパイル時のプログラム
編集テンプレートプログラミングにより、型に依存しない汎用的な関数やクラスを定義できます。また、constexpr
を使ってコンパイル時に評価される定数式を定義できます。
#include <iostream> template <typename T> T add(T a, T b) { return a + b; } constexpr int factorial(int n) { return (n <= 1) ? 1 : (n * factorial(n - 1)); } auto main() -> int { std::cout << "Sum: " << add(5, 3) << std::endl; // Sum: 8 std::cout << "Factorial of 5: " << factorial(5) << std::endl; // Factorial of 5: 120 return 0; }
C++11以降の新機能
編集C++11以降の標準では、多くの新機能が追加されました。例えば、範囲ベースのforループ、構造化束縛、コンセプトなどがあります。
#include <iostream> #include <vector> auto main() -> int { std::vector<int> vec = {1, 2, 3, 4, 5}; for (int n : vec) { // 範囲ベースのforループ std::cout << n << " "; } std::cout << std::endl; auto [a, b] = std::make_pair(1, 2); // 構造化束縛 std::cout << "a: " << a << ", b: " << b << std::endl; return 0; }
移行の実例
編集CのコードをC++に変換する具体例を示します。以下のCコードをC++に変換します。
- Cコード
#include <stdio.h> #include <stdlib.h> typedef struct { int x; int y; } Point; void printPoint(Point* p) { printf("Point(%d, %d)\n", p->x, p->y); } int main() { Point* p = (Point*)malloc(sizeof(Point)); p->x = 10; p->y = 20; printPoint(p); free(p); return 0; }
- C++コード
#include <iostream> #include <memory> class Point { public: int x, y; Point(int x, int y) : x{x}, y{y} {} void printPoint() const { std::cout << "Point(" << x << ", " << y << ")" << std::endl; } }; auto main() -> int { auto p = std::make_unique<Point>(10, 20); p->printPoint(); return 0; }
総まとめと次のステップ
編集この章では、CからC++への移行に必要な基本的な概念とモダンC++の主要な機能を紹介しました。これらの知識を基に、さらに高度なC++の技術やデザインパターンを学び、より効率的で保守性の高いプログラムを作成することを目指しましょう。