アトリエ・エクレア

2DCG&3DCG, プログラミング, 日記などを掲載してます。

C++言語

C++言語

<免責事項> この記事は、管理人の個人的な覚書きのためのものです。内容に間違いがあっても責任は負いません。

  • msdn (C++言語リファレンス) → Link
  • プログラム言語C++ (JISX3014) → Link

C++言語

1983年にベル研究所のコンピュータ科学者のビャーネ・ストロヴストルップが、C言語の拡張として開発した。
拡張はクラスの追加に始まり、仮想関数、多重定義、多重継承、テンプレート、例外処理といった機能が続いていった。

プログラミング言語「C with Classes」の開発を1979年に開始。当時既に汎用的な言語だったC言語にSimulaの特徴を取り入れることを試みた。1983年に 「C with Classes」 から 「C++」 に名称を変更している。

静的な型システムを持ち、手続き型プログラミング・データ抽象・オブジェクト指向プログラミング・ジェネリックプログラミングといった複数のプログラミングパラダイムをサポートするマルチパラダイムプログラミング言語である。

ソースファイルの拡張子

sample.cpp のように、「 .cpp 」を使う。

出力

// プリプロセッサ ディレクティブ
#include <iostream>
using namespace std;   // usingディレクティブ

int main(){            // C++では、仮引数のvoid省略可
	// character output
	cout << "Hello, world!\n";

	// usingディレクティブを使用しない場合
	// std::cout << "Hello, world!\n";  ※::はスコープ解決演算子

	return 0;          // 省略可
}

入力

#include <iostream>
using namespace std;

int main(){
	int num1, num2;
	cout << "整数を2つ続けて入力しなさい。" << endl;

	// 入力
	cin >> num1 >> num2;

	cout << "num1 = " << num1 << '\n';
	cout << "num2 = " << num2 << '\n';

	return 0;
}

コメント

/* 範囲コメント */

/* 複数行の
コメント */

// 一行コメント(改行まで)

特殊文字 (エスケープシーケンスの利用)

特殊文字の例 (※他にもある。)
文字 意味
¥a ベル ( 警告 )
¥b バックスペース
¥f フォームフィード: 改ページ
¥n 改行
¥r キャリッジリターン: 行頭へ復帰
¥t 水平タブ
¥v 垂直タブ
¥¥ 円記号 ( ¥ )
¥? リテラル疑問符 ( ? )
¥' 単一引用符: シングルクォーテーション ( ' )
¥'' 二重引用符: ダブルクォーテーション ( " )
¥0 NULL(ヌル)文字 ※ ヌルポインターとは異なるので注意
¥ooo 8進表記のASCII文字 ( 円記号と、1~ 3桁の8進数 )
¥xhh 16進表記のASCII文字 ( ¥xと、16進数)
¥uxxxx Unicode (UTF-8)
¥Uxxxxxxxx Unicode (UTF-16)

※パーセント記号 ( % ) は、エスケープシーケンスではなく、
変換指定子を用いた変換仕様を用いる(→ %%)。

文字定数

文字定数: シングルクォーテーション ( ' ) で囲まれた、1文字の定数。
変換仕様では、%c を利用。

  • char型のナロー文字リテラル。  ex)  'a'
  • wchar_t型のワイド文字リテラル。  ex)  L'a'
	char narrow = 'A';    // ナロー文字リテラル
	wchar_t wide = L'A';  // ワイド文字リテラル
	char esc = '\\';      // エスケープシーケンス ※ここでは円記号

文字列定数

文字列定数: ダブルクォーテーションで囲まれた、複数の文字による列。
変換仕様では、%s を利用。

  • ナロー文字列リテラル。"xxx" と表される。
  • ワイド文字列リテラル。L"xxx" と表される。
  • 未加工の文字列リテラル。R"ddd(xxx) ddd" と表される。
    ここで、ddd は区切り文字。
    未加工の文字列リテラルは、ナロー (R と表される) またはワイド (LR と表される) 。
	// ナロー文字列リテラル  ※ nullで終わる定数 char の配列
	const char *narrow = "abcd"; // エスケープ シーケンスが含まれる場合もある

	// ワイド文字列リテラル  ※ nullで終わる定数 wchar_t の配列
	const wchar_t* wide = L"zyxw"; // エスケープ シーケンスが含まれる場合もある

	// 未加工文字列リテラル  ※ nullで終わる定数 char または定数 wchar_t の配列
	const char* raw_narrow = R"(An unescaped \ character)";   // represents the string: An unescaped \ character	
	const wchar_t* raw_wide = LR"(An unescaped " character)"; // represents the string: An unescaped " character

整数定数

整数定数: 10進数, 8進数, 16進数の数値。
基本的に、符号有りint型。

符号無しint型で扱う場合、サフィックス(接尾子)として、 U または u を使う。 (ex. 25U, 75u)
符号有りlong型で扱う場合、サフィックスとして、 L または l を使う。 (ex. 25L, 75l)
符号無しlong型で扱う場合、サフィックスとして、 UL または ul を使う。 (ex. 25UL, 75ul)

8進数: プレフィックス(接頭子)として、0をつける。 (ex. 015, 09)
16進数: プレフィックスとして、0xまたは0Xをつける。 (ex. 0x15, 0x1A)

変換仕様では、int型の場合、%d を利用。
変換仕様では、long型の場合、%ld を利用。

	int i = 325;      // 10進定数
	int j = 0527;     // 8進定数  ※プレフィックスとして 0
	int k = 0x3fff;   // 16進定数 ※プレフィックスとして 0x または 0X

	unsigned uVal = 327u;             // 符号無し ※サフィックスとして u または U 
	long lVal = 0x5FFFFFL;            // long型   ※サフィックスとして l または L 
	unsigned long ulVal = 0736725ul;  // 符号無しlong型

浮動小数点定数

浮動小数点定数: 符号付き実数を表す 10 進数。
※符号付きであり、unsignedとして定義はできず、エラーになる (unsigned float→×, unsigned double→×) 。
基本的に、double型。

float型で扱う場合、サフィックス(接尾子)として、 F または f を使う。(ex. 3.14F, 2.38f)
long double型で扱う場合、サフィックスとして、 L または l を使う。(ex. 3.14L, 2.38l)

変換仕様では、double型の場合、%lf を利用。
変換仕様では、float型の場合、%f を利用。
※指数形式では、%eを利用。


定数値

  • constキーワード は、変数の値が不変(一定)であることを指定し、プログラマが変更するのを防ぐようコンパイラに伝える。
  • const 指定したポインタを、const 指定の無いポインタに代入することはできない。
    ※const 指定の無いポインタによって内容が変更されるのを防ぐため。
int main(){
	const int num1 = 777;
	num1 = 753;           // error! 値の変更は不可

	const int num2;       // error! 初期化子が必要
	num2 = 135;           // error! 値の変更は不可
}

データ型

bool型が、基本データ型としてサポートされている。
bool 型は、2 つの値 (true または false) のいずれかを設定でき、そのサイズは指定されていない。

データ型の例 (※環境依存であり、値は目安。)
種類 データ型 サイズ 扱える値の種類 扱える値の範囲例
型無し void - - -
論理型 bool 1 byte true または false -
文字型 char 1 byte 英数字1文字 -128 ~ 127
unsigned char 1 byte 英数字1文字 (符号なし) 0 ~ 255
整数型 short int 2 byte 整数 -32768 ~ 32767
unsigned short int 2 byte 整数 (符号なし) 0 ~ 65535
int 4 byte 整数 -2147483648 ~ 2147483647
unsigned int 4 byte 整数 (符号なし) 0 ~ 4294967295
long int 4 byte 長整数 -2147483648 ~ 2147483647
unsigned long int 4 byte 長整数 (符号なし) 0 ~ 4294967295
浮動小数点型 float 4 byte 単精度浮動小数点数 3.4E-38 ~ 3.4E+38
double 8 byte 倍精度浮動小数点数 1.7E-308 ~ 1.7E+308
long double 8 byte 拡張精度浮動小数点数 1.7E-308 ~ 1.7E+308

変数

変数: データを一定期間記憶し、固有の名前(識別子)を付けたもの。

  • 英字、数字、アンダースコア(_)を利用する。※ 最初が数字からはダメ。
  • 環境により31文字まで。
  • 大文字、小文字は区別される。
  • キーワード(予約語)はダメ。
  • 型を指定する。
  • 変数宣言がブロックの先頭でなくても良い。(Cでは、規格C99から同様)
  • 関数の外で宣言 → グローバル変数。どの関数でも利用可能。
  • 関数(またはブロック)の中で宣言 → ローカル変数。宣言した関数(またはブロック)内でのみ利用可能。
  • 変数や関数が特定の名前で参照可能な範囲 → スコープ。
  • 異なる関数のローカル変数に同じ名前をつけてもよいが、異なる変数として扱われることになる。
  • グローバル変数とローカル変数に同じ名前をつけてもよいが、ローカル変数としての扱いが優先される。
  • ブロックの外側と内側で同じ変数名をつけてもよいが、ブロック内では内側の変数の扱いが優先される。
// (1)変数の宣言
int x, y;   // 宣言
x = 10;     // 代入
x = 50;     // 上書き
y = x;      // 代入 (yは50)

// (2)変数の初期化
int z = 10; // 初期化
#include <iostream>
using namespace std;

int multiply(int x);
int increment1();   // 関数プロトタイプにおいて、C++では引数のvoidは省略可(Cでは明示する)
int increment2();

// グローバル変数 ※関数外で宣言
int b = 50;         // 動的グローバル変数 ※別のファイルでも利用可能
static int d = 70;  // 静的グローバル変数 ※このファイル内での利用に限定される (static: 記憶クラス指定子)

int main(){
	int a = 75;             // 動的ローカル変数 ※関数内で宣言

	cout << b << endl;      // 結果: b==50  ※動的グローバル変数b

	// ※ C言語の場合では、ブロックの先頭以外での変数宣言はC99から対応
	// ローカル変数とグローバル変数が同じ名前の場合、ローカル変数が優先される
	int b = 25;   // ローカル変数のスコープは、宣言した場所から、その変数を囲むブロックの終了まで
	cout << b << endl;      // 結果: b==25  ※動的ローカル変数b

	a = multiply(b) + a;    // bは動的ローカル変数b
	cout << a << endl;      // 結果: a==40075
	if (a > 40000){
		int c = a - 40000;  // cは動的ローカル変数c ※ブロック内で宣言
		cout << "変数aの値は40000より" << c << "大きい\n";    // 結果: c==75
	}

	int x = 0;
	int y = 0;
	for (int i = 0; i < 10; i++){
		x = increment1();
		y = increment2();
	}
	cout << x << '\n' << y << endl;  // x==10, y==1

	return 0;
}

int multiply(int x){
	int a = 32;       // 動的ローカル変数 ※別の関数のローカル変数と同じ変数名でも、別の変数として扱われる
	x = x * a * b;    // bは動的グローバル変数b
	return x;
}

int increment1(){
	static int a = 0; // 静的ローカル変数aは、関数の処理が終了しても、プログラム終了まで保持される
	a++;
	return a;
}

int increment2(){
	int a = 0;        // 動的ローカル変数aは、関数の処理が終了すると消滅
	a++;
	return a;
}
#include <iostream>
using namespace std;

int a = 50;  // グローバル変数 a
int b = 30;  // グローバル変数 b

int main(){
	int a = 75;  // ローカル変数 a

	// 同名のローカル変数が既に存在する場合、スコープ解決演算子(::)を使用する。
	::a = 62;    // グローバル変数 a

	// 同名のローカル変数が無い場合、スコープ解決演算子(::)を使用する必要はない。
	b = 83;      // グローバル変数 b

	cout << a << endl;        // ローカル変数 a の出力    結果: a==75
	cout << ::a << endl;      // グローバル変数 a の出力  結果: a==62
	cout << b << endl;        // グローバル変数 b の出力  結果: b==83

	return 0;
}

演算子

演算子の種類と優先順位 (※ 上:優先度高い。下:優先度低い。)
優先
順位
演算子 名前 演算子のグループ 結合規則
1 :: スコープ解決 スコープ解決演算子 -
2 ( ) 関数呼び出し 関数呼び出し演算子
[ ] (配列の) 添字 添字演算子
. 直接メンバ参照(: ドット) 直接メンバ参照演算子
-> 間接メンバ参照(: アロー) 間接メンバ参照演算子
++ 後置インクリメント 算術演算子
-- 後置デクリメント
3 ! 論理否定 論理演算子
~ 補数 ビット演算子
+ 単項+ (プラス) 算術演算子
- 単項- (マイナス)
sizeof 記憶量 (: サイズ) sizeof演算子
++ 前置インクリメント 算術演算子
-- 前置デクリメント
& アドレス アドレス演算子
* 間接演算子 間接演算子
new new演算子 new演算子
delete delete演算子 delete演算子
( ) 型変換 (: キャスト) 型変換演算子
4 % 剰余 算術演算子
* 乗算
/ 除算
5 + 加算
- 減算
6 << 左シフト ビット演算子
>> 右シフト
7 > 大なり (より大きい) 関係演算子
>= 大なりイコール(以上)
< 小なり (未満)
<= 小なりイコール (以下)
8 == 等価
!= 非等価
9 & ビット論理積 ビット演算子
10 ^ ビット排他的論理和
11 | ビット論理和
12 && 論理積 論理演算子
13 || 論理和
14 ? : 条件 条件演算子
15 = 単純代入 単純代入演算子
+= 加算代入 複合代入演算子
-= 減算代入
*= 乗算代入
/= 除算代入
%= 剰余代入
&= ビット論理積代入
^= ビット排他的論理和代入
|= ビット論理和代入
<<= 左シフト代入
>>= 右シフト代入
16 , 順次 順次演算子

<注意点>

インクリメント、デクリメント演算子は、前置と後置で処理が異なることに注意。

#include <iostream>
using namespace std;

int main(){
	int x, y, z;
	int a[2] = { 15, 75 };
	int b, c;
	int i;

	x = 5;
	y = ++x;      // 加算してから代入 ※ x=x+1; → y=x; と同じ
	x = 5;
	z = x++;      // 代入してから加算 ※ z=x; → x=x+1; と同じ
	cout << y << '\t' << z << endl;      // 結果: y==6, z==5

	i = 0;
	b = a[++i];   // 加算してから代入 ※ i=i+1; → b=a[i]; と同じ
	i = 0;
	c = a[i++];   // 代入してから加算 ※ c=a[i]; → i=i+1; と同じ
	cout << b << '\t' << c << endl;      // 結果: b==75, c==15

	return 0;
}

関係演算子や論理演算子による条件において、0以外の値 → 真, 0 → 偽 となる。

typedef 指定子

既に言語で定義されている型や、宣言した型に対して、より短い、またはわかりやすい名前を作成できる。
新しい型を導入せず、既存の型に対して新しい名前を導入する。

#include <iostream>
using namespace std;

int main()
{
	typedef unsigned int uint;
	uint int_byte = sizeof(int);       // size_t → unsigned int
	uint double_byte = sizeof(double);
	cout << int_byte << '\n' << double_byte << endl;

	return 0;
}
#include <iostream>
using namespace std;

typedef struct bookdatatag
{
	int bnum;   // book_number
	double bwt; // book_weight
} bookdata;

int main()
{
	bookdata bd;
	bd.bnum = 12;
	bd.bwt = 1.57;
	cout << bd.bnum << '\n' << bd.bwt << endl;

	return 0;
}

ステートメント

Nullステートメント : セミコロン( ; )だけ。実行しても何も起きない。

#include <iostream>
using namespace std;

// charへのポインタを返す関数
char *myStrCpy(char *Dest, const char *Source){
	char *DestStart = Dest;
	while (*Dest++ = *Source++)
		;                        // Nullステートメント

	return DestStart;
}

int main(){
	char *deststart;
	char dest[9] = "airplane";
	char souse[5] = "ship";
	deststart = myStrCpy(dest, souse);
	cout << deststart << endl;         // 結果:ship
	deststart = myStrCpy(dest, "car");
	cout << deststart << endl;         // 結果:car

	return 0;
}
#include <iostream>
using namespace std;

int main(){
	int sample[20];
	int i;
	for (i = 0; i < 10; sample[i++] = 10){  // 最初の10個の要素に値を代入
		;       // Nullステートメント ※なにもしない
	}
	for (i = 10; i < 20; sample[i++] = 25){  // 残りの10個の要素に値を代入
		;       // Nullステートメント ※なにもしない
	}
	for (i = 0; i < 20; i++){
		cout << sample[i] << endl;
	}
	return 0;
}

returnステートメント :関数の実行を終了し、コントロールを呼び出し元の関数に戻す。呼び出し元の関数に値(戻り値)を返すこともできる。

  • returnステートメントを省略または、関数の終わりまでreturnステートメントが実行されなかった場合、return;が行われたとみなされる(戻り値は未定義)。
  • C99とC++98では、main関数に限り、戻り値の型がintであればreturn 0;があったと見なされる。
  • 戻り値が必要ない場合は、voidの戻り値の型を持つように関数を宣言する。
  • 既定の戻り値の型は intである。
#include <iostream>
using namespace std;

int sq(int a);
void output(int b, int c);

int main(){
	int x = 20;
	int y = 30;

	x = sq(x);
	y = sq(y);
	output(x, y);

	return 0;       // returnステートメント
}

int sq(int a){
	return(a*a);    // returnステートメント
}

void output(int b, int c){
	cout << b << '\t' << c << endl;
	return;         // returnステートメント
}

式ステートメント :1 つの値, オブジェクト, メソッド, または名前空間に評価できる、1 つ以上のオペランドと 0 個以上の演算子のシーケンスによるステートメント。

#include <iostream>
using namespace std;

int proc(int a, int b);
int f(int c);

int main(){
	int x = 10;
	int y = 20;
	int z = 30;
	int arg1 = 40;
	int arg2 = 50;

	x = (y + 3);        // 式ステートメント ※xは、y+3の値を代入される。
	x++;                // 式ステートメント ※xは、インクリメントされる。
	x = y = 5;          // 式ステートメント ※xとyの両方に、5が代入される。
	proc(arg1, arg2);   // 式ステートメント ※関数を呼び出し、戻り値が返る。
	y = z = (f(x) + 3); // 式ステートメント ※関数呼び出し。

	cout << x << '\t' << y << '\t' << z << endl; // 結果: x==5, y==28, z==28
	return 0;
}

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

int f(int c){
	return 5 * c;
}

複合ステートメント :波括弧{}で囲まれたステートメントの集合。ブロックのこと。

#include <iostream>
using namespace std;

int main(){
	int x = 100;
	int sample[5] = { 0, 1, 2, 3, 4 };
	int i = 3;

	if (i > 0){            // 複合ステートメントの開始
		sample[i] = x;
		x++;
	}                      // 複合ステートメントの終了
	cout << sample[i] << '\t' << x << endl;

	return 0;
}

ifステートメント :条件が真の場合に、指定した文を処理する。

#include <iostream>
using namespace std;

int main(){
	int num;
	cout << "偶数を入力してください\n";
	cin >> num;
	if (!(num % 2)){      // 条件判断
		cout << "偶数" << num << "が入力されました。\n"; // 1文のときは、ブロックにしなくてもいい
	}
	cout << "終了します。\n";

	return 0;
}

if~else :条件が真の場合と、偽の場合に、指定した文を処理する。

#include <iostream>
using namespace std;

int main(){
	int num;
	cout << "整数を入力してください\n";
	cin >> num;
	if (!(num % 2)){      // 条件判断
		cout << "偶数" << num << "が入力されました。\n"; // 1文のときは、ブロックにしなくてもいい
	}
	else {
		cout << "奇数" << num << "が入力されました。\n"; // 1文のときは、ブロックにしなくてもいい
	}
	cout << "終了します。\n";

	return 0;
}

if~else if ~else :2つ以上の条件を判断し、処理する。

#include <iostream>
using namespace std;

int main(){
	int num;
	cout << "整数を入力してください\n";
	cin >> num;
	if (!(num % 2) && num >= 20){      // 条件判断
		cout << "20以上の偶数" << num << "が入力されました。\n";     // 1文のときは、ブロックにしなくてもいい
	}
	else if (!(num % 2)){
		cout << "20より小さい偶数" << num << "が入力されました。\n"; // 1文のときは、ブロックにしなくてもいい
	}
	else{
		cout << "奇数" << num << "が入力されました。\n";             // 1文のときは、ブロックにしなくてもいい
	}
	cout << "終了します。\n";

	return 0;
}

forステートメント :指定した回数だけステートメントを繰り返す

#include <iostream>
using namespace std;

int main(){
	int sum = 0;

	for (int i = 1; i <= 10; i++){   // forステートメント
		sum += i;
	}

	cout << "1から10までの数の合計は" << sum << "です。\n";

	return 0;
}

whileステートメント :指定した式が false になるまでステートメントを繰り返す。

#include <iostream>
using namespace std;

int main(){
	char string1[8] = "destiny";
	char string2[8] = "honesty";
	int i = 7;

	while (i >= 0){               // whileステートメント
		string1[i] = string2[i];  // string2 から string1 に文字をコピー
		i--;
	}

	cout << string1 << endl;

	return 0;
}

do-whileステートメント :指定した式が false になるまでステートメントを繰り返す。ループの本体は少なくとも一度は常に実行される。

#include <iostream>
using namespace std;

int main(){
	char string1[8] = "destiny";
	char string2[8] = "honesty";
	int i = 7;

	do{                           // do-whileステートメント
		string1[i] = string2[i];  // string2 から string1 に文字をコピー
		i--;
	} while (i >= 0);

	cout << string1 << endl;

	return 0;
}

switchステートメント :条件式の値に応じて、多分岐を行う。

#include <iostream>
using namespace std;

int main(){
	int a;
	cout << "整数を入力してください。\n";
	cin >> a;

	switch (a){      // switchステートメント
	case 1:
		cout << "1が入力されました。\n";
		break;
	case 2:
		cout << "2が入力されました。\n";
		break;
	case 3:
	case 4:
		cout << "3または4が入力されました。\n";
		break;
	case 5:
		cout << "5が入力されました。\n";
		break;
	default:         // defaultの処理が必要ない場合は省略可能
		cout << "1~5以外の整数が入力されました。\n";
		break;
	}

	return 0;
}

continueステートメント :最も内側の、do, for, while のステートメントにおいて、残りのステートメントを実行せず、次のループに移る。

#include <iostream>
using namespace std;

int main(){
	int sum = 0;
	for (int i = 0; i <= 10; i++){
		if (i % 2){
			continue;     // continueステートメント
		}
		sum += i;
	}
	cout << "0から10までの偶数の数の合計は" << sum << endl;  // 結果: sum==30

	return 0;
}

breakステートメント :最も内側の、do, for, switch または while のステートメントの実行を終了する。

#include <iostream>
using namespace std;

int main(){
	int flag = 0;
	int x = 0;
	int y = 0;

	for (int i = 0; i < 10; i++){
		for (int j = 0; j < 10; j++){
			if (x*y == 50){
				flag = 1;
				break;    // breakステートメント
			}
			x++;
		}
		if (flag == 1){
			break;        // breakステートメント
		}
		y++;
	}
	cout << x << '\t' << y << endl;  // 結果: x==25, y==2

	return 0;
}

gotoステートメント :制御をラベルに移す。

#include <iostream>
using namespace std;

int main(){
	int x = 0;
	int y = 0;

	for (int i = 0; i < 10; i++){
		for (int j = 0; j < 10; j++){
			if (x*y == 50){
				goto mylabel;   // gotoステートメント
			}
			x++;
		}
		y++;
	}

mylabel:
	cout << x << '\t' << y << endl;   // 結果: x==25, y==2

	return 0;
}

関数

関数 : 識別子を持ち、いくつかの文がブロックでまとめられた、一連の命令群。

#include <iostream>
using namespace std;

// 関数形式マクロ ※引数の型は制限されない
#define MULTIPLY(x, y) ((x) * (y))

// 関数の定義
void display1(){                    // 仮引数のvoidは省略可
	cout << "関数1です。\n";

	// サブルーチンからの復帰
	return;                         // 省略可 ※省略した場合もreturn;があると見なされる
}

// 関数プロトタイプ
void display2();                    // 関数プロトタイプにおいて、C++では引数のvoidは省略可(Cでは明示する)

double multiply(int x, double y);   // 関数プロトタイプでは仮引数の名前を省略できる。
                                    // → 但し、引数の意味や目的を、引数名から判断できなくなる。

int main(){                         // 仮引数のvoid省略可
	double x, y;
	display1();                     // 関数呼び出し
	display2();                     // 関数呼び出し
	x = multiply(5, 3.14);          // 関数を呼び出し、戻り値を変数xに代入 ※5, 3.14 は実引数
	y = MULTIPLY(5, 3.14);          // 通常の関数処理に比べて、関数形式マクロのほうが処理が早い場合がある
	cout << x << '\n' << y << endl;

	return 0;     // C++98(及びC99)では、main関数に限り、戻り値の型がintであればreturn 0;があったと見なされる
}

// 関数の定義
void display2(){                    // 仮引数のvoid省略可
	cout << "関数2です。\n";
	return;                         // 省略可
}

// 関数の定義
double multiply(int x, double y){   // int x, double y は仮引数
	return x*y;                     // double型の戻り値を返す
}

インライン関数

コンパイラに対して、その関数を呼び出している箇所に関数の実体を挿入(インライン展開)するよう指示する。
コンパイラの費用対効果分析により利益があるとわかった場合のみ挿入がなされる。

#include <iostream>
using namespace std;

// インライン関数
inline int max(int a, int b) {
	if (a > b)
		return a;
	return b;
}

int main(){
	int x = 29;
	int y = 76;
	int resultmax = max(x, y);
	cout << resultmax << endl;

	return 0;
}

デフォルト引数

関数を呼び出す際に、実引数を省略でき、デフォルト値が仮引数で扱われる。
※ 関数プロトタイプ、または定義のいずれかで指定し、両方で指定することはできない。
引数が複数ある場合は、右から順に設定する。

#include <iostream>
using namespace std;

// デフォルト引数は右から設定する
int add(int a, int b, int c = 10, int d = 20, int e = 30);

int main(){
	int num1 = 40;
	int num2 = 50;
	int num3 = 60;
	int num4 = 70;
	int num5 = 80;
	int resultadd;

	// 実引数で値を指定した場合はそのまま採用され、指定しない場合はデフォルト引数が採用される
	resultadd = add(num1, num2, num3, num4, num5);
	cout << resultadd << endl;     // 40 + 50 + 60 + 70 + 80 = 300

	resultadd = add(num1, num2, num3, num4);
	cout << resultadd << endl;     // 40 + 50 + 60 + 70 + 30 = 250

	resultadd = add(num1, num2, num3);
	cout << resultadd << endl;     // 40 + 50 + 60 + 20 + 30 = 200

	resultadd = add(num1, num2);
	cout << resultadd << endl;     // 40 + 50 + 10 + 20 + 30 = 150

	return 0;
}

// 関数プロトタイプでデフォルト引数を指定したので、関数定義では指定しない
int add(int a, int b, int c, int d, int e) {
	return a + b + c + d + e;
}

関数のオーバーロード

同じスコープで、同じ名前の関数を複数定義し、利用時にプログラムの文脈に応じて選択することで、複数の動作を行わせる仕組み(多重定義)。
同じ関数名で引数の型や数が異なる関数を作成する。

関数のオーバーロードは、関数で同じような処理も、異なるような処理もできる。
(※ 関数テンプレートは、関数内で同じような処理をする。型が異なる。)

#include <iostream>
using namespace std;

int add(int a, int b);
double add(double a, double b);

int main(){
	int inum1 = 10;
	int inum2 = 20;
	double dnum1 = 30.52;
	double dnum2 = 40.45;

	int iresultadd = add(inum1, inum2);
	cout << iresultadd << endl;     // 10 + 20 = 30

	double dresultadd = add(dnum1, dnum2);
	cout << dresultadd << endl;     // 30.52 + 40.45 = 70.97

	return 0;
}

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

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

関数テンプレート

自由な型の引数を受け取ることができる、関数のひな型のようなもの。

関数テンプレートは、関数内で同じような処理をする。型が異なる。
(※ 関数のオーバーロードは、関数で同じような処理も、異なるような処理もできる。)

#include <iostream>
using namespace std;

// 関数テンプレート
template <typename T>
T max(T a, T b){       // T:テンプレート仮引数
	if (a > b)
		return a;
	return b;
}

int main(){
	int inum1 = 10;
	int inum2 = 20;
	double dnum1 = 30.52;
	double dnum2 = 40.45;

	int iresultadd = max(inum1, inum2);     // 実引数の値の型:テンプレート実引数 ※ここではint
	cout << iresultadd << endl;     // 20

	double dresultadd = max(dnum1, dnum2);  // 実引数の値の型:テンプレート実引数 ※ここではdouble
	cout << dresultadd << endl;     // 40.45

	return 0;
}

ポインタ

ポインタ : 特定のメモリ領域を参照するための値をもつ変数。メモリアドレスを格納することができる変数。

#include <iostream>
using namespace std;

int main(){
	int x = 25;
	int *a;        // int型へのポインタ a の宣言 (宣言時における* : 名前(識別子)をポインタとして宣言
	               // この宣言は、記号表現として、*aという表現がintであることを表す。

	// ポインタの初期化 (& :アドレス演算子)
	int *b = &x;   // 変数xのアドレスを、ポインタbに代入。※ポインタbは変数xを指す。

	a = &x;        // 変数xのアドレスを、ポインタaに代入。※ポインタaは変数xを指す。
	cout << "変数xのアドレスは" << &x << "です\n";            // アドレスの変換仕様には%pを利用する。
	cout << "ポインタaの値は" << a << "です。\n";             // &xとaは同じ値。

	// 間接演算子(*)を利用して、ポインタが指すアドレス(の値)にアクセスする。(ポインタ利用時における* :間接演算子)
	cout << "変数xの値は" << x << "です。\n";                     // 結果:  x==25
	cout << "ポインタaが指すアドレスの値は" << *a << "です。\n";  // 結果: *a==25
	cout << "ポインタbが指すアドレスの値は" << *b << "です。\n";  // 結果: *b==25

	*b = 75;       // ポインタbが指すアドレスの値に、75を代入する。※変数xに値の代入をしたことになる。
	cout << "変数xの値は" << x << "です。\n";                     // 結果:  x==75 に変わる。
	cout << "ポインタaが指すアドレスの値は" << *a << "です。\n";  // 結果: *a==75 に変わる。
	cout << "ポインタbが指すアドレスの値は" << *b << "です。\n";  // 結果: *b==75 に変わる。

	return 0;
}
#include <iostream>
using namespace std;

void replace1(int a, int b);
void replace2(int *a, int *b);

int main(){
	int x = 25;
	int y = 75;

	replace1(x, y);
	cout << "xは" << x << "yは" << y << "です。\n";  // 結果: x==25, y==75

	replace2(&x, &y);                                // 実引数をアドレスにする
	cout << "xは" << x << "yは" << y << "です。\n";  // 結果: x==75, y==25

	return 0;
}

// 値渡し
void replace1(int a, int b){
	int c;
	c = a;
	a = b;
	b = c;
}

// 参照渡し
void replace2(int *a, int *b){   // 仮引数をポインタにする
	int c;
	c = *a;
	*a = *b;
	*b = c;
}
#include <iostream>
using namespace std;

int main(){
	char c[] = "Honesty";
	char *p = "Honesty";  // どこかのアドレスに文字列が格納され、そのアドレスを指す

	cout << c << endl;
	cout << p << endl;

	p = "destiny";        // 配列では初期化後に""での代入はできないが、ポインタでは可能
	cout << p << endl;

	return 0;
}
#include <iostream>
using namespace std;

int main(){
	int i;

	// ""による文字列の初期化では'\0'が最後に格納されるので、各文字列は9文字以内にする
	char str1[3][10] = { "Sunday", "Monday", "Tuesday" }; // 10個までの値を格納可能な配列を、3つ格納可能な多次元配列

	char *str2[3] = { "Sunday", "Monday", "Tuesday" };    // 文字列を指すポインタが3つの配列

	for (i = 0; i < 3; i++){
		cout << str1[i] << '\t' << str2[i] << endl;
	}

	str2[0] = "Wednesday";   // ポインタの配列の場合、指す文字列を変更可能
	str2[1] = "Thursday";
	str2[2] = "Friday";
	for (i = 0; i < 3; i++){
		cout << str2[i] << endl;
	}

	return 0;
}

リファレンス (参照)

リファレンスはオブジェクトの別名。
初期設定時に指示されたオブジェクトを参照し続ける。
リファレンスは初期設定が必要であり、後で変更はできない。

#include <iostream>
using namespace std;

int main(){
	// リファレンス ---------------------------------------------------------------------
	int a = 20;
	int& ra = a;    // リファレンスでは、宣言時に必ず初期化をする

	cout << "変数aの値は" << ra << '\t' << "アドレスは" << &ra << endl;
	cout << "リファレンスraの値は" << ra << '\t' << "アドレスは" << &ra << endl;

	ra = 30;
	cout << "変数aの値は" << ra << '\t' << "アドレスは" << &ra << endl;
	cout << "リファレンスraの値は" << ra << '\t' << "アドレスは" << &ra << endl;

	// ポインタ -------------------------------------------------------------------------
	int b = 40;
	int* pb = &b;   // ポインタでは、宣言時の初期化は、必ずしも必要としない

	cout << "変数bの値は" << b << '\t' << "アドレスは" << &b << endl;
	cout << "ポインタpbの値は" << pb << '\t' << "アドレスは" << &pb << endl;

	*pb = 50;
	cout << "変数bの値は" << b << '\t' << "アドレスは" << &b << endl;
	cout << "ポインタpbの値は" << pb << '\t' << "アドレスは" << &pb << endl;

	return 0;
}
#include <iostream>
using namespace std;

void replace1(int a, int b);
void replace2(int* a, int* b);
void replace3(int& a, int& b);

int main(){
	int x = 25;
	int y = 75;

	replace1(x, y);
	cout << "xは" << x << "yは" << y << "です。\n";  // 結果: x==25, y==75

	replace2(&x, &y);                                // 実引数をアドレスにする
	cout << "xは" << x << "yは" << y << "です。\n";  // 結果: x==75, y==25

	// リファレンスの利用
	replace3(x, y);                                  // 実引数を変数にする
	cout << "xは" << x << "yは" << y << "です。\n";  // 結果: x==25, y==75

	return 0;
}

// 値渡し
void replace1(int a, int b){
	int c;
	c = a;
	a = b;
	b = c;
}

// 参照渡し
void replace2(int* a, int* b){   // 仮引数をポインタにする
	int c;
	c = *a;
	*a = *b;
	*b = c;
}

// リファレンスの利用
void replace3(int& a, int& b){   // 仮引数をリファレンスにする
	int c;
	c = a;
	a = b;
	b = c;
}

配列

配列 : 同じ型の値を複数まとめて記憶する機能。

#include <iostream>
using namespace std;

#define NUM 3   // マクロ

int main(){
	const int num = 3;  // constキーワードはオブジェクトまたは変数が変更できないことを指定する

	int sample1[3];                    // 配列の宣言 ※要素数を利用
	int sample2[3] = { 25, 57, 12 };   // 配列の初期化 ※初期化子を利用(25,57,12など)
	int sample3[] = { 25, 57, 12 };    // 配列の初期化では、要素数を省略可能
	int sample4[3] = { 25, 57 };       // 要素数よりも初期化子が少ない場合、残りの要素に0が入る
	int sample5[NUM] = { 25, 57, 12 }; // マクロの利用
	int sample6[num] = { 25, 57, 12 }; // constキーワードによる定数の利用

	sample1[0] = 25;  // 配列要素への、値の代入 ※添字を利用
	sample1[1] = 57;
	sample1[2] = 12;

	for (int i = 0; i < NUM; i++){
		cout << sample1[i] << '\t' << sample2[i] << '\t' << sample3[i]
			<< '\t' << sample4[i] << '\t' << sample5[i] << '\t' << sample6[i] << endl;   // \tは水平タブ
	}
	return 0;
}
#include <iostream>
using namespace std;

#define NUM 8   // マクロ

int main(){
	const int num = 8;  // constキーワードはオブジェクトまたは変数が変更できないことを指定する

	char str1[8];                                                 // 文字配列の宣言 ※要素数を利用
	char str2[8] = { 'H', 'o', 'n', 'e', 's', 't', 'y', '\0' };   // 文字配列の初期化 ※初期化子を利用('H','o'など)
	char str3[] = { 'H', 'o', 'n', 'e', 's', 't', 'y', '\0' };    // 文字配列の初期化では、要素数を省略可能
	char str4[8] = "Honesty";     // ""による代入は、初期化のときのみ使用可能 ※自動的にNULL文字が代入される
	char str5[] = "Honesty";      // 文字配列の初期化では、要素数を省略可能
	char str6[NUM] = { 'H', 'o', 'n', 'e', 's', 't', 'y', '\0' }; // マクロの利用
	char str7[num] = { 'H', 'o', 'n', 'e', 's', 't', 'y', '\0' }; // constキーワードによる定数の利用
	int i;

	str1[0] = 'H';  // 文字配列の要素への、値の代入 ※添字を利用
	str1[1] = 'o';
	str1[2] = 'n';
	str1[3] = 'e';
	str1[4] = 's';
	str1[5] = 't';
	str1[6] = 'y';
	str1[7] = '\0'; // NULL文字

	// 書き出し例 1
	for (i = 0; i < NUM; i++){
		cout << str1[i];
	}
	cout << '\n';

	// 書き出し例 2
	for (i = 0; str1[i] != '\0'; i++){
		cout << str1[i];
	}
	cout << '\n';

	// 書き出し例 3
	i = 0;
	while (str1[i]){        // \0は、コード0
		cout << str1[i];
		i++;
	}
	cout << '\n';

	// 書き出し例 4
	cout << str1 << endl;   // 配列名は、先頭要素へのポインタのように扱われる。(但し他のアドレスを代入はできない)

	// ------------------------------------------------------------------------------------------------------------------
	// 書き出し例 4 のやりかたで全ての結果を表示してみる
	cout << str1 << '\t' << str2 << '\t' << str3 << '\t' << str4 << '\t' << str5 << '\t' << str6 << '\t' << str7 << endl;

	return 0;
}

多次元配列 : 配列そのものを要素として持つ配列。

#include <iostream>
using namespace std;

int main(){
	int sample1[3][5];   // 多次元配列の宣言

	// 多次元配列の初期化
	int sample2[3][5] = { { 13, 42, 3, 12, 3 }, { 10, 9, 203, 62, 58 }, { 906, 0, 2058, 55, 7 } };

	// 初期化では最初の配列要素数を省略可能
	int sample3[][5] = { { 13, 42, 3, 12, 3 }, { 10, 9, 203, 62, 58 }, { 906, 0, 2058, 55, 7 } };
	// ※これは無理 int sample4[][] = { { 13, 42, 3, 12, 3 }, { 10, 9, 203, 62, 58 }, { 906, 0, 2058, 55, 7 } };

	sample1[0][0] = 13;  // 多次元配列への値の代入
	sample1[0][1] = 42;
	sample1[0][2] = 3;
	sample1[0][3] = 12;
	sample1[0][4] = 3;

	sample1[1][0] = 10;
	sample1[1][1] = 9;
	sample1[1][2] = 203;
	sample1[1][3] = 62;
	sample1[1][4] = 58;

	sample1[2][0] = 906;
	sample1[2][1] = 0;
	sample1[2][2] = 2058;
	sample1[2][3] = 55;
	sample1[2][4] = 7;

	for (int i = 0; i < 3; i++){
		for (int j = 0; j < 5; j++){
			cout << sample1[i][j] << '\t' << sample2[i][j] << '\t' << sample3[i][j] << endl;
		}
	}

	return 0;
}

ポインタ演算

ポインタ演算 (※p, p1, p2はポインタ)
ポインタ演算 説明
p + n  pが指すアドレスに n*sizeof(pointer_type) を加算した
 アドレスを指す。
p - n  pが指すアドレスから n*sizeof(pointer_type) を減算した
 アドレスを指す。
p1 - p2  ((long)p1 - (long)p2)/sizeof(pointer_type)
  → p1 と p2 の間の要素数を得る。
p++  pが指すアドレスに sizeof(pointer_type) を加算した
 アドレスを指す。p+1の結果と同じ。
p--  pが指すアドレスから sizeof(pointer_type) を減算した
 アドレスを指す。p-1の結果と同じ。
#include <iostream>
using namespace std;

int main(){
	int sample[3] = { 56, 652, 12 };

	// 値 ------------------------------------------------------------------------------------------------------------
	// sample[0] と *sample は同じ値
	cout << "sample[0] の値は、" << sample[0] << "です。\n";
	cout << "*sample の値は、" << *sample << "です。\n";        // 配列名は、先頭要素へのポインタのように扱われる。
	                                                            // (但し他のアドレスを代入はできない)

	// sample[1] と *(sample + 1) は同じ値
	cout << "sample[1] の値は" << sample[1] << "です。\n";
	cout << "*(sample + 1) の値は" << *(sample + 1) << "です。\n";

	// sample[2] と *(sample + 2) は同じ値
	cout << "sample[2] の値は、" << sample[2] << "です。\n";
	cout << "*(sample + 2) の値は、" << *(sample + 2) << "です。\n";

	// アドレス ------------------------------------------------------------------------------------------------------
	// &sample[0] と sample は同じ値
	cout << "sample[0] のアドレスは、" << &sample[0] << "です。\n";
	cout << "sample の値は、" << sample << "です。\n";          // 配列名は、先頭要素へのポインタのように扱われる。
	                                                            // (但し他のアドレスを代入はできない)

	// &sample[1] と sample + 1 は同じ値
	cout << "sample[1] のアドレスは、" << &sample[1] << "です。\n";
	cout << "sample + 1 の値は、" << sample + 1 << "です。\n";  // sampleが指すアドレスに、sizeof(int)を加算したアドレスを指す。
	                                                            // → sampleが指す要素の、1つ次の要素のアドレス値を意味する。

	// &sample[2] と sample + 2 は同じ値
	cout << "sample[2] のアドレスは、" << &sample[2] << "です。\n";
	cout << "sample + 2 の値は、" << sample + 2 << "です。\n";  // sampleが指すアドレスに、2 * sizeof(int)を加算したアドレスを指す。
	                                                            // → sampleが指す要素の、2つ次の要素のアドレス値を意味する。
	return 0;
}
#include <iostream>
using namespace std;

int add(int t[]);        // 仮引数が配列
int multiply(int *p);    // 仮引数がポインタ
double average(int *p);  // 仮引数がポインタ

int main(){
	int sample[3] = { 33, 652, 13 };
	int resultAdd, resultMultiply;
	double resultAverage;

	// (1)
	resultAdd = add(sample);  // 実引数が配列名
	cout << "3つの値を加算した結果は、" << resultAdd << "です。\n";

	// (2)
	resultMultiply = multiply(sample);
	cout << "3つの値を乗算した結果は、" << resultMultiply << "です。\n";

	// (3)
	resultAverage = average(sample);
	cout << "3つの値を平均した結果は、" << resultAverage << "です。\n";

	return 0;
}

int add(int t[]){             // 仮引数が配列
	int summation = 0;
	for (int i = 0; i < 3; i++){
		summation += t[i];
	}
	return summation;
}

int multiply(int *p){         // 仮引数がポインタ
	int product = 1;
	for (int i = 0; i < 3; i++){
		product *= *(p + i);  // ポインタ演算の利用
	}
	return product;
}

double average(int *p){       // 仮引数がポインタ
	double average = 0;
	for (int i = 0; i < 3; i++){
		average += p[i];      // 添字演算子[]の利用
	}
	return average / 3;
}

文字列の操作

#include <iostream>
#include <string>      // strlen(), strcpy(), strcat(), strcmp()の利用
using namespace std;

int main(){
	// 配列の大きさに注意
	char str[9] = "Blue Sky";
	char str1[30];
	char str2[30];

	// 文字列の長さ(length)を調べる -------------------------------------------------------------------------------------------
	cout << "文字列の長さは" << strlen(str) << "です。\n";   // strlen(str) :str の文字数を返す。空白文字は含む。\0は含まない

	// 文字列を配列にコピーする(copy) -----------------------------------------------------------------------------------------
	strcpy(str1, "Blue Sky");            /* strcpy(strDestination, strSource) :終端の\0を含めてstrSourceをstrDestinationで
										 指定された位置にコピーし、strDestinationを返す */
	strcpy(str2, "Twilight Sky");
	cout << "str1は、" << str1 << "です。\n";
	cout << "str2は、" << str2 << "です。\n";

	strcpy(str1, str2);
	cout << "str1は、" << str1 << "に変更されました。\n";

	strcpy(str1, "Starry Sky");
	cout << "str1は、" << str1 << "に変更されました。\n";

	// 文字列を連結する(concatenate) ------------------------------------------------------------------------------------------
	strcat(str1, str2);           /* strcat(strDestination, strSource) :strSourceをstrDestinationに追加し、終端に\0を付け、
								  strDestinationを返す。strSourceの先頭の文字はstrDestinationの終端の\0を上書きする */
	cout << "文字列を連結すると" << str1 << "です。\n";

	// 文字列を辞書式の順序で比較する(compare) --------------------------------------------------------------------------------
	if (strcmp(str1, str2) == 0){                    /* strcmp(string1, string2) :string1とstring2を辞書式の順序で比較し、
													 その関係を示す値を返す */
		cout << "str1とstr2の文字列は同じです。\n";
	}
	else if (strcmp(str1, str2) > 0){
		cout << "str1は、str2より大きい。\n";
	}
	else if (strcmp(str1, str2) < 0){
		cout << "str1は、str2より小さい。\n";
	}

	return 0;
}

ファイルの分割

ヘッダファイル :外部に公開する個々の関数、オブジェクト、データ型などの宣言をする。

extern : 記憶クラス指定子の一つ。変数または関数を宣言し、外部リンケージを持つことを指定する。

<グローバル変数について>

  • 記憶クラス指定子と初期化子の無い外部データ宣言は仮定義となる。
    宣言された識別子がその後で定義されている場合、仮定義は externがあるのと同等に処理される。
    仮定義は参照宣言になる。
  • 識別子が、その識別子の以前の宣言が可視である有効範囲において、記憶クラス指定子externを伴って宣言される場合
    → 以前の宣言において内部結合又は外部結合が指定されているならば、新しい宣言における識別子は、以前の宣言と同じ結合をもつ。
    → 可視である以前の宣言がない場合、又は以前の宣言が無結合である場合、この識別子は外部結合をもつ。
  • グローバル変数はデフォルトで外部リンケージを持つ。
  • ヘッダファイルでグローバル変数を初期化すると、それをインクルードするソースファイルが複数ある場合に、初期化が重複するので、再定義エラーとなる。
  • ヘッダファイルをインクルードするソースファイルが一つであり、且つ、ソースファイルで初期化をしない場合は、ヘッダファイルで初期化をしてもエラーにならない。
  • ヘッダファイルでは宣言だけにするのが無難。
  • static(記憶クラス指定子の一つ)の利用で内部リンケージにすることが可能。

<関数ついて>

  • externを省略しても、externがあるのと同等なので、書いても書かなくても同じ。
    → 関数はデフォルトで外部リンケージを持つ。
  • ヘッダファイルで関数を定義すると、それをインクルードするソースファイルが複数ある場合に、定義が重複するので、再定義エラーとなる。
  • ヘッダファイルをインクルードするソースファイルが一つであり、且つ、ソースファイルで関数定義をしない場合は、ヘッダファイルで関数定義をしてもエラーにならない。
  • ヘッダファイルでは宣言(関数プロトタイプ)だけにするのが無難。
  • static(記憶クラス指定子の一つ)の利用で内部リンケージにすることが可能。
// myheader.h

// インクルードガード ※インクルードが重複した時に、#ifndef ~ #endifまでの間のコードをコンパイルしない
// _MULTIPLY_H_の部分の文字は任意
#ifndef _MULTIPLY_H_         // もしも_MULTIPLY_H_が未定義ならば#endifまでのコードをコンパイルする
#define _MULTIPLY_H_

// グローバル変数の宣言
extern int gblvar;           // extern : 変数または関数を宣言し、外部リンケージを持つことを指定する

// 関数プロトタイプ
int multiply(int x, int y);  // 関数プロトタイプにより、関数の宣言をする

#endif
// multiply.cpp

// 自作のヘッダファイルのインクルード
#include "myheader.h"  // カレントディレクトリからのインクルード

// グローバル変数の定義
int gblvar = 10;

// 関数の定義
int multiply(int x, int y){
	return gblvar * x * y;
}
// sample.cpp

// 標準ライブラリのヘッダファイルのインクルード
#include <iostream>     // インクルードディレクトリからのインクルード

// 自作のヘッダファイルのインクルード
#include "myheader.h"  // カレントディレクトリからのインクルード

using namespace std;

int main(){
	int x;
	x = multiply(20, 30);

	cout << "gblvarの値は" << gblvar << endl;       // gblvar == 10
	cout << "multiply関数の戻り値は" << x << endl;  // x == 6000

	return 0;
}

動的メモリ確保

動的メモリ確保 : メモリ管理のひとつ。プログラムの実行をしながら、並行して必要なメモリ領域の確保と解放を行う仕組み。

#include <iostream>
using namespace std;

int main(){
	// 動的メモリ確保
	int* px;                // 確保したメモリのアドレスを記憶しておくための、ポインタを用意
	px = new int;           // new演算子はメモリ領域を確保し、その確保したメモリのアドレスを返す

	*px = 50;
	cout << *px << endl;

	// 動的メモリ解放
	delete px;

	// 配列の動的メモリ確保 --------------------------------------------------------------------	
	cout << "いくつの整数を入力しますか?\n";
	int num;
	cin >> num;

	// 動的メモリ確保
	int* parray;            // 確保したメモリのアドレスを記憶しておくための、ポインタを用意
	parray = new int[num];  // new演算子はメモリ領域を確保し、その確保したメモリのアドレスを返す

	for (int i = 0; i < num; i++){
		cout << i + 1 << "番目の整数は?\n";
		cin >> parray[i];
	}

	for (int i = 0; i < num; i++){
		cout << i + 1 << "番目の整数: " << parray[i] << endl;
	}

	// 動的メモリ解放
	delete[] parray;

	return 0;
}

列挙型

  • 列挙型 : 複合型に属する、データ型の一つ(CではC89で追加)。
  • 識別子をもった整数定数のリストである。
  • 列挙型を用いることで、整数定数の代わりに識別子を使うことができ、ソースコードの可読性を高める。
  • 識別子を値(列挙定数)として格納できる。
  • 列挙定数は、int型の定数(整数定数)であり、列挙定数による数値演算が可能である。
  • 列挙型の変数を宣言するときの、enumキーワードは省略可。
    ※付けても可だが、付けないのが一般的な感じ。(Cでは必須)
#include <iostream>
using namespace std;

// 列挙型の型の宣言 ※typedefで新たな型名を定義するかは任意
enum WeekA{ SUNA, MONA, TUEA, WEDA, THUA, FRIA, SATA };           // 左から、0,1,2,3,4,5,6
enum WeekB{ SUNB, MONB, TUEB, WEDB, THUB, FRIB, SATB };           // 左から、0,1,2,3,4,5,6
enum WeekC{ SUNC, MONC, TUEC = 0, WEDC, THUC, FRIC = 25, SATC };  // 左から、0,1,0,1,2,25,26

int main(){
	WeekA dayA;    // 列挙型WeekAの変数dayAの宣言
	WeekB dayB;
	WeekC dayC;

	dayA = WEDA;   // 代入 ※列挙定数は、変数名などのような識別子なので、文字列リテラルのように""で括らない
	dayB = MONB;
	dayC = SATC;

	switch (dayA)  // 列挙定数を、識別子のまま利用
	{
	case SUNA:
		cout << "日曜日です。\n"; break;
	case MONA:
		cout << "月曜日です。\n"; break;
	case TUEA:
		cout << "火曜日です。\n"; break;
	case WEDA:
		cout << "水曜日です。\n"; break;
	case THUA:
		cout << "木曜日です。\n"; break;
	case FRIA:
		cout << "金曜日です。\n"; break;
	case SATA:
		cout << "土曜日です。\n"; break;  // 最後のbreak;は省略可
	}
	cout << '\n';

	switch (dayB)  // 列挙定数を、int型の定数(整数定数)として利用
	{
	case 0:
		cout << "日曜日です。\n"; break;
	case 1:
		cout << "月曜日です。\n"; break;
	case 2:
		cout << "火曜日です。\n"; break;
	case 3:
		cout << "水曜日です。\n"; break;
	case 4:
		cout << "木曜日です。\n"; break;
	case 5:
		cout << "金曜日です。\n"; break;
	case 6:
		cout << "土曜日です。\n"; break;
	}
	cout << '\n';

	switch (dayC)  // 列挙定数を、int型の定数(整数定数)として利用
	{
	case 0:
		cout << "日曜日または火曜日です。\n"; break;
	case 1:
		cout << "月曜日または水曜日です。\n"; break;
	case 2:
		cout << "木曜日です。\n"; break;
	case 25:
		cout << "金曜日です。\n"; break;
	case 26:
		cout << "土曜日です。\n"; break;
	}

	return 0;
}

構造体 (クラスキー: struct)

  • C++における構造体は、クラスの一種。
    → メンバがデフォルトで公開されるクラスとして定義される。(Cと異なる)
  • 配列は同じ型のデータのみ格納できるのに対して、構造体は、同じ型と異なる型のデータをまとめて格納できる。(Cと同じ)
  • メンバ関数を持つことが可能。(Cと異なる)
  • 既定のアクセスは publicである。クラスキー:structでは、アクセス指定子を省略した場合、publicメンバとなる。
    (←→ クラスキー:classでは省略した場合、privateメンバとなる)
  • 構造体型の変数を宣言するときの、structキーワードは省略可。
    ※付けても可だが、付けないのが一般的な感じ。(Cでは必須)
#include <iostream>
using namespace std;

// 構造体の型(struct AnthropometricData)の宣言
struct AnthropometricData{
	char *name;       // メンバ変数 ※char *型のポインタname
	int age;          // メンバ変数
	double height;    // メンバ変数
	double weight;    // メンバ変数
};                    // セミコロン(;)が必要。

int main(){
	AnthropometricData x;  // 構造体 AnthropometricData 型の変数 x の宣言

	// ドット演算子(.)を利用して、構造体の各メンバにアクセスする
	x.name = "日本太郎";
	x.age = 23;
	x.height = 167.5;

	cout << "体重を入力してください\n";
	cin >> x.weight;      // アドレス演算子(&)は、構造体変数名の前に使用する

	cout << "名前:" << x.name << endl;
	cout << "年齢:" << x.age << "歳\n";
	cout << "身長:" << x.height << "cm\n";
	cout << "体重:" << x.weight << "kg\n";

	return 0;
}
#include <iostream>
using namespace std;

// 構造体の型の宣言と、構造体変数の宣言を同時に行う
struct AnthropometricData{
	char *name;
	int age;
	double height;
	double weight;
}a, b;                // 構造体変数aとbの宣言

// 構造体の型名の省略
struct{
	char *name;
	int age;
	double height;
	double weight;
}c;                   // 構造体変数cの宣言

int main(){
	a.name = "日本太郎";
	a.age = 23;
	a.height = 170.5;
	a.weight = 70.3;

	b.name = "日本花子";
	b.age = 22;
	b.height = 160.2;
	b.weight = 45.2;

	cout << "名前:" << a.name << endl;
	cout << "年齢:" << a.age << "歳\n";
	cout << "身長:" << a.height << "cm\n";
	cout << "体重:" << a.weight << "kg\n";
	cout << '\n';

	cout << "名前:" << b.name << endl;
	cout << "年齢:" << b.age << "歳\n";
	cout << "身長:" << b.height << "cm\n";
	cout << "体重:" << b.weight << "kg\n";
	cout << '\n';

	c.name = "日本一郎";
	c.age = 22;
	c.height = 165.5;
	c.weight = 65.5;

	cout << "名前:" << c.name << endl;
	cout << "年齢:" << c.age << "歳\n";
	cout << "身長:" << c.height << "cm\n";
	cout << "体重:" << c.weight << "kg\n";

	return 0;
}
#include <iostream>
using namespace std;

// 構造体の型(struct AnthropometricData)を、新しい型名 Data1 として定義する
typedef struct AnthropometricData{
	char *name;
	int age;
	double height;
	double weight;
}Data1;

// 構造体の(元の)型名の省略
typedef struct{
	char *name;
	int age;
	double height;
	double weight;
}Data2;

int main(void){
	// 構造体変数の宣言
	Data1 a = { "日本太郎", 23, 170.5, 70.3 };    // 構造体変数の初期化
	Data1 b;
	Data2 c;

	b.name = "日本花子";
	b.age = 22;
	b.height = 160.2;
	b.weight = 45.2;

	cout << "名前:" << a.name << endl;
	cout << "年齢:" << a.age << "歳\n";
	cout << "身長:" << a.height << "cm\n";
	cout << "体重:" << a.weight << "kg\n";
	cout << '\n';

	cout << "名前:" << b.name << endl;
	cout << "年齢:" << b.age << "歳\n";
	cout << "身長:" << b.height << "cm\n";
	cout << "体重:" << b.weight << "kg\n";
	cout << '\n';

	c.name = "日本一郎";
	c.age = 22;
	c.height = 165.5;
	c.weight = 65.5;

	cout << "名前:" << c.name << endl;
	cout << "年齢:" << c.age << "歳\n";
	cout << "身長:" << c.height << "cm\n";
	cout << "体重:" << c.weight << "kg\n";
	cout << '\n';

	a = b;      // 値の代入

	cout << "名前:" << a.name << endl;
	cout << "年齢:" << a.age << "歳\n";
	cout << "身長:" << a.height << "cm\n";
	cout << "体重:" << a.weight << "kg\n";
	cout << '\n';

	cout << "名前:" << b.name << endl;
	cout << "年齢:" << b.age << "歳\n";
	cout << "身長:" << b.height << "cm\n";
	cout << "体重:" << b.weight << "kg\n";
	cout << '\n';

	return 0;
}
#include <iostream>
using namespace std;

typedef struct AnthropometricData{
	char* name;
	int age;
	double height;
	double weight;
}Data;

void display1(Data x);
void display2(Data* x);
void display3(Data& x);

int main(){
	Data a = { "日本太郎", 23, 170.5, 70.3 };

	display1(a);    // 値渡し ※メンバが多いほど処理に時間がかかる
	cout << '\n';
	display2(&a);   // 参照渡しでは、関数にアドレス値だけ渡すので、値渡しに比べて処理が速くなる場合がある
	cout << '\n';
	display3(a);    // リファレンスの利用

	return 0;
}

// 値渡し
void display1(Data x){
	cout << "名前:" << x.name << endl;
	cout << "年齢:" << x.age << "歳\n";
	cout << "身長:" << x.height << "cm\n";
	cout << "体重:" << x.weight << "kg\n";
}

// ポインタの利用
void display2(Data* x){
	// ポインタからメンバにアクセスするにはアロー演算子(->)を利用する
	cout << "名前:" << x->name << endl;
	cout << "年齢:" << x->age << "歳\n";
	cout << "身長:" << x->height << "cm\n";
	cout << "体重:" << x->weight << "kg\n";
}

// リファレンスの利用
void display3(Data& x){
	cout << "名前:" << x.name << endl;
	cout << "年齢:" << x.age << "歳\n";
	cout << "身長:" << x.height << "cm\n";
	cout << "体重:" << x.weight << "kg\n";
}

共用体 (クラスキー: union)

  • C++における共用体は、クラスの一種。
    → メンバがデフォルトで公開されるクラスとして定義される。(Cと異なる)
  • 同じデータ型、または異なるデータ型が、同一のメモリー領域を共用する。
  • 既定のアクセスは public である。
  • 共用体型の変数を宣言するときの、unionキーワードは省略可。
    ※付けても可だが、付けないのが一般的な感じ。(Cでは必須)
#include <iostream>
using namespace std;

// 共用体の型の宣言 ※typedefで新たな型名を定義するかは任意
union Identification{
	char name[6];
	int id_number;
	double password;
};

int main(){
	Identification iddata;    // 共用体Identification型の変数iddataの宣言

	iddata.name[0] = 'T';
	iddata.name[1] = 'A';
	iddata.name[2] = 'R';
	iddata.name[3] = 'O';
	iddata.name[4] = 'U';
	iddata.name[5] = '\0';
	cout << iddata.name << endl;

	iddata.id_number = 75;
	cout << iddata.id_number << endl;

	iddata.password = 35.67;
	cout << iddata.password << endl;

	// sizeof演算子による評価結果の型はsize_t型。変換仕様は%zu (CではC99からの規格対応限定になる)
	// サイズはそれぞれ 6,4,8byte ※環境依存
	cout << sizeof(char)* 6 << "," << sizeof(int) << "," << sizeof(double) << endl;
	// サイズ:8byte ※この環境では、それぞれの変数を宣言した場合18byteになる。共用体の利用により、8byteで済む
	cout << sizeof(ID) << endl;

	return 0;
}

クラス (クラスキー:class)

  • クラスとは、クラスベースのオブジェクト指向においてオブジェクトの設計図にあたるもの。
  • クラスから生成したオブジェクトのことをインスタンスという。
  • 既定のアクセスは privateである。クラスキー:classでは、アクセス指定子を省略した場合、privateメンバとなる。
    (←→ クラスキー:structでは省略した場合、publicメンバとなる)
  • カプセル化 :データとそれを操作する手続きを一体化し、オブジェクト内の仕様や構造を外部から隠蔽すること。
#include <iostream>
using namespace std;

// Shipクラスの宣言
class Ship{
private:                        // アクセス指定子private :クラスの外からはアクセスできない指定
	int ship_num;               // データメンバ
	double weight;              // データメンバ
public:                         // アクセス指定子public :クラスの外からアクセス可能な指定
	void setShip_num(int num);             // メンバ関数
	void setWeight(double wt);             // メンバ関数
	int getShip_num(){ return ship_num; }  // メンバ関数 ※インライン関数
	double getWeight(){ return weight; }   // メンバ関数 ※インライン関数
	void go(){                             // メンバ関数 ※インライン関数
		cout << "進みます" << endl;
	}
};

// Shipクラスのメンバ関数の定義
void Ship::setShip_num(int num){  // スコープ解決演算子::
	if (num >= 1){
		ship_num = num;
		cout << "適切な値" << num << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

// Shipクラスのメンバ関数の定義
void Ship::setWeight(double wt){
	if (wt >= 0){
		weight = wt;
		cout << "適切な値" << wt << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

int main(){
	Ship ship;               // Shipクラス型の変数shipの宣言 ※オブジェクト(インスタンス)の作成
	ship.setShip_num(10);
	ship.setWeight(3.5);
	cout << "船の番号は" << ship.getShip_num() << endl;
	cout << "船の排水トン数は" << ship.getWeight() << "トン" << endl;
	ship.go();

	Ship* pship;             // Shipクラスへのポインタ
	pship = new Ship;        // オブジェクトを動的に作成
	pship->setShip_num(15);
	pship->setWeight(5.2);
	cout << "船の番号は" << pship->getShip_num() << endl;
	cout << "船の排水トン数は" << pship->getWeight() << "トン" << endl;
	pship->go();
	delete pship;            // オブジェクトの破棄

	return 0;
}
#include <iostream>
using namespace std;

class Ship{
private:
	int ship_num;
	double weight;
public:
	void setShip_num(int num);
	void setWeight(double wt);
	int getShip_num(){ return ship_num; }
	double getWeight(){ return weight; }
	void go(){
		cout << "進みます" << endl;
	}
};

void Ship::setShip_num(int num){
	if (num >= 1){
		ship_num = num;
		cout << "適切な値" << num << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

void Ship::setWeight(double wt){
	if (wt >= 0){
		weight = wt;
		cout << "適切な値" << wt << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

void showShip1(Ship sh);
void showShip2(Ship* sh);
void showShip3(Ship& sh);

int main(){
	Ship ship1;
	ship1.setShip_num(100);
	ship1.setWeight(1.5);
	showShip1(ship1);          // 実引数にオブジェクト
	ship1.go();

	Ship ship2;
	ship2.setShip_num(200);
	ship2.setWeight(2.5);
	showShip2(&ship2);         // 実引数にオブジェクトのアドレス
	ship2.go();

	Ship ship3;
	ship3.setShip_num(300);
	ship3.setWeight(3.5);
	showShip3(ship3);          // 実引数にオブジェクト
	ship3.go();

	return 0;
}

void showShip1(Ship sh){       // 仮引数にオブジェクト
	cout << "船の番号は" << sh.getShip_num() << endl;
	cout << "船の排水トン数は" << sh.getWeight() << "トン" << endl;
}

void showShip2(Ship* sh){      // 仮引数にポインタ
	cout << "船の番号は" << sh->getShip_num() << endl;
	cout << "船の排水トン数は" << sh->getWeight() << "トン" << endl;
}

void showShip3(Ship& sh){      // 仮引数にリファレンス
	cout << "船の番号は" << sh.getShip_num() << endl;
	cout << "船の排水トン数は" << sh.getWeight() << "トン" << endl;
}

コンストラクタ

  • オブジェクトを生成する際に呼び出されて、内容の初期化などを行なう関数のこと。
  • 引数を指定せずに呼び出せるコンストラクタを、デフォルトコンストラクタという。
      → 例えば、全ての引数にデフォルト引数がある場合は、引数を指定せずに呼び出せるので、デフォルトコンストラクタ。
  • コンストラクタを省略した場合は、コンパイラが用意したデフォルトコンストラクタが呼び出される。
      ※ 結果論であり、デフォルトコンストラクタの定義ではないので注意。
  • 関数(コンストラクタ)名を、クラス名と同じものにする。
  • アクセス指定子を public にする。
  • 戻り値を持たない。※void型の指定もしない。
  • 引数を持つことができる(無くても可)。よって、オーバーロードによる複数定義が可能。
#include <iostream>
using namespace std;

class Ship{
private:
	int ship_num;
	double weight;
public:
	Ship();                                 // デフォルトコンストラクタ
	Ship(int n, double w);                  // コンストラクタ ※オーバーロード
	void setShip_num(int num);
	void setWeight(double wt);
	int getShip_num(){ return ship_num; }
	double getWeight(){ return weight; }
	void go(){ cout << "進みます" << endl; }
};

// デフォルトコンストラクタの定義
Ship::Ship(){                  // 関数名はクラス名と同じ。戻り値は持たない。
	ship_num = 0;
	weight = 0;
	cout << "初期値が設定されました。" << endl;
}

// ※コンストラクタのオーバーロード
// コンストラクタの定義
Ship::Ship(int n, double w){   // 関数名はクラス名と同じ。戻り値は持たない。
	ship_num = n;
	weight = w;
	cout << "初期値が設定されました。" << endl;
}

void Ship::setShip_num(int num){
	if (num >= 1){
		ship_num = num;
		cout << "適切な値" << num << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

void Ship::setWeight(double wt){
	if (wt >= 0){
		weight = wt;
		cout << "適切な値" << wt << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

int main(){
	Ship ship1;  // オブジェクト作成時に、引数が無いほうのコンストラクタ(デフォルトコンストラクタ)が呼び出される
	// Ship ship1 = Ship();  ←これでも可
	cout << "船の番号は" << ship1.getShip_num() << endl;                   // 0
	cout << "船の排水トン数は" << ship1.getWeight() << "トン" << endl;     // 0

	// ------------------------------------------------------------------------------------------
	Ship ship2(20, 50);  // オブジェクト作成時に、引数が2つあるほうのコンストラクタが呼び出される
	// Ship ship2 = Ship(20, 50);  ←これでも可
	cout << "船の番号は" << ship2.getShip_num() << endl;                   // 20
	cout << "船の排水トン数は" << ship2.getWeight() << "トン" << endl;     // 50

	// ------------------------------------------------------------------------------------------
	// それぞれ引数無し, 引数2つ, 引数無し, 引数2つのコンストラクタで初期化
	Ship ship3[4] = { Ship(), Ship(30, 60), Ship(), Ship(40, 70) };
	cout << "船の番号は" << ship3[0].getShip_num() << endl;                // 0
	cout << "船の排水トン数は" << ship3[0].getWeight() << "トン" << endl;  // 0

	cout << "船の番号は" << ship3[1].getShip_num() << endl;                // 30
	cout << "船の排水トン数は" << ship3[1].getWeight() << "トン" << endl;  // 60

	cout << "船の番号は" << ship3[2].getShip_num() << endl;                // 0
	cout << "船の排水トン数は" << ship3[2].getWeight() << "トン" << endl;  // 0

	cout << "船の番号は" << ship3[3].getShip_num() << endl;                // 40
	cout << "船の排水トン数は" << ship3[3].getWeight() << "トン" << endl;  // 70

	return 0;
}
#include <iostream>
using namespace std;

class Ship{
private:
	int ship_num;
	double weight;
public:
	Ship(int n = 10, double w = 20.5);       // コンストラクタ ※デフォルト引数あり
	void setShip_num(int num);
	void setWeight(double wt);
	int getShip_num(){ return ship_num; }
	double getWeight(){ return weight; }
	void go(){ cout << "進みます" << endl; }
};

// コンストラクタの定義
Ship::Ship(int n, double w){                 // コンストラクタ ※デフォルト引数あり
	ship_num = n;
	weight = w;
	cout << "初期値が設定されました。" << endl;
}

void Ship::setShip_num(int num){
	if (num >= 1){
		ship_num = num;
		cout << "適切な値" << num << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

void Ship::setWeight(double wt){
	if (wt >= 0){
		weight = wt;
		cout << "適切な値" << wt << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

int main(){
	Ship ship1;
	cout << "船の番号は" << ship1.getShip_num() << endl;                   // 10
	cout << "船の排水トン数は" << ship1.getWeight() << "トン" << endl;     // 20.5

	Ship ship2(30);
	cout << "船の番号は" << ship2.getShip_num() << endl;                   // 30
	cout << "船の排水トン数は" << ship2.getWeight() << "トン" << endl;     // 20.5

	Ship ship3(40, 50.5);
	cout << "船の番号は" << ship3.getShip_num() << endl;                   // 40
	cout << "船の排水トン数は" << ship3.getWeight() << "トン" << endl;     // 50.5

	return 0;
}

デストラクタ

  • オブジェクトが破棄される際に呼び出されて、終了時に必要な処理などを行なう関数のこと。
  • 関数(デストラクタ)名を、クラス名の前に~(チルダ)をつけたものにする。
  • アクセス指定子は public にする。
  • 戻り値を持たない。※void型の指定もしない。
  • 引数も持たない。→ オーバーロードによる複数定義はできない。
.

静的メンバ

  • クラスに関連づけられたメンバ。
  • オブジェクトが作成されていなくても利用できる。
  • オブジェクトに関連づけられた通常のメンバにはアクセスできない。
#include <iostream>
using namespace std;

class Ship{
private:
	int ship_num;
	double weight;
public:
	static int sum;                             // 静的データメンバ
	Ship();
	void setShip_num(int num);
	void setWeight(double wt);
	int getShip_num(){ return ship_num; }
	double getWeight(){ return weight; }
	void go(){ cout << "進みます" << endl; }
	static void showSum();                      // 静的メンバ関数
};

// 静的データメンバ
int Ship::sum = 0;

// 静的メンバ関数
void Ship::showSum(){
	cout << "船の数は" << sum << endl;
}

Ship::Ship(){
	ship_num = 0;
	weight = 0;
	cout << "初期値が設定されました。" << endl;
	sum++;                                      // 静的データメンバをインクリメント
}

void Ship::setShip_num(int num){
	if (num >= 1){
		ship_num = num;
		cout << "適切な値" << num << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

void Ship::setWeight(double wt){
	if (wt >= 0){
		weight = wt;
		cout << "適切な値" << wt << "が設定されました。" << endl;
	}
	else{
		cout << "適切な値ではありません。" << endl;
	}
}

int main(){
	// 静的メンバ関数の呼び出し
	Ship::showSum();                  // 0

	Ship ship1;  // オブジェクト作成
	Ship::showSum();                  // 1

	Ship ship2;  // オブジェクト作成
	Ship::showSum();                  // 2	

	// 静的データメンバへのアクセス
	Ship::sum = 7;
	Ship::showSum();                  // 7

	return 0;
}

クラスの派生

  • 既に定義されているクラスをもとに、拡張した新しいクラスを定義することを、"クラスの派生" という。
  • 基になるクラス(厳密には、継承関係が成り立つ場合の継承元クラス)を、"基底クラス" と呼ぶ。
    ※スーパークラス(superclass)と呼ぶ場合もあるが、C++では、基底クラス(base class)と呼ぶのが一般的。
  • 新たに定義された、拡張したクラス(厳密には、継承関係が成り立つ場合の継承先クラス)を、"派生クラス" と呼ぶ。
    ※サブクラス(subclass)と呼ぶ場合もあるが、C++では、派生クラス(derived class)と呼ぶのが一般的。
  • 拡張されたクラス(派生クラス)は、既存のクラス(基底クラス)のメンバを受け継ぐ。これを、"継承" という。
  • "派生" と "継承" は意味が異なるので注意。
.

メンバ関数のオーバーライド

  • 基底クラスで定義されたメンバを、派生クラスで再定義し、機能を上書きすること。
  • 派生クラスでは、基底クラスのメンバ関数と同じ関数名, 引数の型・数のメンバ関数を定義することができる。
.

仮想関数

  • 仮想関数は、派生クラスで再定義とするメンバ関数。
  • 基底クラスへのポインタまたはリファレンスを用いて、派生クラスのオブジェクトを参照する場合、
  • 仮想関数を呼び出して、その派生クラスのバージョンの関数を実行することができる。
.

抽象クラス

  • 純粋仮想関数(実装のない仮想関数)を1つでも含むクラスのこと。
  • そのクラス自身はオブジェクト(インスタンス)の生成ができない。
    しかし、抽象クラス型へのポインタとリファレンスは使用できる。
  • 純粋仮想関数を持つ抽象クラスを派生したクラスでは、純粋仮想関数をオーバーライド(定義・実装)する。
.

多重継承

複数の基底クラスからの派生クラスが、複数の基底クラスから継承をすることを多重継承という。

.

演算子のオーバーロード

.

.

クラスの型変換

.

.

メモリ確保・解放

.

.

テンプレートクラス

.

.

ストリーム

.

.

マニピュレータ

.

.

ファイル入出力

.

.

コマンドライン

.

.

(´・ω・`)途中・・・





コメントの投稿

非公開コメント

マイブログへようこそ♪
PLEASANT_DRAGON

2DCG&3DCG,プログラミング,
日記などを掲載中☆

(*´▽`*)コメント大歓迎です☆

最新記事
記事一覧

全ての記事を表示する

カテゴリ
SAI (0)
mi (2)
C (1)
C++ (1)
C# (0)
VBA (0)
月別アーカイブ
最新コメント
RSSリンクの表示
リンク
FC2ブログランキング

FC2Blog Ranking

ピックアップ商品1♪










カレンダー
08 | 2017/09 | 10
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
ブログ内検索フォーム
プロフィール

エクレア

Author:エクレア


  • 2DCG&3DCGの創作活動をしています。

  • SF系のメカが大好物。

アクセスカウンター
Twitter
ピックアップ商品2♪