C++ 学習教材
筑波⼤学 システム情報系 三⾕純
最終更新⽇ 2025/8/29
(C) 2025 Jun Mitani 図表出典:三⾕純著『C ++ ゼロからはじめるプログラミング』(翔泳社 刊)
本資料の位置づけ
出版社 : 翔泳社
発売⽇ : 2025/9/8
ISBN : 9784798191218
2
本資料は専⾨学校・⼤学・企業などで
『 C++ ゼロからはじめるプログラミング』
を教科書として採⽤された教員・指導員を対象に、教科書
の内容を解説するための副教材として作られています。
上記に該当する場合は、⾃由にご使⽤ください。授業の進
め⽅などに応じて、改変していただいて結構です。
※ このページを削除して構いません
ただし、⺠間企業が商⽤、ビジネス⽬的で利⽤する際には
別途許諾が必要ですので、著者までご連絡ください。
(個⼈で使⽤される分には許諾を得る必要はありません)
はじめに
プログラミングを学ぶ意義(1/2)
• ソフトウェアを使う⽴場から、作る⽴場へ
– パソコン、スマートフォンなどで動作するアプリ
– TV、エアコン、洗濯機などの電⼦機器の制御
– 電⼦決済、電⼦申請、各種のシステム
• 個⼈での簡単な開発
– 電卓・Excel関数の⼀歩先
– データ処理・データ解析
– 個⼈⽤途のアプリ開発
• スキルアップ
– 情報処理関係の資格取得
– プログラミングコンテスト
プログラミングを学ぶ意義(2/2)
• 実際に開発する⽴場になる予定が無くても
– アルゴリズム的思考(ものごとを処理する⼿順に関する合理的な考え⽅)
が⾝につく
– ソフトウェアの開発の様⼦、動作原理がわかることによる広い視野を獲得
できる
– 専⾨⽤語の理解、ITエンジニアとのコミュニケーション
– 将来にプログラミングを独習したくなったときに役⽴つ(異なるプログラ
ミング⾔語でも考え⽅の基本は同じ)
この講義で学ぶこと
• プログラミング全般の基礎知識
• プログラミングに関する基本的な⽤語と考え⽅
• C++⾔語というプログラミング⾔語活⽤の基礎
よりよく学ぶために
• 実際に⼿を動かしてプログラムコードを⼊⼒する、⼀部を変更し
て実験する
• Webで公開されているプログラムコードを動かしてみる、⼀部を
変更して実験する
• プログラミングコンテストに参加してみる
(モチベーションアップ、実⼒向上、他者のコードからの学び)
学習 実践 学習 実践 学習 実践
実際に試してみよう
全体の流れ
1. C++⾔語に触れる
2. 条件分岐と繰り返し
3. 関数
4. クラスの基本
5. クラスの⼀歩進んだ使い⽅
6. 標準ライブラリ
7. アドレスとポインタ
8. ⼀歩進んだC++プログラミング
第1章 C++⾔語に触れる
プログラムとは
• コンピュータに命令を与えるものがプログラム
• プログラムを作成するための専⽤⾔語がプログラミング⾔語
• その中の1つに「C++⾔語」がある
さまざまなプログラミング⾔語
• C 歴史のある⾔語、OS開発、組み込みプログラム
• C++ C⾔語の後継、オブジェクト指向
• C# C++⾔語の後継、⽶マイクソロソフト
• Perl スクリプト⾔語、⼿軽な開発
• PHP サーバサイド、Webページ⽣成
• Java オブジェクト指向、⼤規模システム
• JavaScript ブラウザで動作、動的なWebページ
• Python 修得が容易、機械学習分野で普及
※ C++⾔語の特徴
最も歴史のあるC⾔語の後継として、現在も幅広い分野で使⽤されている。
効率的で⾼速に動作するプログラムを作成できる。
オブジェクト指向の仕組みに基づいた、規模の⼤きなシステム開発にも適している。
プログラムが作成されるまでの流れ
C++⾔語のプログラムコード
• 半⾓英数と記号で記述する
• 命令⽂の末尾にはセミコロン(;)をつける
• 空⽩や改⾏は好きな場所に⼊れてかまわない
• ⼤⽂字と⼩⽂字は区別される
「こんにちは」という⽂字列を出⼒する、最も基本的なプログラムコードの例
ブロックとインデント
ブロック: { と } で囲まれた範囲
ブロックの中にブロックが含まれることもある(ブロックのネスト)
インデント: プログラムコードを⾒やすくするために⼊れる⾏頭の空⽩
ブロックの階層の深さにあわせてインデントの数を変える
(最近のエディタは⾃動で調整してくれる)
※ インデントは無くてもプログラムに影響しない
コメント⽂
コメント⽂
・プログラムコードの中に記したメモ書き
・1 ⾏のコメント⽂には // を使⽤
・複数⾏のコメント⽂は /* と */ で囲む
・コンパイラに無視される(プログラムの動作には影響しない)
プログラムの作成と実⾏
Visual Studio とは
Visual Studio は以下のものを含む統合開発環境の1つ
エディタ:プログラムコードを記述する
コンパイラ:コンパイルを⾏う(オブジェクトファイルを⽣成する)
リンカ:リンクを⾏う(実⾏ファイルを⽣成する)
Visual Studio のインストール(Windows)
Visual Studio (Community) の⼊⼿
https://visualstudio.microsoft.com/ja/downloads/
※ MacOSでの開発環境の構築は付録を参照
Visual Studio のインストール(Windows)
Visual Studioの画⾯構成
コードエディター
出⼒・エラー⼀覧
ソリューション
エクスプローラー
プロパティ
プログラムを作成して実⾏する
実⾏までの3つのステップ
1.プロジェクトの作成
2.プログラムコードの作成
3.プログラムの実⾏
1. プロジェクトの作成
2. プログラムコードの作成
1. [プロジェクト]メニューの[新しい項⽬の追加]を選択
2. ファイル名を⼊⼒(拡張⼦は .cpp)
3. コードエディターにプログラムコードを⼊⼒
4.[ファイル]メニューの[すべて保存]を選択してプログラムコードを保存
3. プログラムの実⾏
[デバッグ]メニュー→[デバッグなしで開始]を選択
※ 練習⽤であれば、毎回新しいプロジェクトファイルを作る必要は無い。
エディターの中でプログラムコードを更新して、その都度、実⾏結果を確認する
プログラムコードの間違い
Error(エラー)の種類
• コンパイルエラー(Compile Error)
– キーワードのつづりミス
– ⽂法上の間違い
• ランタイムエラー または 実⾏時エラー (Runtime Error)
– コンパイル時には発⾒されず、プログラムを実⾏している最中に⾒つかる問題
Visual Studioで
最初のプログラムを作ってみよう
出⼒と変数
画⾯へ⽂字列を出⼒する
・画⾯へ⽂字列を出⼒する例
std::cout << "こんにちは。";
・⽂字列をダブルクォーテーション( " )で囲む
・<< を続けることで、複数の⽂字列を連続して出⼒できる。
std::cout << "こんにちは。" << "よい天気ですね。";
・⽂字列の代わりに std::endl と書くことで改⾏を出⼒できる
std::cout << "こんにちは。" << std::endl;
画⾯へ⽂字列を出⼒するプログラムコード
いろいろな⽂字列を出⼒してみよう
名前空間stdを使⽤する
using namespace std;
プログラムコードの中に
と書くと、それ以降では std:: の表記を省略できる
変数
変数とは値を⼊れておく⼊れ物のこと
変数の宣⾔:変数を作成すること
値の代⼊:変数に値を⼊れること
#include <iostream>
using namespace std;
int main()
{
int i;
i = 5;
cout << i;
}
変数の宣言
値の代入
値の出力
変数の宣⾔
型名 変数名;
int i;
整数を表す型名 変数名
• 英字、数字、アンダースコア( _ )が使える
• 先頭の⽂字が数字であってはいけない
• ⼤⽂字と⼩⽂字が区別される
• C++⾔語で⽤途が決まっている単語を変数名にはできない
値の代⼊
変数名 = 値;
i = 5;
整数名 値 左辺の変数に右辺の値を⼊れる操作
i = 5;
i = 10;
cout << i;
複数回実⾏した場合は、後から代⼊した値に上書きされる
10
実行結果
変数の初期化
初期化:変数に最初の値を⼊れること
int i;
i = 5;
int i = 5;
1⾏にまとめられる
変数の型
よく使⽤する型
・整数 :int型
・⼩数点を含む数:double型
・⽂字 :char型
・論理値 :bool型
※ char型は a〜z,A〜Z,0〜9, #!?>
といった半⾓英数字記号1⽂字
※ bool型は true または false
さまざまな型の変数
#include <iostream>
using namespace std;
int main()
{
int i = 1;
double d = 0.2;
char c = 'A';
bool b = true;
cout << "I の値は" << i << endl;
cout << "d の値は" << d << endl;
cout << "c の値は" << c << endl;
cout << "b の値は" << b;
}
iの値は1
dの値は0.2
cの値はA
bの値は1
実行結果
※ char型の値は、⽂字をシン
グルクォーテーションで囲む
実際に試してみよう
※ bool型のtrueは整数の1として出⼒される
算術演算と型
計算を⾏う
用語
実行結果
5
算術演算⼦
算術演算子
変数を含む算術演算
jの値は 20
実行結果
いろいろな計算をしてみよう
変数の値を変更する
例:変数iの値を 3 増やす
i = i + 3;
※ 「i に3を加えた値」を、変数iに代⼊する
i ← i + 3 のイメージ
短縮表現
i += 3;
さまざまな短縮表現
使⽤例
演算の内容
演算⼦
a += 2; (a = a + 2; と同じ)
加算代⼊
+=
a -= 2; (a = a - 2; と同じ)
減算代⼊
-=
a *= 2; (a = a * 2; と同じ)
乗算代⼊
*=
a /= 2; (a = a / 2; と同じ)
除算代⼊
/=
a %= 2; (a = a % 2; と同じ)
剰余代⼊
%=
a++; (a = a + 1; と同じ)
インクリメント
++
a--; (a = a - 1; と同じ)
デクリメント
--
いろいろな計算をしてみよう
異なる型の値の代⼊
int i = 1.99;
cout << i;
1
実行結果
int型の変数には整数しか代⼊できない。
⼩数点を含む数を代⼊すると、⼩数点以下が無視される
異なる型を含む演算
型によって変数(⼊れ物)の⼤きさが異なる
※ double 型の⽅が⼤きい
型の異なる変数が含まれる演算では、⼤きい型に統⼀されて演算が⾏われる
5.5
実行結果
※ double 型の変数とint型の変数が含まれる
演算では、double型に統⼀される
整数どうしの割り算
int 型どうしの割り算では、結果もint型になるので注意が必要
cの値は 0
実行結果
double 型に型変換(キャスト)して計算する
cの値は 0.5
実行結果
実際に試してみよう
string型による⽂字列の扱い
⽂字列はstring型の変数に代⼊できる
+演算⼦を使って⽂字列を連結できる
こんにちは。今日はよい天気ですね。
実行結果
キーボードからの⼊⼒を受け取る
実行結果
キーボードからの⼊⼒を受け取ることで、
⼊⼒に応じた処理を⾏うプログラムを作成できるようになる
実際に試してみよう
※ ⼩数を含む値はdouble型、
⽂字列はstring型の変数で受け取れる
第2章 条件分岐と繰り返し
条件分岐
条件分岐
条件による処理の分岐
「もしも○○ならば××を実⾏する」
if (○○) {
××;
}
if (条件式) {
命令文; //条件式が「真」の場合に実行される
}
条件分岐の例
if (age < 18) {
cout << "まだ選挙権はありません";
}
関係演算⼦
• 関係演算⼦を使って、2つの値を⽐較できる
• ⽐較した結果は 「真」 または 「偽」になる
if 〜 else ⽂
「もしも○○ならば××を実⾏し、そうでなければ△△を実⾏する」
if (○○) {
××;
} else {
△△;
}
if (条件式) {
//条件式が「真」の場合
命令文1;
} else {
//条件式が「偽」の場合
命令文2;
}
if (age < 18) {
cout << "まだ選挙権はありません";
} else {
cout << "投票に行きましょう";
}
例
複数の if 〜 else ⽂
if〜else⽂を連結して、条件に応じた複数の分岐を⾏える
if (age < 4) {
cout << 入場料は無料です";
} else if (age < 13) {
cout << "子供料金で入場できます";
} else {
cout << "大人料金が必要です";
}
実際に試してみよう
ワン・モア・ステップ:条件式に変数を使⽤する
• if ⽂の条件式に変数を使うことができる
bool b = ture;
if (b) {
命令文
}
変数 bの値が true のときに命令⽂が実⾏される
bの値を false にすると実⾏されない
int i = 1;
if (i) {
命令文
}
変数iの値が0でない場合に命令⽂が実⾏される
iの値を0にすると実⾏されない
実際に試してみよう
• 変数の型が整数型の場合、値が0でないときに命令⽂が実⾏される
switch⽂
式の値によって処理を切り替える。break;でブロックを抜ける。
switch⽂の例(1)
switch (score) {
case 1:
cout << "もっと頑張りましょう" << endl;
break;
case 2:
cout << "もう少し頑張りましょう" << endl;
break;
case 3:
cout << "普通です" << endl;
break;
case 4:
cout << "よくできました" << endl;
break;
case 5:
cout << "大変よくできました" << endl;
break;
default:
cout << "想定されていない点数です" << endl;
}
cout << "switchブロックを抜けました";
実際に試してみよう
switch⽂の例(2)
switch (score) {
case 1:
case 2:
cout << "もっと頑張りましょう";
break;
case 3:
case 4:
case 5:
cout << "合格です";
break;
default:
cout << "想定されていない点数です";
}
実際に試してみよう
ワン・モア・ステップ : 3項演算⼦
(構⽂) 条件式 ? 値1 : 値2
条件式が「真」の場合に、式の値が「値1」になる。
「偽」の場合には「値2」になる
int c;
if (a > b) {
c = a;
} else {
c = b;
}
int c = (a > b) ? a : b;
論理演算⼦
論理演算⼦を使って複数の条件式を組み合わせられる
論理演算⼦の例
ageが13以上 かつ ageが65未満
age >= 13 && age < 65
ageが13以上 かつ age が65未満 かつ age が20でない
age >= 13 && age < 65 && age !=20
ageが13未満 または age が65以上
age < 13 || age >= 65
演算⼦の優先度
算術演算⼦が関係演算⼦より優先される
a + 10 > b * 5 (a + 10) > (b * 5)
関係演算⼦が論理演算⼦より優先される
a > 10 && b < 3 (a > 10) && (b < 3)
カッコの付け⽅で論理演算の結果が異なる
x && ( y || z ) (x && y ) || z
実際に試してみよう
処理の繰り返し
繰り返し処理
• ある処理を繰り返し実⾏したいことがよくある
• ループ構⽂を使⽤すると、繰り返し処理を簡単に記述で
きる
• C++⾔語には3つのループ構⽂がある
for⽂
while⽂
do 〜 while⽂
for⽂
for⽂の構⽂
for (最初の処理; 条件式; 命令文の後に行う処理) {
命令文
}
1. 「最初の処理」を⾏う
2. 「条件式」が 真なら「命令⽂」を⾏う
偽 ならfor⽂を終了する
3. 「命令⽂の後に⾏う処理」を⾏う
4. 2.に戻る
for⽂の例
for (int i = 0; i < 5; i++) {
cout "こんにちは" << endl;
}
forループ内で変数を使う
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
cout << i << "を加えました" << endl;
}
cout << "合計は" << sum;
for ループ内で変数を使⽤することで、例えば1から100までを順番
に⾜し合わせる計算ができる
1を加えました
2を加えました
…(中略)…
99を加えました
100を加えました
合計は5050です
実行結果
実際に試してみよう
変数のスコープ
• 変数には扱える範囲が決まっている。これを「変数のスコープ」と
呼ぶ
• スコープは変数の宣⾔が⾏われた場所から、そのブロック{ } の終
わりまで
int main()
{
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
cout << i << "を加えました" << endl;
}
cout << "合計は" << sum;
}
while⽂
while⽂の構⽂
while (条件式) {
命令文
}
1. 「条件式」が 真なら「命令⽂」を⾏う
偽 ならwhileループを終了する
2. 1.に戻る
※ for⽂と同じ繰り返し命令を書ける
while⽂の例
int i = 0;
while (i < 5) {
cout << "こんにちは" << endl;
i++; // この命令文が無いと「無限ループ」
}
int i = 5;
while (i > 0) {
cout << "こんにちは" << endl;
i--; // この命令文が無いと「無限ループ」
}
実際に試してみよう
※ 無限ループにならないように注意が必要
( [Ctrl]+c キーで強制終了できる)
do 〜 while⽂
do 〜 while⽂の構⽂
do {
命令文
} while (条件式);
1. 「命令⽂」を実⾏する
2. 「条件式」が 真なら1.に戻る。
偽ならdo〜whileループを終了する
※ for⽂、while⽂と同じ繰り返し命令を書ける
必ず1回は実⾏される
do 〜 while⽂の例
int i = 0;
do {
cout << "こんにちは" << endl;
i++; // この命令文が無いと「無限ループ」
} while (i < 5);
int i = 5;
do {
cout << i << endl;
i--; // この命令文が無いと「無限ループ」
} while (i > 0);
実際に試してみよう
※ 無限ループにならないように注意が必要
ループの処理を中断する break
break; でループ処理を中断できる
int sum = 0;
for (int i = 1; i <= 10; i++) {
sum += i;
cout << "変数sumに" << i << "を加えました。";
cout "sumは" << sum << endl;
if (sum > 20) {
cout << "合計が20を超えました。";
break;
}
}
ループ内の処理をスキップする continue
continue; でブロック内の残りの命令⽂をスキップできる
int sum = 0;
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue;
}
sum += i;
cout << "変数sumに" << i << "を加えました。";
cout << "sumは" << sum << endl;
}
実際に試してみよう
for (int a = 1; a <= 3; a++) {
cout << "a = " << a << endl;//★
for (int b = 1; b <= 3; b++) {
cout << " b = " << b << endl;//☆
}
}
ループ処理のネスト
ループ処理の中にループ処理を⼊れられる
★の命令⽂は3回実⾏される
☆の命令⽂は9回実⾏される
実際に試してみよう
配列
1次元配列
• 複数の値の⼊れ物が並んだもの
(1次元配列とも呼ぶ)
• 複数の値をまとめて扱うときに便利
配列の使い⽅
1. 配列を表す変数を宣⾔する
int scores[5];
2. 配列に値を⼊れる
scores[0] = 50;
scores[4] = 80;
3. インデックスを指定して要素の値にアクセスする
例:cout << scores[i];
…
[]の中の数字はインデックス
0〜(要素の数-1)を指定する
要素の数を指定する
配列の使⽤
配列の使⽤
配列は次のようにしても初期化できる
int scores[5] = {50, 55, 70, 65, 80};
要素の数の記述を省略できる
int scores[] = {50, 55, 70, 65, 80};
実際に試してみよう
多次元配列(配列の配列)
int scores[3][5];
scores[0][0] = 50;
scores[2][3] = 65;
※ 横に並んだ⼊れ物の列が、さらに縦にも並んでいるイメージ
2次元配列の宣⾔と初期化
2次元配列は次のようにしても初期化できる
最初の配列の要素数の記述は省略できる
第3章 関数
関数とは
関数とは
• ⻑いプログラムが必要になるときは、命令⽂を分けて管理した⽅
が⾒通しがよくなる
• 関数は複数の命令⽂をまとめたもの
関数の定義
void 関数名()
{
命令文
}
※ 関数をプログラムコードで記述することを「関数の定義」と呼ぶ
関数の定義の例
関数の呼び出し
実際に試してみよう
main関数
int main()
• C++⾔語では、プログラムが実⾏されるときに、この
main関数が呼び出される
• main関数は、プログラムの開始位置となる特別な関数
関数を呼び出すときの処理の流れ
関数の呼び出しの階層
#include <iostream>
using namespace std;
void func_a()
{
cout << "func_a" << endl;
}
void func_b()
{
cout << "func_b開始" << endl;
func_a();
cout << "func_b終了" << endl;
}
int main()
{
cout << "main開始" << endl;
func_b();
cout << "main終了" << endl;
}
実際に試してみよう
関数の引数
引数とは
引数(ひきすう)
関数には、呼び出すときに値を渡すことができる。
この値を「引数」と呼ぶ。
void 関数名(型 変数名)
{
命令文
}
引数のある関数の定義
引数の受け渡しには、関数名の後ろのカッコ()を使⽤する。
引数のある関数の例
#include <iostream>
using namespace std;
void countdown(int start)
{
cout << "関数が受け取った値:" << start << endl;
cout << "カウントダウンをします" << endl;
for (int i = start; i >= 0; i--) {
cout << i << " ";
}
cout << endl;
}
int main()
{
countdown(3);
countdown(10);
}
実際に試してみよう
startという名前のint型の変数で値を受け取る
異なる値を引数として
countdown関数を呼び出す
引数が複数ある関数の例
カンマで区切って複数の引数を指定できる
#include <iostream>
using namespace std;
void countdown(int start, int end)
{
cout << "カウントダウンをします" << endl;
for (int i = start; i >= end; i--) {
cout << i << " ";
}
}
int main()
{
countdown(7, 3);
} 実際に試してみよう
2つの値をcountdown関数に渡す
実引数と仮引数
実引数:関数を呼び出すときに、関数に渡される値
仮引数:関数側で値を受け取るために準備される変数
countdown(7, 3);
実引数
void countdown(int start, int end)
仮引数
※ 実引数の値がコピーされて、それ
が仮引数に代⼊される
実引数と仮引数
#include <iostream>
using namespace std;
void func(int i) {
i++;
}
int main()
{
int i = 10;
cout << "(1) iの値は" << i << endl;
func(i);
cout << "(2) iの値は" << i;
}
(1) iの値は10
(2) iの値は10
実行結果
iの値はfunc関数呼び出し前後で変化しない
func関数には、値の複製(コピー)が渡される
実際に試してみよう
関数の戻り値
戻り値とは
戻り値
関数から返される値
戻り値の型 関数名(引数リスト) {
命令文
return 戻り値;
}
戻り値のある関数の定義
戻り値のある関数
• return を使って値を戻すようにする
• 戻り値は1つだけ
• 戻り値の型を関数名の前に記す
#include <iostream>
using namespace std;
double circle_area(double r)
{
return r * r * 3.14159;
}
int main()
{
double d = circle_area(2.5);
cout << "半径2.5の円の面積は " << d;
} 実際に試してみよう
真偽値を戻り値とする関数
• 戻り値の型がbool型の関数は、
true または false の値を戻
す
• if⽂の条件式の代わりに関数の
呼び出しを書くことができる
[ワン・モア・ステップ]
is_positive_number 関数の中
⾝を、次のように1⾏で書くこと
もできる
return (d > 0);
関数のまとめ
引数なし、戻り値なし
void 関数名() {
命令文
}
引数あり、戻り値なし
void 関数名(型 変数名) {
命令文
}
引数あり、戻り値あり
戻り値の型 関数名(型 変数名) {
命令文
return 戻り値;
}
関数のプロトタイプ宣⾔
main関数から、他の関数を呼び出すときには、その関数がどのよう
なものであるか(引数と戻り値)をコンパイラが知っている必要が
ある
1. main関数よりも前に関数の定義を書く
2. プロトタイプ宣⾔(どのような関数であるかを記したもの)を、
main関数の前に書いて、関数の定義はmain関数の後ろに書く
戻り値の型 関数名(引数リスト);
関数のプロトタイプ宣⾔
関数のプロトタイプ宣⾔の例
#include <iostream>
using namespace std;
void func1(int a);
void func2();
int main()
{
func1(10);
func2();
}
void func1(int a)
{
cout << "func1が呼び出されました" << endl;
}
void func2()
{
cout << "func2が呼び出されました" << endl;
}
関数のプロトタイプ宣⾔
関数のオーバーロード
同じ名前を持つ関数
• 名前が同じで、引数が異なる関数
を複数定義できる
• 同じ名前の関数を定義することを
「関数のオーバーロード」とよぶ
• 右のプログラムコードでは、func
という名前の関数が4つ定義されて
いる
※ 関数名と引数列の組み合わせをシ
グネチャと呼ぶ。シグネチャが同じ
関数を複数定義することはできない
第4章 クラスの基本
クラスとオブジェクト
クラスとオブジェクト
クラス
オブジェクトがどのような情報と機能を持つかを定義したもの
オブジェクト
クラスによって定義された情報と機能を持つ1つ1つの実体
オブジェクト
クラス
ソフトウェアで
管理するもの
学⽣Aの情報、学⽣Bの情報、
学⽣Cの情報、・・・
学籍番号、⽒名など、どのよ
うな項⽬を管理するか定めた
もの
学⽣情報
選⼿A、選⼿B、
選⼿C、・・・
体⼒、⾛⼒、ポジションと
いった、どのようなステータ
スを管理するか定めたもの
サッカーゲームの
サッカー選⼿情報
例
こういった、クラスとオブジェクトという概念に基づいてプログラムを作ることを
「オブジェクト指向」とよぶ
クラスの定義
class クラス名 {
アクセス指定子:
メンバ変数の定義
メンバ関数の定義
};
• 末尾にセミコロン(;)をつける
• メンバ変数とメンバ関数をあわせて「メンバ」と呼ぶ
• アクセス指定⼦はメンバへのアクセスを制御するもの(詳しくは後で学ぶ。
ここでは、 public と書くものとする)。
オブジェクトが持つ情報
(値を格納するための変数を書く)
オブジェクトが持つ機能
(処理を実⾏するための関数を書く)
メンバ変数を持つクラスの定義
学籍番号(id)と⽒名(name)を持つ学⽣証を扱うための
StudentCardクラスの定義
class StudentCard {
public:
int id = 0;
string name = "未定";
};
• idとnameという2つの値をセットにして扱える
メンバ変数
オブジェクトの⽣成とメンバ変数の変更
オブジェクトの⽣成
StudentCard a;
オブジェクトaのメンバ変数の変更
a.id = 1234;
a.name = "鈴木太郎";
※(オブジェクトを代⼊した変数の名前).(メンバ変数名)
でオブジェクトのメンバ変数にアクセスできる
複数のオブジェクトを⽣成する例
class StudentCard {
public:
int id; // 学籍番号
string name; // 氏名
}
int main()
{
StudentCard a;
a.id = 1234;
a.name = "鈴木太郎";
StudentCard b;
b.id = 1235;
b.name = "佐藤花子";
cout << "aのidは" << a.id << endl;
cout << "aのnameは" << a.name << endl;
cout << "bのidは" << b.id << endl;
cout << "bのnameは" << a.name;
}
実際に試してみよう
参照
オブジェクトの複製
StudentCard a;
a.id = 1234;
a.name = "鈴木太郎";
StudentCard b = a;
オブジェクトが⽣成される
オブジェクトの複製が⽣成される
※ 全部で2つのオブジェクトが⽣成される
参照型
StudentCard a;
a.id = 1234;
a.name = "鈴木太郎";
StudentCard& c = a;
• オブジェクトに別名cを与えている
• a.id = 1001; と書くことと c.id = 1001; と
書くことは同じ意味を持つ
• 「cはaを参照する」「cはaの参照である」という
• cの型を参照型という
• 全体でオブジェクトは1つしか存在しない
関数への参照渡し
StudentCard a;
a.id = 1234;
a.name = "鈴木太郎";
print_info(a);
オブジェクトが⽣成される
関数の呼び出し
Void print_info(StudentCard& card)
{
cout << "学籍番号:" << card.id << endl;
cout << "氏名:" << card.name << endl;
}
参照を引数とする関数
関数にStudentCard
オブジェクトを渡す
仮引数cardは参照型
※ 関数の中では、card
という別名を使⽤する
実際に試してみよう
メンバ関数
メンバ関数とは
• オブジェクトに機能を持たせることができる
• これを、クラスに関数(メンバ関数)を持たせることで実現する
メンバ関数の具体例
117
StudentCard a;
a.id = 1234;
a.name = "鈴木太郎";
a.printInfo();
※ メンバ関数の中でメンバ変数に
アクセスするには、this->の後
に変数名を続ける
※ (オブジェクトの変数名).(メンバ関数名)
で、メンバ関数を呼び出す
実際に試してみよう
メンバ関数の宣⾔と定義を分けて書く
118
メンバ関数の宣⾔だけをクラスの定義の中に書いて、メンバ関数の定義をク
ラスの外に書くことができる
※ クラスの定義をシンプルにして、全体の⾒通しを良くできる
thisキーワードの省略
119
「this->変数名」の表記で、キーワードがなくてもメンバ変数で
あることが明らかな場合は、this->の部分を省略できる
実際に試してみよう
コンストラクタとデストラクタ
コンストラクタとは
コンストラクタ:オブジェクトが⽣成される
ときに⾃動的に実⾏される特別なメンバ関数
121
コンストラクタの定義
クラス名(引数リスト) {
命令文
}
コンストラクタの定義(メンバ初期化リストがある場合)
クラス名(引数リスト): メンバ変数1(初期値1), メンバ変数2(初期値2) {
命令文
}
StudentCard(int i, string s)
{
id = i;
name = s;
}
例
StudentCard(int i, string s): id(i), name(s)
{
}
例
※オブジェクトを⽣成するときに引数を渡せる
引数を使ってメンバ変
数を初期化する
メンバ初期化リストでメンバ変数を初期化する場合は、
コンストラクタの中⾝は空でよい
コンストラクタの使⽤例
122
#include <iostream>
#include <string>
using namespace std;
class StudentCard {
public:
int id; // 学籍番号
string name; // 氏名
StudentCard(int i, string s) : id(i), name(s) {
cout << "StudentCardクラスのコンストラクタでの処理" << endl;
}
void printInfo() {
cout << "学籍番号:" << id << endl;
cout << "氏名:" << name << endl;
}
};
int main()
{
StudentCard card(1234, "鈴木太郎");
card.printInfo();
}
メンバ初期化リストを持つ
コンストラクタ
オブジェクトの⽣成
※ コンストラクタが⾃動で呼び出される
実⾏結果
実際に試してみよう
コンストラクタのオーバーロード
123
• 引数が異なる複数のコンストラクタを定義できる
(これをコンストラクタのオーバーロードとよぶ)
• オブジェクトを⽣成するときに、引数に応じて対応するコンストラクタが
⾃動で呼び出される
• 引数がないコンストラクタをデフォルトコンストラクタとよぶ
StudentCard() : id(0), name("未定") {
cout << "引数のないコンストラクタ(デフォルトコンストラクタ)が実行されました" << endl;
}
StudentCard(int i) : id(i), name("未定") {
cout << "引数が1つのコンストラクタが実行されました" << endl;
}
StudentCard(int i, string s) : id(i), name(s) {
cout << "引数が2つのコンストラクタが実行されました" << endl;
}
デストラクタとは
124
• オブジェクトには「寿命」という概念がある
• オブジェクトは、スコープから外れるときに、⾃動的に
破棄される
• オブジェクトが破棄されるときに⾃動的に実⾏される特
別なメンバ関数をデストラクタと呼ぶ
デストラクタの定義
class MyClass {
public:
~MyClass() {
cout << "デストラクタが呼ばれました" << endl;
}
};
int main()
{
MyClass a;
for (int i = 2; i < 5; i++) {
MyClass b;
}
}
オブジェクトbはforループで次の処理にうつるときに破棄される
オブジェクトaはmain関数が終わるときに破棄される
実際に試してみよう
アクセス制御とconst修飾⼦
アクセス指定⼦
• オブジェクト指向の考え⽅でプログラムコードを作成するときには、外部か
らのクラス内部へのアクセスを制御することが⼤切。
• アクセス指定⼦を使って、メンバへのアクセスを制御できる。
126
説明
アクセス指定⼦
クラスの外部からもアクセスできる
public
⾃⾝のクラス内部および派⽣クラス(*)からアクセス
できる。クラスの外部からはアクセスできない
protected
⾃⾝のクラス内部からのみアクセスできる
private
*派⽣クラス:第5章で説明
アクセス指定⼦の影響が及ぶ範囲
127
アクセス指定⼦を使⽤する例
128
#include <iostream>
using namespace std;
class Car {
private:
int speed; // 車の速度 (km/h)
public:
Car() : speed(0) {}
void speedUp() {// 速度を1増やす(最大80まで)
if (speed < 80) { speed++; }
}
void speedDown() { // 速度を1減らす(0未満にはならない)
if (speed > 0) { speed--; }
}
int getSpeed() const { return speed; }
};
int main() {
Car c;
cout << c.getSpeed() << endl;
for (int i = 0; i < 100; i++) { c.speedUp(); }
cout << c.getSpeed() << endl;
for (int i = 0; i < 20; i++) { c.speedDown(); }
cout << c.getSpeed();
}
0
80
60
実行結果
• メンバ変数 speed は、外部からアクセスでき
ない(privateアクセス指定⼦の範囲)。
• main関数で c.speed = 10; のように書く
ことは許されない。
• speedの値を変更するには、 Carオブジェク
トのspeedUpまたはspeedDownメンバ関数を
呼び出すことで実現する。
実際に試してみよう
const 修飾⼦
const int x = 10;
x++;
void func(const StudentCard& card)
{
card->name = "山本俊介";
}
変数xを変更できなくなる
値が変化しない変数であることを明⽰するためにconst修飾⼦を使⽤する
コンパイルエラー
引数で受け取ったオブジェクトのメンバ変数を変更できなくなる
コンパイルエラー
※ 「メンバ変数の値が変更されない」ということが保証される
int memberFunc() const {
this->speed++;
}
⾃⾝のメンバ変数を変更できなくなる
コンパイルエラー
※ 定数を定義するために使⽤する
第5章クラスの⼀歩進んだ使い⽅
静的メンバ変数と静的メンバ関数
静的メンバ変数
• 静的メンバ変数とは、宣⾔のときにstaticキーワードをつけた
もので、オブジェクトを⽣成しなくても使⽤できる(オブジェク
ト間で共有する値を持たせる⽬的で使⽤できる)
• 静的メンバ変数の定義はクラスの定義の外に書く。
• 静的メンバ変数にアクセスするには 「クラス名::変数名」 のよ
うに書く。
静的メンバ変数の宣⾔
静的メンバ変数を使⽤する例
133
#include <iostream>
#include <string>
using namespace std;
class StudentCard {
public:
static int counter; // 学生証発行枚数
int id; // 学籍番号
string name; // 氏名
StudentCard(int i, string s) : id(i), name(s) {
cout << "コンストラクタが呼び出されました" << endl;
StudentCard::counter++;
}
};
int StudentCard::counter = 0;
int main()
{
cout << "counterの値:" << StudentCard::counter << endl;
StudentCard a(1234, "鈴木太郎");
cout << "counterの値:" << StudentCard::counter << endl;
StudentCard b(1235, "佐藤花子");
cout << "counterの値:" << StudentCard::counter;
}
counterの値:0
コンストラクタが呼び出されました
counterの値:1
コンストラクタが呼び出されました
counterの値:2
実行結果
静的メンバ変数の宣⾔
静的メンバ変数の定義と初期化
静的メンバ変数へのアクセス
静的メンバ関数
• 静的メンバ関数とは、宣⾔のときにstaticキーワードをつけたも
ので、オブジェクトを⽣成しなくても使⽤できる
• 静的メンバ関数の定義はクラスの定義の中でも外でもよい。
• 静的メンバ関数を呼び出すには 「クラス名::関数名()」 のように
書く。
静的メンバ関数の宣⾔
静的メンバ関数を使⽤する例
135
#include <iostream>
using namespace std;
class AreaCalculator {
public:
static double getTriangleArea(double base, double height) {
return base * height / 2.0;
}
static double getCircleArea(double radius);
};
double AreaCalculator::getCircleArea(double radius)
{
return radius * radius * 3.14159;
}
int main()
{
cout << "底辺が10、高さが5の三角形の面積は"
<< AreaCalculator::getTriangleArea(10, 5) << endl;
cout << "半径5の円の面積は"
<< AreaCalculator::getCircleArea(5) << endl;
}
底辺が10、高さが5の三角形の面積は25
半径5の円の面積は78.5397
実行結果
静的メンバ関数の宣⾔と定義
静的メンバ関数の呼び出し
静的メンバ関数の宣⾔
静的メンバ関数の定義
• 静的メンバ関数は、オブジェクトを⽣
成しなくても使⽤できる
• 静的メンバ関数の中からメンバ変数に
アクセスできない
• 静的メンバ関数の中からメンバ関数を
呼び出せない
実際に試してみよう
継承
継承とは
• すでにあるクラスの機能を新しいクラスが引き継ぐこと。
• 機能の拡張が容易にできる
137
・クラスAはクラスBの基底クラス(親クラス)
・クラスBはクラスAの派⽣クラス(⼦クラス)
C++⾔語での継承
138
• あるクラスから複数の派⽣クラスを作れる
(例: クラスBとクラスCはクラスAの派⽣クラス)
• 複数の基底クラスを持つクラスを作れる(多重継承)
(例: クラスDとクラスCはクラスGの基底クラス)
※ ⽮印は派⽣(⼦)クラスから基底(親)クラスに向かう
※ 本講義では多重継承を扱わない
継承を⾏う
139
説明
アクセス指定⼦
基底クラスのpublicメンバは派⽣クラスのpublicメンバになる
public
基底クラスのpublicメンバもprotectedメンバとして継承される
protected
基底クラスのpublicメンバもprivateメンバとして継承される
private
他のクラスを継承するクラスの定義
例:クラスAを継承するクラスBの定義
アクセス指定⼦の働き
※ クラスBはクラスAのメンバ変数・メンバ関数を引き継ぐ
継承の例
140
#include <iostream>
#include <string>
using namespace std;
class StudentCard {
public:
int id = 0; // 学籍番号
string name = "未定"; // 氏名
void printInfo() {
cout << "学籍番号:" << id << endl;
cout << "氏名:" << name << endl;
}
};
class IStudentCard : public StudentCard {
public:
string nationality = "未定"; // 国籍
};
int main()
{
IStudentCard a;
a.id = 2345;
a.name = "John Smith";
a.nationality = "イギリス";
a.printInfo();
}
• IStudentCardクラスは StudentCardクラスを継承する
• メンバ変数 nationality が IStudentCardクラスに追加
されている
• StudentCardオブジェクトが持つメンバを、
IStudentCardオブジェクトも持つ
オーバーライドとポリモーフィズム
141
派⽣クラスによるメンバ関数の再定義
142
• 基底クラスのメンバ関数と同じ名前のメンバ関数を、
派⽣クラスで再定義できる。
• 派⽣クラスのメンバ関数が優先され、基底クラスのメ
ンバ関数は実⾏されなくなる。これを基底クラスのメ
ンバ関数が隠蔽される、という。
class StudentCard {
public:
int id = 0;
string name = "未定";
void printInfo() {
cout << "学籍番号:" << id << endl;
cout << "氏名:" << name << endl;
}
};
class IStudentCard : public StudentCard {
public:
string nationality = "未定";
void printInfo() {
cout << "国籍:" << nationality << endl;
}
};
基底クラスが持つメンバ関数のオーバーライド
基底クラスのメンバ関数を呼び出す
143
class StudentCard {
public:
int id = 0;
string name = "未定";
void printInfo() {
cout << "学籍番号:" << id << endl;
cout << "氏名:" << name << endl;
}
};
class IStudentCard : public StudentCard {
public:
string nationality = "未定";
void printInfo() {
cout << "国籍:" << nationality << endl;
StudentCard::printInfo();
}
};
基底クラスが持つメンバ関数を呼び出す
基底クラス名の後ろにコロン(:)を2つ並べて
から関数名を書くことで派⽣クラスから基底
クラスのメンバ関数を呼び出せる
クラスの継承と参照
144
class Person { };
class Student : public Person { };
class Teacher : public Person { };
class Car { };
上図の継承関係を持つ4つのクラス
Person型オブジェクトの参照を受け取る関数
関数に渡せるオブジェクト
×
※ 派⽣クラスのオブジェクトも渡すことができる
オーバーライドとポリモーフィズム
• virtual キーワードがついたメンバ関数
を仮想関数と呼ぶ
• 仮想関数を派⽣クラスが再定義すること
をオーバーライドと呼ぶ
• 基底クラスの型の参照を通じてメンバ関
数を呼び出したとき、派⽣クラスのメン
バ関数が実⾏される。この仕組みをポリ
モーフィズムと呼ぶ
145
class Person {
public:
virtual void work() { cout << "人:仕事する" << endl; }
};
class Student : public Person {
public:
void work() override { cout << "学生:勉強する" << endl;}
};
class Teacher : public Person {
public:
void work() override { cout << "教員:授業する" << endl;}
};
void execute_work(Person& person) { person.work(); }
int main() {
Person person;
Student student;
Teacher teacher;
execute_work(person);
execute_work(student);
execute_work(teacher);
}
人:仕事する
学生:勉強する
教員:授業する
実行結果
実際に試してみよう
第6章 標準ライブラリ
テンプレートの仕組み
147
テンプレートとは
テンプレートを使うと、1つのプログラムコードで複数の型に対応
する関数やクラスを定義できる。
148
int get_max(int a, int b) {
return a > b ? a : b;
}
例:2つの引数のうち⼤きい⽅の値を返す get_max関数を作りたい
double get_max(double a, double b) {
return a > b ? a : b;
}
int型に対応した関数
double型に対応した関数
型の数だけ関数を定義する必要があるのは不便 → テンプレートを使⽤する
template <typename T>
T get_max(T a, T b) {
return a > b ? a : b;
}
※ 型名を T (プレースホルダ)で表現する
※ 関数を呼び出すときは
get_max<int>(3, 10)
のようにして型を指定する
関数テンプレートの使⽤例
• 関数テンプレートを使⽤すると、異
なる型に対応する関数を⼀度書くだ
けで済む
• 関数を呼び出すときに、型を指定す
る <int> や <double> の箇所を
省略できる(これは、コンパイラが
引数を⾒て推測できるため)
149
#include <iostream>
using namespace std;
template <typename T>
T get_max(T a, T b) {
return a > b ? a : b;
}
int main() {
int i = get_max<int>(10, 4);
double d = get_max<double>(1.2, 5.2);
cout << i << ", " << d;
}
10, 5.2
実行結果
実際に試してみよう
クラステンプレート
• 異なる型のメンバ変数に対応した汎⽤的なクラスを定義するための仕組み
• template <typename T> に続けてクラスの定義を書く
150
クラステンプレートを使って定義された
Boxクラスの使⽤例
コンテナ
151
標準ライブラリとコンテナ
• 標準ライブラリ:あらかじめ開発環境に標準で⽤意されている関数やクラス
の集まり
• コンテナ:値やオブジェクトを格納し、管理するためのクラス
• 範囲ベースのforループ: forループの新しい書き⽅
152
構⽂
例
※ インデックスを使⽤しないで各要素にアクセスできる
コンテナの基本: vector (動的配列)
• vectorは配列と同じ⽤途で使⽤できる
• 格納できる要素の数が⾃動的に調整される
• 最初にサイズを指定する必要がなく、後から要素を好きなだけ追加できる
153
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = { 1, 2, 3 };
v.push_back(4);
v.push_back(5);
cout << v.size() << endl;
cout << v.front() << endl;
cout << v.back() << endl;
v.pop_back();
v[1] = 10;
for (int x : v) {
cout << x << " ";
}
}
vectorクラスの主なメンバ関数
5
1
5
1 10 3 4
実行結果
実際に試してみよう
コンテナの基本: list (双⽅向連結リスト)
• listはvectorとほぼ同じ⽤途で使⽤できる
• インデックスで要素にアクセスできない
• 要素の追加と削除をvectorよりも⾼速に実⾏できる
154
#include <iostream>
#include <list>
using namespace std;
int main() {
list<int> l = { 10, 20, 30 };
l.push_front(5);
l.push_back(40);
l.remove(20);
for (int x : l) {
cout << x << " ";
}
}
listクラスの主なメンバ関数
5 10 30 40
実行結果
実際に試してみよう
コンテナの基本: map (連想配列)
• mapは「キー」と「値」のペアで要素を管理する
• キーを使って要素にアクセスする
• 重複するキーを持つことはできない
155
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> scores;
scores["Suzuki"] = 86;
scores["Yamada"] = 92;
cout << scores["Suzuki"] << endl;
cout << scores["Yamada"] << endl;
}
mapクラスの主なメンバ関数
86
92
実行結果
実際に試してみよう
コンテナの基本: set (集合)
• setは格納されるオブジェクトに重複がないことを保証する
• insertメンバ関数で要素を追加する
• インデックスで要素にアクセスできない
• 要素は昇順(値が⼩さい順)に格納される
156
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s = { 10, 2, 8 };
s.insert(2);
s.insert(5);
for (int x : s) {
cout << x << " ";
}
} 2 5 8 10
実行結果
実際に試してみよう
アルゴリズムとイテレータ
157
イテレータ
• イテレータは、コンテナに格納されている要素を指し⽰すことができるオブ
ジェクト
• イテレータを使うと、どのようなコンテナに対しても同じような書き⽅で、
コンテナに格納されているオブジェクト1つ1つにアクセスできる
158
イテレータのイメージ
イテレータの使⽤
159
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> data = { 10, 20, 30 };
list<int>::iterator it = data.begin();
while (it != data.end()) {
cout << *it << " ";
++it;
}
}
• int型の値を格納するlistの要素にアクセ
スするためのイテレータ it の型は
list<int>::iterator
• 先頭の要素を指すイテレータを取得するに
は、listクラスのbegin()関数を使⽤する
• end()関数の戻り値は「最後の要素の次」
を指すイテレータ
• *it で要素の値にアクセスできる
• ++it でイテレータを1つ先に進める
アルゴリズム
• 標準ライブラリには、コンテナに格納されている要素の並べ替え
(sort)、検索(find)、削除(remove)などを⾏う関数が
数多く⽤意されている
• これらをアルゴリズム(algorithm)とよぶ
• 使⽤するには、次のようにして algorithm ヘッダーをインクル
ードする
160
#include <algorithm>
アルゴリズムの活⽤(sort)
161
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
vector<int> vec = {5, 3, 8, 1, 4};
sort(vec.begin(), vec.end());
for (int x : vec) {
cout << x << " ";
}
}
1 3 4 5 8
• sort関数を⽤いて、コンテナ内の要素を値
が⼩さい順、または⼤きい順に並べ替える
ことができる
• sort関数には、2 つのイテレータを引数に
渡すことで、並べ替えを⾏う範囲の始まり
と終わりを指定する
• 第1引数のイテレータが指す要素と、第2引
数のイテレータの1つ⼿前の要素までが並
べ替えの対象となる
実行結果
実際に試してみよう
アルゴリズムの活⽤(find)
• find関数を使⽤して、コンテナ
の中に特定の要素が含まれるかど
うか知ることができる
• 検索を⾏う範囲の始まりと終わり
を指定する2つのイテレータと、
検索したい値を引数にする
• 要素が⾒つかった場合は、その要
素を指すイテレータが戻り値にな
る。要素が⾒つからなかった場合
は、末尾の要素の次を指すイテレ
ータ(コンテナのend関数の戻り
値)が戻り値になる
162
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main() {
vector<char> data = {'A', 'D', 'Z', 'P'};
vector<char>::iterator it =
find(data.begin(), data.end(), 'D');
if (it != data.end()) {
cout << "見つかりました";
}
else {
cout << "見つかりませんでした";
}
}
見つかりました
実行結果
実際に試してみよう
代表的なアルゴリズム
• std::min_element 範囲内の最⼩値を⾒つける
• std::max_element 範囲内の最⼤値を⾒つける
• std::count 指定した値が範囲内にいくつあるか数える
• std::reverse 範囲内の要素の並び順を逆にする
163
vector<int>::iterator min_it = std::min_element(v.begin(), v.end());
例
vector<int>::iterator max_it = std::max_element(v.begin(), v.end());
例
int num = std::count(v.begin(), v.end(), 5);
例
std::reverse(v.begin(), v.end());
例
第7章 アドレスとポインタ
アドレスとポインタ
コンピューターのメモリー
• コンピューターがプログラムを実⾏している途中に扱う、さまざまな情報
がメモリーに格納される
• メモリーを、1 バイト単位で区切れるように⽬盛りがついた、横に⻑い箱
のようなものだとみなす
• ⽬盛りに割り当てられた数字(番地)をアドレスという
166
アドレス
int i = 5;
• int型の箱(サイズ 4バイト)がメモリー
上に確保される
• その領域に、5という値のデータが格納さ
れる
cout << &i;
000000A7046FF6E4
実行結果
メモリー上の変数iの位置(アドレス)を知る
16進数表現(実⾏のたびに変化する。具体的な値
にあまり意味はない)
&変数名 変数のアドレスを参照するための記号「&」はアドレス演算⼦と呼ばれる。
167
ポインタ
アドレスはポインタ変数に代⼊できる
int i = 5;
int* p = &i;
※ 図では、ポインタ変数の⼊れ物のサイズを8バイトで表している
ポインタ変数(変数名の前に*記号をつける)
168
ポインタを使った値の参照
int i = 5;
int* p = &i;
cout << "iのアドレスは" &i << endl;
cout << "pの値は" p << endl;
cout << "iの値は" i << endl;
cout << "*pの値は" *p << endl;
iのアドレスは0000002376EFFD24
pの値は0000002376EFFD24
iの値は5
*pの値は5
実行結果
• ポインタ変数pに⼊っているアドレスの場所に存在する値にアクセスするには、
プログラムコードの中で「*p」と書く
• 「i」と「*p」は、メモリー上の同じ値を参照する
169
実際に試してみよう
ポインタの活⽤
ポインタを使って値を変更する
int i = 5;
int* p = &i;
• *p は変数 i の別名としてふるまう
• これ以降のプログラムコードに*pが登場したときには、これを変数iに置き換
えて読むと理解しやすくなる
• 「int j = *p;」は、「int j = i;」と同じように働き、変数jに変数iの
値が代⼊される
• 「*p = 10;」は「i = 10;」と同じように働き、変数iの値が10になる。
• つまり、ポインタを使って、変数の値を変更できる
171
ポインタを使って値を変更する
int i = 5;
int* p = &i;
int j = *p;
cout << "jの値は" << j << endl;
*p = 10;
cout << "iの値は" << i;
jの値は5
iの値は10
実行結果
• 変数iと*pは、名前が違うだけで、まったく同じようにふるまう。
• *pはiのエイリアス(別名)である
実際に試してみよう
172
ポインタが指す先を変更する
int i = 5;
int j = 8;
int* p = &i;
cout << "*pの値は" << *p << endl;
p = &j;
cout << "*pの値は" << *p;
*pの値は5
*pの値は8
実行結果
ポインタ変数pに変数jのアドレスを代⼊
173
ポインタを引数とする関数
#include <iostream>
using namespace std;
void func(int* p)
{
*p = 10;
}
int main()
{
int i = 5;
func(&i);
cout << "iの値は" << i;
}
※ 関数にアドレスを渡すと、そのアドレスに格納されている値を、関数の中で変更できる
iの値は100
実行結果
実際に試してみよう
174
値の交換をする swap 関数
#include <iostream>
using namespace std;
void swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int main() {
int a = 2;
int b = 3;
cout << "a=" << a << ", b=" << b << endl;
cout << "swap関数を呼び出します" << endl;
swap(&a, &b);
cout << "a=" << a << ", b=" << b;
}
a=2, b=3
swap関数を呼び出します
a=3, b=2
実行結果
実際に試してみよう
175
配列とポインタ
配列の要素のアドレス
int scores[3] = {10, 20, 30};
cout << "scores[0]のアドレス:" << &scores[0] << endl;
cout << "scores[1]のアドレス:" << &scores[1] << endl;
cout << "scores[2]のアドレス:" << &scores[2];
実行結果
配列の要素は、メモリ上に連続して格納される
配列とポインタ
int scores[3] = {10, 20, 30};
int* p = scores;
int* p = &scores[0]; • どちらの表記も同じ意味
• 配列名だけの表記は、先頭要素
のアドレスを表す
*p = 5;
scores[0] = 5;
どちらの表記も同じ意味
※ 配列の要素には、異なる表記
(別名)でアクセスできる
ポインタに対する加算
int scores[] = {10, 20, 30};
int* p = scores;
cout << "*pの値は << *p << endl;
cout << "*(p + 1)の値は" << *(p + 1) << endl;
cout << "*(p + 2)の値は" << *(p + 2);
実行結果
*pの値は10
*(p + 1)の値は20
*(p + 2)の値は30
※ ポインタ変数に対して1だけ加算すると、型のサ
イズ分だけ、アドレスの値が増える
ポインタのインクリメント
ポインタが配列の先頭の要素を指している
とき、ポインタ変数の値を1だけ増やすと、
配列の次の要素を指すようになる。
int scores[] = {10, 20, 30};
int *p = scores;
cout << *p << endl;
p++;
cout << *p << endl;
p++;
cout << *p ;
実行結果
10
20
30
実際に試してみよう
newを⽤いた動的なメモリー確保
#include <iostream>
using namespace std;
int main() {
int size;
cout << "配列のサイズを入力してください: ";
cin >> size;
int* a = new int[size];
for (int i = 0; i < size; i++) {
a[i] = i + 1;
}
for (int i = 0; i < size; i++) {
cout << a[i] << " ";
}
delete[] a;
}
• 配列ははじめに要素の数が決まっている必要がある
• new キーワードを使うとプログラム実⾏時に必要な
⼤きさのメモリーを確保できる(動的なメモリー確
保という)
• int* a = new int[size]; と書くとプログラム
実⾏時のsizeの値で配列を⽣成できる
• a[0] = 5; のように、通常の配列と同じように使
⽤できる
• 使⽤する必要がなくなったときには delete[] a;
で、メモリーを解放する
実行結果
配列のサイズを⼊⼒してください:
5
1 2 3 4 5
実際に試してみよう
第8章 ⼀歩進んだC++プログラミング
複数ファイルへの分割
関数の定義を別のファイルで⾏う
184
クラスの定義を別のファイルに分ける
185
#pragma once
#include <string>
using namespace std;
class StudentCard {
public:
int id = 0;
string name = "未定";
void printInfo();
};
#include <iostream>
#include "StudentCard.h"
using namespace std;
void StudentCard::printInfo() {
cout << "学籍番号:" << id << endl;
cout << "氏名:" << name << endl;
}
#include "StudentCard.h"
int main()
{
StudentCard a;
a.id = 1234;
a.name = "鈴木太郎";
a.printInfo();
}
StudentCard.h
StudentCard.cpp
main.cpp
• ファイルを分けることでプログラムコードの管理が
しやすくなる
• クラス単位での再利⽤がしやすくなる
• ヘッダーファイルの冒頭にと #pragma once 書く。
(複数回インクルードされるのを防ぐ)
ローカル変数とグローバル変数
• 変数は、宣⾔されたブロックの内部だ
けで使⽤できる(ローカル変数)
• すべてのブロックの外側で宣⾔された
変数は、どの関数でも使⽤できる(グ
ローバル変数)
• 同じ名前が使⽤された場合はローカル
変数が優先される
186
実際に試してみよう
グローバル変数と
複数ファイルへの分割
グローバル変数
• 変数が使⽤できる範囲は、宣⾔されたブロックの中に限られる(変数のスコープ)
• 関数の中で宣⾔した変数、または引数の受け取りのために使⽤する変数をローカル
変数とよぶ
• プログラム全体で使⽤できるグローバル変数というものがある
• グローバル変数は、関数の外側で宣⾔し、どの関数の中からも使⽤できる
#include <stdio.h>
int a = 10;
void func(void) { a++; }
int main(void)
{
func();
cout << "%d¥n", a);
}
グローバル変数。プログラム全体のどこからでも参照できる
実際に試してみよう
188
グローバル変数を複数のファイルで共有する
189
#include <iostream>
#include "triangle.h"
using namespace std;
int main()
{
double area = triangle_area(3.0, 5.0);
cout << "面積は" << area << endl;
cout << "g_countの値は" << g_count;
}
#include "triangle.h"
int g_count = 0;
double triangle_area(double base, double height)
{
g_count++;
return base * height / 2.0;
}
#pragma once
extern int g_count;
double triangle_area(double base, double height);
StudentCard.h
StudentCard.cpp
main.cpp
ファイル⼊出⼒と例外処理
テキストファイルの読み込み
• テキストファイル:⽂字列が保存されたファイル
• バイナリファイル:テキストファイルではないファイル(画像デ
ータ、⾳声データなどのファイル)
• テキストファイルの読み込みの⼿順
1. ファイルを開く(std::ifstreamを使⽤する)
2. ファイルから⽂字列を読み込み、読み取った内容に対して処理を⾏う
(std::getline関数や>>演算⼦を使⽤する)
3. ファイルを閉じる(std::ifstreamのclose関数を使⽤する)ファイルを開く
ファイルの読み込みとファイルの保存場所
ifstream ifs("data/sample.txt");
プロジェクトファイル(.vcxproj)があるフォルダが基準
Humpty Dumpty sat on a wall,
Humpty Dumpty had a great fall.
All the king's horses and all the
king's men
Couldn't put Humpty together again.
sample.txt の中⾝
ファイルの場所(相対パス)の指定
テキストファイル読み込みの例
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// 1. ファイルを開く
ifstream ifs("data/sample.txt");
if (!ifs) {
cerr << "ファイルを開けませんでした。";
return 1;
}
// 2. ファイルから文字列を読み込んで処理する
string line;
int line_count = 1;
while (getline(ifs, line)) {
cout << line_count << ": " << line << endl;
line_count++;
}
// 3. ファイルを閉じる
ifs.close();
}
実際に試してみよう
実行結果
テキストファイルの書き出し
テキストファイルの書き出しの⼿順
1. ファイルを開く(std::ofstreamを使⽤する)
2. ⽂字列をファイルに書き出す(<< 演算⼦を使⽤する)
3. ファイルを閉じる(std::ofstreamのclose関数を使⽤する)
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream ofs("output.txt");
if (!ofs) {
cerr << "ファイルを開けませんでした";
return 1;
}
for (int i = 0; i < 10; i++) {
ofs << "[" << i << "]" << endl;
}
ofs.close();
} 実際に試してみよう 194
例外処理
• プログラムを実⾏させたときに発⽣するエラーを「ランタイムエラー」という
• プログラムを実⾏している途中に発⽣する「通常の処理では対処できない問題」のことを例
外と呼ぶ
• こうした問題を検知して、呼び出し元に通知し、適切な処理を⾏う仕組みが「例外処理」
void divide(double a, double b)
{
double c = a / b;
cout << c;
}
↑ このようなプログラムコードでは、
引数のbに値0が渡されたときに例外が発⽣する
※ 例外処理が必要となる
例外処理の構⽂
例外処理に使⽤するキーワード
• try 例外が起きそうな処理を{ }で囲む
• throw 例外オブジェクトを投げる
• catch 投げられた例外を受け取って処理する
196
例外処理の構⽂
std::exception
すべての例外クラスの基底クラス
std::runtime_error
実⾏時の⼀般的なエラー
std::logic_error
プログラムロジック上のエラー
std::out_of_range
コンテナの範囲外アクセスなどのエラー
std::bad_alloc
new 演算⼦によるメモリ確保失敗
※ 標準ライブラリで提供される
例外オブジェクトのためのクラス
例外処理の例
197
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
int main() {
double a, b;
cout << "2つの数値を半角スペース区切りで入力してください" << endl;
cin >> a >> b;
try {
if (!cin) { throw runtime_error("数として正しく読み取れません"); }
if (b == 0) { throw runtime_error("0で除算できません"); }
double result = a / b;
cout << a << " / " << b << " = " << result << endl;
}
catch (const runtime_error& e) {
cerr << "エラー: " << e.what() << endl;
}
cout << "プログラム終了";
} 実際に試してみよう
演算⼦のオーバーロードと型推論
演算⼦のオーバーロード
例:2つのPoint オブジェクトのx,y座標値をそれぞれ⾜し合わせた新し
いPointオブジェクトを + 演算⼦で作りたい
199
class Point {
private:
int x;
int y;
public:
Point() : x(0), y(0) {}
Point(int x, int y) : x(x), y(y) {}
};
Point p1(1, 3);
Point p2(2, 5);
Point p3;
p3.x = p1.x + p2.x;
p3.y = p1.y + p2.y;
Point p3 = p1 + p2;
算術演算⼦ +、-、*、/ に新しい役割を与えることができる
これまでに学習した⽅法
+演算⼦のオーバーロードした場合
※ 通常の⾜し算のように書くことができる
演算⼦のオーバーロードの実現
200
class Point {
private:
int x;
int y;
public:
Point() : x(0), y(0) {}
Point(int x, int y) : x(x), y(y) {}
// 2項演算子+のオーバーロード
Point operator+(const Point& other) const {
return Point(x + other.x, y + other.y);
}
// 2項演算子-のオーバーロード
Point operator-(const Point& other) const {
return Point(x - other.x, y - other.y);
}
// 2項演算子==のオーバーロード
bool operator==(const Point& other) const {
return (x == other.x && y == other.y);
}
};
Point p1(1, 3);
Point p2(2, 5);
Point p3 = p1 + p2; // Pointオブジェクトどうしの加算
Point p4 = p2 - p1; // Pointオブジェクトどうしの減算
if (p3 == p4) { // Pointオブジェクトどうしの比較
cout << "同じ座標です";
}
演算⼦のオーバーロードの構⽂
左のようにして演算⼦をオーバーロードすると、
次のようなプログラムコードを書くことができる
実際に試してみよう
⾃動型推論
autoキーワードを使⽤すると、コンパイラが型を⾃動的に推論するため、プ
ログラムコードに型を書かなくても済む
201
int i = 5;
double d = 2.3;
auto i = 5;
auto d = 2.3;
vector<int> v = {1, 3, 5};
vector<int>::iterator it = v.begin();
vector<int> v = {1, 3, 5};
auto it = v.begin();
autoキーワードを使った書き⽅ autoキーワードを使った書き⽅
実際に試してみよう
終

More Related Content

PPTX
C言語 学習教材
PPTX
C++ tips4 cv修飾編
PPTX
超LINQ入門
PDF
組み込みでこそC++を使う10の理由
PDF
講座C入門
PPTX
条件分岐・繰り返し処理
PDF
Boost.Flyweight
C言語 学習教材
C++ tips4 cv修飾編
超LINQ入門
組み込みでこそC++を使う10の理由
講座C入門
条件分岐・繰り返し処理
Boost.Flyweight

Similar to 翔泳社 「C++ ゼロからはじめるプログラミング」対応 C++学習教材(三谷純) (20)

PPTX
競技プログラミングのためのC++入門
PDF
PPTX
エラーハンドリング
PDF
C++コミュニティーの中心でC++をDISる
PPTX
C++14言語編
PDF
Learning Template Library Design using Boost.Geomtry
PDF
君はまだ,本当のプリプロセスを知らない
PPTX
C++ tips 3 カンマ演算子編
PDF
C言語講習会2
ODP
Lt会01_uetch
PDF
【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】
PDF
Processing
PDF
What is template
PDF
組み込み関数(intrinsic)によるSIMD入門
PPTX
第1回Java講義資料
PDF
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第3回 ‟条件とループ„
PDF
Javaセキュアコーディングセミナー東京第2回講義
PPTX
普通のコードがCodeGolfコードになるまで in Ruby
PPTX
復習と型 Jyoken
PDF
新しくプログラミング言語・・・Rubyでやってみた
競技プログラミングのためのC++入門
エラーハンドリング
C++コミュニティーの中心でC++をDISる
C++14言語編
Learning Template Library Design using Boost.Geomtry
君はまだ,本当のプリプロセスを知らない
C++ tips 3 カンマ演算子編
C言語講習会2
Lt会01_uetch
【解説】JOI 2019/2020 一次予選 最速非公式解説【競技プログラミング】
Processing
What is template
組み込み関数(intrinsic)によるSIMD入門
第1回Java講義資料
【C++BUILDER STARTER チュートリアルシリーズ】シーズン2 C++Builderの部 第3回 ‟条件とループ„
Javaセキュアコーディングセミナー東京第2回講義
普通のコードがCodeGolfコードになるまで in Ruby
復習と型 Jyoken
新しくプログラミング言語・・・Rubyでやってみた
Ad

Recently uploaded (6)

PDF
ココロ分解帳|感情をやさしく分解し自分と他者を理解するためのモバイルノートアプリ
PDF
Working as an OSS Developer at Ruby Association Activity Report 2025
PDF
AIシステムのセキュリティ:脅威となりつつあるAIの現状と課題 [English] Security of AI Systems: The Current...
PPTX
生成AIとモデルベース開発:実はとても相性が良いことを説明します。まあそうだろうなと思われる方はご覧ください。
PDF
20250826_Devinで切り拓く沖縄ITの未来_AI駆動開発勉強会 沖縄支部 第2回
ココロ分解帳|感情をやさしく分解し自分と他者を理解するためのモバイルノートアプリ
Working as an OSS Developer at Ruby Association Activity Report 2025
AIシステムのセキュリティ:脅威となりつつあるAIの現状と課題 [English] Security of AI Systems: The Current...
生成AIとモデルベース開発:実はとても相性が良いことを説明します。まあそうだろうなと思われる方はご覧ください。
20250826_Devinで切り拓く沖縄ITの未来_AI駆動開発勉強会 沖縄支部 第2回
Ad

翔泳社 「C++ ゼロからはじめるプログラミング」対応 C++学習教材(三谷純)