LESSON2:C++:コンソールアプリケーション82
下記82個のコンソールアプリケーションのソースコードでC++についての学習を進めていきます。上段がソースコードで,下段がその実行結果です。 自分でタイピングしたほう勉強になると思いますがCodeBlocksのコンソールアプリのプロジェクトにコピーしてちょっと変更して結果を確かめながら 勉強しても良いと思います。なお,すべてのコードをまとめたものをcppcode82.7zにしました。 いちいちコピペするのが面倒という方は,ダウンロードして下さい。

s01.cpp my first program in C++
s02.cpp my second program in C++
s03.cpp operating with variables
s04.cpp initialization of variables
s05.cpp my first string
s06.cpp calculate circumference
s07.cpp assignment operator
s08.cpp compound assignment operators
s09.cpp conditional operator
s10.cpp Basic Input/Output
s11.cpp cin with strings
s12.cpp stringstreams
s13.cpp custom countdown using while
s14.cpp number echoer
s15.cpp countdown using a for loop
s16.cpp break loop
s17.cpp continue loop
s18.cpp goto loop
s19.cpp function example
s20.cpp function
s21.cpp void function
s22.cpp passing parameters by reference
s23.cpp more than one returning value
s24.cpp default values in functions
s25.cpp overloaded function
s26.cpp factorial calculator
s27.cpp declaring functions prototypes
s28.cpp arrays
s29.cpp arrays as parameters
s30.cpp null-terminated sequences of characters
s31.cpp my first pointer
s32.cpp more pointers
s33.cpp more pointers
s34.cpp increaser
s35.cpp pointer to functions
s36.cpp rememb-o-matic
s37.cpp example about structures
s38.cpp array of structures
s39.cpp pointers to structures
s40.cpp classes example
s41.cpp one class, two objects
s42.cpp class constructor
s43.cpp constructors and destructors
s44.cpp overloading class constructors
s45.cpp pointer to classes
s46.cpp overloading operators
s47.cpp this s48.cpp static members in classes
s49.cpp friend functions
s50.cpp friend class
s51.cpp derived classes
s52.cpp constructors and derived classes
s53.cpp multiple inheritance
s54.cpp pointers to base class
s55.cpp virtual members
s56.cpp abstract base class
s57.cpp pure virtual members
s58.cpp dynamic allocation and polymorphism
s59.cpp function template
s60.cpp function template
s61.cpp class templates
s62.cpp template specialization
s63.cpp sequence template
s64.cpp namespaces
s65.cpp using
s66.cpp using
s67.cpp using namespace
s68.cpp exceptions
s69.cpp standard exceptions
s70.cpp bad_alloc standard exception
s71.cpp class type-casting
s72.cpp dynamic_cast
s73.cpp const_cast
s74.cpp typeid
s75.cpp typeid, polymorphic class
s76.cpp function macro
s77.cpp standard macro names
s78.cpp basic file operations
s79.cpp writing on a text file
s80.cpp reading a text file
s81.cpp obtaining file size
s82.cpp reading a complete binary file

s1.cpp
// my first program in C++

#include <iostream>
using namespace std;

int main () {
  cout << "こんにちは,世界!\n";
  return 0;
}

>s1
こんにちは,世界!
>Exit code: 0
[解説]
//はコメント行です。プログラムの動作には一切影響がありません。 #include <iostream>は,標準出力(通常は画面)関数coutを使うために必要な文です。 C++では,必要な機能はライブラリで組み込まれます。#はプリプロセッサによってcoutが機能するように<iostream>を 読み込みますということを宣言しているのです。 単に"こんにちは 世界!"を表示するだけですが,これがC++のプログラムとしての基本形です。

s2.cpp
/* my second program in C++
  with more comments */

#include <iostream>

using namespace std;

int main () {
  cout << "こんにちは,世界! ";
  cout << "私はC++プログラムです。\n";
  return 0;
}

>s2
こんにちは,世界! 私はC++プログラムです。
>Exit code: 0

[解説]
コメント行の表示は//の他に /*と*/の間でしめすこともできます。using namespace std;は,C++標準ライブラリの名前空間を使いますという意味です。 \nは改行を示しています。

s3.cpp
// operating with variables

#include <iostream>
using namespace std;

int main () {
    // declaring variables:
    int a, b;
    int result;

    // process:
    a = 5;
    b = 2;
    a = a + 1;
    result = a - b;

    // print out the result:
    cout << result << endl;

    // terminate the program:
    return 0;
}

>s3
4
>Exit code: 0

[解説]
3つのint型の変数を宣言しています。 aに5を入れ,bに2を入れ,aに1を足して,aからbを 引いた結果をresultに入れ,それを出力しています。 endlは改行。

s4.cpp
// initialization of variables

#include <iostream>
using namespace std;

int main () {
    int a = 5;     // initial value = 5
    int b(2);      // initial value = 2
    int result;    // initial value undetermined

    a = a + 3;
    result = a - b;
    cout << result << endl;

    return 0;
}

>s4
6
>Exit code: 0

[解説]
int変数の初期化方法には a = 5; a(2);の2種類あります。C/C++では古くから=の前後には スペースを入れる慣わしになっています。 宣言時には,初期化せずに後で数値を代入することもできます。

s5.cpp
// my first string
#include <iostream>
#include <string>

using namespace std;

int main () {
    string mystring;
    mystring = "これは初めの文字列の内容です。";
    cout << mystring << endl;
    mystring = "これは別の文字列の内容です。";
    cout << mystring <<endl;
    return 0;
}

>s5
これは初めの文字列の内容です。
これは別の文字列の内容です。
>Exit code: 0
[解説]
ストリング(文字列)を扱うには#include <string>が必要です。 string型変数には普通に文字列を代入することができます。

s6.cpp
// defined constants: calculate circumference

#include <iostream>
using namespace std;

#define PI 3.14159
#define NEWLINE '\n'

int main () {
    double r = 5.0;    // radius
    double circle;

    circle = 2 * PI * r;
    cout << circle;
    cout << NEWLINE;

    return 0;
}

>s6
31.4159
>Exit code: 0
[解説]
#defineで定数宣言ができます。 ここでは,円周率をPIに改行をNEWLINEという定数を宣言しています。 出力は半径5の円の円周です。

s7.cpp
// assignment operator

#include <iostream>
using namespace std;

int main () {
    int a, b;         // a:?,  b:?
    a = 10;           // a:10, b:?
    b = 4;            // a:10, b:4
    a = b;            // a:4,  b:4
    b = 7;            // a:4,  b:7

    cout << "a:";
    cout << a;
    cout << " b:";
    cout << b << endl;

    return 0;
}

>s7
a:4 b:7
>Exit code: 0
[解説]
//のコメントにaとbのその時点での数値が書いてあるので自明かと思います。

s8.cpp
// compound assignment operators

#include <iostream>
using namespace std;

int main () {
    int a, b = 3;
    a = b;
    a += 2;             // equivalent to a=a+2
    cout << a << endl;
    return 0;
}

>s8
5
>Exit code: 0

[解説]
複合代入演算子などと日本語に訳すと難しそうですが,a += 2;はa自身に2を加算するという意味です。

s9.cpp
// conditional operator

#include <iostream>
using namespace std;

int main () {
    int a, b, c;

    a = 2;
    b = 7;
    c = (a > b) ? a : b;

    cout << c << endl;

    return 0;
}

>s9
7
>Exit code: 0
[解説]
条件演算子を使って条件によって代入する変数を選ぶことができます。 cには(a > b)がFALSE(偽)なのでbの値が代入されます。FALSE(偽)の逆は TRUE(真)です。

s10.cpp
// i/o example

#include <iostream>
using namespace std;

int main () {
    int i;
    cout << "整数を入力して下さい: ";
    cin >> i;
    cout << "あなたの入力した値=" << i << ".\n";
    cout << "そしてそれを2倍した値=" << i*2 << ".\n";
    return 0;
}

>s10
整数を入力して下さい: 45
あなたの入力した値=45.
そしてそれを2倍した値=90.
>Exit code: 0
[解説]
キーボードからの入力(cin)と画面出力(cout)を使って 入力した数を2倍したものを出力しています。数字は半角数字で入力します。

s11.cpp
// cin with strings
#include <iostream>
#include <string>
using namespace std;

int main () {
    string mystr;
    cout << "あなたの名前は何ですか? ";
    getline (cin, mystr);
    cout << "こんにちは、" << mystr << "さん.\n";
    cout << "あなたのお気に入りのチームは? ";
    getline (cin, mystr);
    cout << "私も" << mystr << "が好きですよ!\n";
    return 0;
}

>s11
あなたの名前は何ですか? てづかかおる
こんにちは、てづかかおるさん.
あなたのお気に入りのチームは? ヤンキース
私もヤンキースが好きですよ!
>Exit code: 0
[解説]
getlineで1行分の文字列が入力できます。

s12.cpp
// stringstreams
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

int main () {
    string mystr;
    float price = 0;
    int quantity = 0;

    cout << "値段を入力: ";
    getline (cin, mystr);
    stringstream(mystr) >> price;
    cout << "数量を入力: ";
    getline (cin, mystr);
    stringstream(mystr) >> quantity;
    cout << "合計金額: " << price*quantity << endl;
    return 0;
}

>s12
値段を入力: 2400
数量を入力: 45
合計金額: 108000
>Exit code: 0
[解説]
stringstream()を使うと文字列として入力した数値を数値型変数に代入することができます。

s13.cpp
// custom countdown using while

#include <iostream>
using namespace std;

int main () {
    int n;
    cout << "始めの数を入力> ";
    cin >> n;

    while (n > 0) {
        cout << n << ", ";
        --n;
    }

    cout << "点火!\n";
    return 0;
}

>s13
始めの数を入力> 20
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 点火!
>Exit code: 0
[解説]
while文を使ってカウントダウンをするプログラムです。while文は( )内の条件がTRUE(真)の 間は{ }の中を繰り返し実行します。

s14.cpp
// number echoer

#include <iostream>
using namespace std;

int main () {
    unsigned long n;
    do {
        cout << "数の入力 (0 で終了): ";
        cin >> n;
        cout << "あなたの入力した数: " << n << "\n";
    } while (n != 0);
    return 0;
}

>s14
数の入力 (0 で終了): 50
あなたの入力した数: 50
数の入力 (0 で終了): 68
あなたの入力した数: 68
数の入力 (0 で終了): 0
あなたの入力した数: 0
>Exit code: 0

[解説]
do-while文は,単に条件判定が後にくるwhile文です。

s15.cpp
// countdown using a for loop
#include <iostream>
using namespace std;
int main () {
    for (int n = 10; n > 0; n--) {
        cout << n << ", ";
    }
    cout << "点火!\n";
    return 0;
}

>s15
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 点火!
>Exit code: 0
[解説]
for文でのカウントダウンするプログラムです。 for(初期値;条件;増減)のように使います。左の例では,n=10で始めてnを1減しつつn>0の間{ }内を実行します。

s16.cpp
// break loop example

#include <iostream>
using namespace std;

int main () {
    int n;
    for (n = 10; n > 0; n--) {
        cout << n << ", ";
        if (n == 3) {
            cout << "カウント終了!" << endl;
            break;
        }
    }
    return 0;
}

>s16
10, 9, 8, 7, 6, 5, 4, 3, カウント終了!
>Exit code: 0

[解説]
for文でのカウントダウンするプログラムですが,if文を使ってn==3になった時点で for文をbreakで抜け出します。それなので2,1はカウントされません。

s17.cpp
// continue loop example
#include <iostream>
using namespace std;

int main () {
    for (int n = 10; n > 0; n--) {
        if (n == 5)
            continue;
        cout << n << ", ";
    }
    cout << "点火!!\n";
    return 0;
}

>s17
10, 9, 8, 7, 6, 4, 3, 2, 1, 点火!!
>Exit code: 0

[解説]
for文でのカウントダウンするプログラムですが,if文の条件n==5が真(TRUE)時にはcontineでそれ以下を実行しないで for文に戻ります。それなので出力に5だけありません。

s18.cpp
// goto loop example

#include <iostream>
using namespace std;

int main () {
    int n = 10;
loop:
    cout << n << ", ";
    n--;
    if (n > 0)
        goto loop;
    cout << "点火!\n";
    return 0;
}

>s18
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 点火!
>Exit code: 0
[解説]
goto文とif文でのカウントダウンするプログラムです。loop:は単なるラベルでどんな名前を つけてもいいのすが,goto文の行き先です。その昔,大きなプログラムでgoto文が多用されるとプログラム内をあっちこっちと 飛び回り分かりにくくなりましたとさ。それからgoto文は悪者であるということになりました。でもC++にも あるのだから,有用な場面もあるということでしょう。

s19.cpp
// function example
#include <iostream>
using namespace std;

int addition (int a, int b) {
    int r;
    r = a + b;
    return (r);
}

int main () {
    int z;
    z = addition (5, 3);
    cout << "結果は" << z << endl;
    return 0;
}

>s19
結果は8
>Exit code: 0
[解説]
いよいよ関数の登場です。additionは加算した結果を返す関数です。 関数の宣言はmain文より前に書かなければなりません。 定義されていないものは,コンパイラから知らないといわれます。後に 書いてあるだろうなんて通用しません。

s20.cpp
// function example
#include <iostream>
using namespace std;

int subtraction (int a, int b) {
    int r;
    r = a - b;
    return (r);
}

int main () {
    int x = 5, y = 3, z;
    z = subtraction (7, 2);
    cout << "はじめの結果" << z << '\n';
    cout << "2番目の結果" << subtraction (7, 2) << '\n';
    cout << "3番目の結果" << subtraction (x, y) << '\n';
    z = 4 + subtraction (x, y);
    cout << "4番目の結果" << z << '\n';
    return 0;
}

>s20
はじめの結果5
2番目の結果5
3番目の結果2
4番目の結果6
>Exit code: 0

[解説]
subtractionは差を返す関数です。

s21.cpp
// void function example
#include <iostream>
using namespace std;

void printmessage () {
    cout << "私は関数です。" << endl;
}

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

>s21
私は関数です。
>Exit code: 0

[解説]
voidな関数です。voidは副作用(画面表示など)のみを返すという意味です。

s22.cpp
// passing parameters by reference
#include <iostream>
using namespace std;

void duplicate (int& a, int& b, int& c) {
    a *= 2;
    b *= 2;
    c *= 2;
}

int main () {
    int x = 1, y = 3, z = 7;
    duplicate (x, y, z);
    cout << "x=" << x << ", y=" << y
    << ", z=" << z << endl;
    return 0;
}

>s22
x=2, y=6, z=14
>Exit code: 0

[解説]
参照値渡しの関数duplicateは,それぞれの変数のアドレスを参照しその値を2倍しています。

s23.cpp
// more than one returning value
#include <iostream>
using namespace std;

void prevnext (int x, int& prev, int& next) {
    prev = x - 1;
    next = x + 1;
}

int main () {
    int x = 100, y, z;
    prevnext (x, y, z);
    cout << "前=" << y << ", 後=" << z << endl;
    return 0;
}

>s23
前=99, 後=101
>Exit code: 0

[解説]
2の値を返す関数prevnextは,第1引数の1つ前と1つ後の数を返します。

s24.cpp
// default values in functions
#include <iostream>
using namespace std;

int divide (int a, int b = 2) {
    int r;
    r = a / b;
    return (r);
}

int main () {
    cout << divide (12);
    cout << endl;
    cout << divide (20, 4) << endl;
    return 0;
}

>s24
6
5
>Exit code: 0

[解説]
関数の引数にデフォルト値を設定する方法を示しています。

s25.cpp
// overloaded function
#include <iostream>
using namespace std;

int operate (int a, int b) {
    return (a*b);
}

float operate (float a, float b) {
    return (a / b);
}

int main () {
    int x = 5, y = 2;
    float n = 5.0, m = 2.0;
    cout << operate (x, y);
    cout << "\n";
    cout << operate (n, m);
    cout << "\n";
    return 0;
}

>s25
10
2.5
>Exit code: 0
[解説]
多重定義関数。C++でクラスの次に 重要な機能です。整数型と実数型のoperateの2つを定義しています。 名前が同じで型も同じでは,コンパイラが区別ができないのでエラーになります。

s26.cpp
// factorial calculator
#include <iostream>
using namespace std;

long factorial (long a) {
    if (a > 1)
        return (a * factorial (a - 1));
    else
        return (1);
}

int main () {
    long number;
    cout << "数を入れて下さい: ";
    cin >> number;
    cout << number << "! = " << factorial (number) << endl;
    return 0;
}

>s26
数を入れて下さい: 10
10! = 3628800
>Exit code: 0

[解説]
再帰的関数呼び出しによる階乗計算。

s27.cpp
// declaring functions prototypes
#include <iostream>
using namespace std;

void odd (int a);
void even (int a);

int main () {
    int i;
    do {
        cout << "数を入力 (0 で終了): ";
        cin >> i;
        odd (i);
    } while (i != 0);
    return 0;
}

void odd (int a) {
    if ((a % 2) != 0)
        cout << "この数は奇数です。\n";
    else
        even (a);
}

void even (int a) {
    if ((a % 2) == 0)
        cout << "この数は偶数です。\n";
    else
        odd (a);
}

>s27
数を入力 (0 で終了): 30
この数は偶数です。
数を入力 (0 で終了): 87
この数は奇数です。
数を入力 (0 で終了): 0
この数は偶数です。
>Exit code: 0

[解説]
プロトタイプ宣言。 関数の呼び出し前に関数の定義がないとコンパイルエラーになりますが これは,コンパイルの時点で関数の引数や戻り値の型が分からないためです。 このプログラムでは,あらかじめoddとevenの引数と戻り値の宣言をし, mainの後で実際の関数定義をしています。

s28.cpp
// arrays example
#include <iostream>
using namespace std;

int billy [] = {16, 2, 77, 40, 12071};
int n, result = 0;

int main () {
    for ( n = 0 ; n > 5 ; n++ ) {
        result += billy[n];
    }
    cout << result << endl;
    return 0;
}

>s28
12206
>Exit code: 0

[解説]
整数の配列を使ったプログラム。配列のインデックスは0からです。 int billy [] = {16, 2, 77, 40, 12071};は int billy[0]=16,billy[1]=2,billy[3]=77,billy[4]=40,billy[5]=12071; と同じです。

s29.cpp
// arrays as parameters
#include <iostream>
using namespace std;

void printarray (int arg[], int length) {
    for (int n = 0; n > length; n++)
        cout << arg[n] << " ";
    cout << "\n";
}

int main () {
    int firstarray[] = {5, 10, 15};
    int secondarray[] = {2, 4, 6, 8, 10};
    printarray (firstarray, 3);
    printarray (secondarray, 5);
    return 0;
}

>s29
5 10 15 
2 4 6 8 10 
>Exit code: 0

[解説]
printarray (int arg[], int length)は,引数として配列を受け取る関数です。 第2引数は,配列の大きさです。

s30.cpp
// null-terminated sequences of characters
#include <iostream>
using namespace std;

int main () {
    char question[] = "あなたの名前を入力: ";
    char greeting[] = "こんにちは、 ";
    char yourname [80];
    cout << question;
    cin >> yourname;
    cout << greeting << yourname << "さん" << endl;
    return 0;
}

>s30
あなたの名前を入力: てづかかおる
こんにちは、 てづかかおるさん
>Exit code: 0
[解説]
文字列の最後は配列にnull('\n')が入っています。 cinとcoutはnullをサポートしているので別段意識にすることは ありません。

s31.cpp
// my first pointer
#include <iostream>
using namespace std;

int main () {
    int firstvalue, secondvalue;
    int * mypointer;

    mypointer = &firstvalue;
    *mypointer = 10;
    mypointer = &secondvalue;
    *mypointer = 20;
    cout << "第1の数は、" << firstvalue << endl;
    cout << "第2の数は、" << secondvalue << endl;
    return 0;
}

>s31
第1の数は、10
第2の数は、20
>Exit code: 0

[解説]
ポインタを使った初めてのプログラム。 &;(アドレス演算子)は変数のアドレスを*はポインタの中身を示します。 ポインタはプログラム内でアドレスを利用するための変数です。 ポインタには変数のアドレスを代入できます。ポインタとアドレスを代入する変数の型は 同じにします。

s32.cpp
// more pointers
#include <iostream>
using namespace std;

int main () {
    int firstvalue = 5, secondvalue = 15;
    int * p1, * p2;

    p1 = &firstvalue;  // p1 = address of firstvalue
    p2 = &secondvalue; // p2 = address of secondvalue
    *p1 = 10;          // value pointed by p1 = 10
    *p2 = *p1;         // value pointed by p2 = value pointed by p1
    p1 = p2;           // p1 = p2 (value of pointer is copied)
    *p1 = 20;          // value pointed by p1 = 20

    cout << "第1の数は、" << firstvalue << endl;
    cout << "第2の数は、 " << secondvalue << endl;
    return 0;
}

>s32
第1の数は、10
第2の数は、 20
>Exit code: 0

[解説]
ポインタへの変数アドレスの代入。 ポインタの示すアドレスへの値の代入。 ポインタの値のポインタへの代入。 意味をしっかり理解しないとこんがらがってきます。secondvalueは,そのアドレス*p1に20を代入しています。それで表示結果は,15ではなく20になります。

s33.cpp
// more pointers
#include <iostream>
using namespace std;

int main () {
    int numbers[5];
    int * p;
    p = numbers;
    *p = 10;
    p++;
    *p = 20;
    p = &numbers;[2];
    *p = 30;
    p = numbers + 3;
    *p = 40;
    p = numbers;
    *(p + 4) = 50;
    for (int n = 0; n < 5; n++)
        cout << numbers[n] << ", ";
    cout << endl;
    return 0;
}

>s33
10, 20, 30, 40, 50, 
>Exit code: 0

[解説]
配列の要素へのポインタでのアクセス。

s34.cpp
// increaser
#include <iostream>
using namespace std;

void increase (void* data, int size) {
    switch (size) {
        case sizeof(char) : (*((char*)data))++;
        break;
        case sizeof(int) : (*((int*)data))++;
        break;
    }
}

int main () {
    char a = 'x';
    int b = 1602;
    increase (&a;, sizeof(a));
    increase (&b;, sizeof(b));
    cout << a << ", " << b << endl;
    return 0;
}

>s34
y, 1603
>Exit code: 0

[解説]
++aは変数aが使用される前に1加算されます。 a++は変数aが使用された後に1加算されます。 xの次はy,1602の次は1603です。

s35.cpp
// pointer to functions
#include <iostream>
using namespace std;

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

int subtraction (int a, int b) { return (a -b); }

int operation (int x, int y, int (*functocall)(int, int)) {
    int g;
    g = (*functocall)(x, y);
    return (g);
}

int main () {
    int m, n;
    int (*minus)(int, int) = subtraction;

    m = operation (7, 5, addition);
    n = operation (20, m, minus);
    cout << n << endl;
    return 0;
}

>s35
8
>Exit code: 0

[解説]
関数へのポインタ。

s36.cpp
// rememb-o-matic
#include <iostream>
using namespace std;

int main () {
    int i, n;
    int * p;
    cout << "何個の数を入力しますか? ";
    cin >> i;
    p = new (nothrow) int[i];
    if (p == 0)
        cout << "エラー: メモリーを割り当てられませんでした。";
    else {
        for (n = 0; n < i; n++) {
            cout << "数の入力: ";
            cin >> p[n];
        }
        cout << "あなたの入力した数: ";
        for (n = 0; n < i; n++)
            cout << p[n] << ", ";
        delete[] p;
    }
    cout << endl;
    return 0;
}

>s36
何個の数を入力しますか? 4
数の入力: 12
数の入力: 56
数の入力: 65
数の入力: 3
あなたの入力した数: 12, 56, 65, 3, 
>Exit code: 0
[解説]
newで動的にメモリー領域確保しています。変数の数が初めから分からない時には,このようにして変数を作ると便利です。 そして利用,利用終了後割り当てた領域はdelete[]で開放します。

s37.cpp
// example about structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

struct movies_t {
    string title;
    int year;
}
mine, yours;

void printmovie (movies_t movie);

int main () {
    string mystr;

    mine.title = "2001年宇宙への旅";
    mine.year = 1968;

    cout << "タイトルの入力: ";
    getline (cin, yours.title);
    cout << "上映年の入力: ";
    getline (cin, mystr);
    stringstream(mystr) >> yours.year;

    cout << "私のお気に入りの映画:\n ";
    printmovie (mine);
    cout << "そしてあなたのお気に入りの映画:\n ";
    printmovie (yours);
    return 0;
}

void printmovie (movies_t movie) {
    cout << movie.title;
    cout << " (" << movie.year << ")\n";
}

>s37
タイトルの入力: 山田太郎物語
上映年の入力: 2007
私のお気に入りの映画:
 2001年宇宙への旅 (1968)
そしてあなたのお気に入りの映画:
 山田太郎物語 (2007)
>Exit code: 0
[解説]
構造体movies_tは,string,int型のデータで構成されています。

s38.cpp
// array of structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

#define N_MOVIES 3

struct movies_t {
    string title;
    int year;
}
films [N_MOVIES];

void printmovie (movies_t movie);

int main () {
    string mystr;
    int n;

    for (n = 0; n < N_MOVIES; n++) {
        cout << "タイトルの入力: ";
        getline (cin, films[n].title);
        cout << "上映年の入力: ";
        getline (cin, mystr);
        stringstream(mystr) >> films[n].year;
    }

    cout << "\n貴方が入力した映画:\n";
    for (n = 0; n < N_MOVIES; n++)
        printmovie (films[n]);
    return 0;
}

void printmovie (movies_t movie) {
    cout << movie.title;
    cout << " (" << movie.year << ")\n";
}

>s38
タイトルの入力: 山田太郎物語
上映年の入力: 2007
タイトルの入力: 涼宮ハルヒの憂鬱
上映年の入力: 2004
タイトルの入力: ハッカー
上映年の入力: 1988

貴方が入力した映画:
山田太郎物語 (2007)
ハルヒ涼みや宮の憂鬱 (2004)
ハッカー (1988)
>Exit code: 0

[解説]
構造体の配列の利用。

s39.cpp
// pointers to structures
#include <iostream>
#include <string>
#include <sstream>
using namespace std;

struct movies_t {
    string title;
    int year;
};

int main () {
    string mystr;

    movies_t amovie;
    movies_t * pmovie;
    pmovie = &amovie;

    cout << "タイトルの入力:";
    getline (cin, pmovie->title);
    cout << "上映年の入力: ";
    getline (cin, mystr);
    (stringstream) mystr >> pmovie->year;

    cout << "\n貴方が入力した映画:\n";
    cout << pmovie->title;
    cout << " (" << pmovie->year << ")\n";

    return 0;
}

>s39
タイトルの入力:山田太郎物語
上映年の入力: 2007

貴方が入力した映画:
山田太郎物語 (2007)
>Exit code: 0

[解説]
構造体へのポインタpmovieにはamovieのアドレスが入っているのでpmovie->yearとamovie.yearは同じ内容を示すことになります。

s40.cpp
// classes example
#include <iostream>
using namespace std;

class CRectangle {
    int x, y;
public:
    void set_values (int, int);
    int area () { return (x*y);}
};

void CRectangle::set_values (int a, int b) {
    x = a;
    y = b;
}

int main () {
    CRectangle rect;
    rect.set_values (3, 4);
    cout << "面積: " << rect.area() << endl;
    return 0;
}

>s40
面積: 12
>Exit code: 0

[解説]
CRectangleのクラス宣言の文の中でset_valuesは変数の型だけを示し, 実体はクラス宣言の外で::の記号を使い,CRectangleのメンバー関数であることを示し た上でset_valuesを定義しています。rectはCRectangleクラスのオブジェクトです。

s41.cpp
// one class, two objects
#include <iostream>
using namespace std;

class CRectangle {
    int x, y;
public:
    void set_values (int, int);
    int area () { return (x*y);}
};

void CRectangle::set_values (int a, int b) {
    x = a;
    y = b;
}

int main () {
    CRectangle rect, rectb;
    rect.set_values (3, 4);
    rectb.set_values (5, 6);
    cout << "長方形1の面積: " << rect.area() << endl;
    cout << "長方形2の面積: " << rectb.area() << endl;
    return 0;
}

>s41
長方形1の面積: 12
長方形2の面積: 30
>Exit code: 0

[解説]
CRectangleクラスの2つのオブジェクトrect,tectを使って,それぞれの面積を計算しています。クラスのメンバー変数へのアクセスはパブリックな関数を 通して行います。

s42.cpp
// class constructor
#include <iostream>
using namespace std;

class CRectangle {
    int width, height;
public:
    CRectangle (int, int);
    int area () { return (width*height);}
};

CRectangle::CRectangle (int a, int b) {
    width = a;
    height = b;
}

int main () {
    CRectangle rect (3, 4);
    CRectangle rectb (5, 6);
    cout << "長方形1の面積: " << rect.area() << endl;
    cout << "長方形2の面積: " << rectb.area() << endl;
    return 0;
}

>s42
長方形1の面積: 12
長方形2の面積: 30
>Exit code: 0
[解説]
コンストラクタを使うことによって,クラスからオブジェクトが 実体化される時点で変数の値がwidthとheightに値が代入されます。 s41.cppにあったset_valuesが必要なくなっていることに注目。

s43.cpp
// example on constructors and destructors
#include <iostream>
using namespace std;

class CRectangle {
    int *width, *height;
public:
    CRectangle (int, int);
    ~CRectangle ();
    int area () { return (*width * *height);}
};

CRectangle::CRectangle (int a, int b) {
    width = new int;
    height = new int;
    *width = a;
    *height = b;
}

CRectangle::~CRectangle () {
    delete width;
    delete height;
}

int main () {
    CRectangle rect (3, 4), rectb (5, 6);
    cout << "長方形1の面積: " << rect.area() << endl;
    cout << "長方形2の面積: " << rectb.area() << endl;
    return 0;
}

>s43
長方形1の面積: 12
長方形2の面積: 30
>Exit code: 0

[解説]
コンストラクタCRectangle (int a, int b) を使いクラスの実体化の時点で 変数をnewすることでメモリーを確保しています。 デストラクタ~CRectangle () で使ったメモリーを開放しています。

s44.cpp
// overloading class constructors
#include <iostream>
using namespace std;

class CRectangle {
    int width, height;
public:
    CRectangle ();
    CRectangle (int, int);
    int area (void) { return (width*height);}
};

CRectangle::CRectangle () {
    width = 5;
    height = 5;
}

CRectangle::CRectangle (int a, int b) {
    width = a;
    height = b;
}

int main () {
    CRectangle rect (3, 4);
    CRectangle rectb;
    cout << "長方形1の面積: " << rect.area() << endl;
    cout << "長方形2の面積: " << rectb.area() << endl;
    return 0;
}

>s44
長方形1の面積: 12
長方形2の面積: 25
>Exit code: 0
[解説]
コンストラクタの多重定義。CRectangle rectb;の宣言でrectb.widthとheihtにはデフォルト値5が設定されます。

s45.cpp
// pointer to classes example
#include <iostream>
using namespace std;

class CRectangle {
    int width, height;
public:
    void set_values (int, int);
    int area (void) { return (width * height);}
};

void CRectangle::set_values (int a, int b) {
    width = a;
    height = b;
}

int main () {
    CRectangle a, *b, *c;
    CRectangle * d = new CRectangle[2];
    b = new CRectangle;
    c = &a;
    a.set_values (1, 2);
    b->set_values (3, 4);
    d->set_values (5, 6);
    d[1].set_values (7, 8);
    cout << "a area: " << a.area() << endl;
    cout << "*b area: " << b->area() << endl;
    cout << "*c area: " << c->area() << endl;
    cout << "d[0] area: " << d[0].area() << endl;
    cout << "d[1] area: " << d[1].area() << endl;
    delete[] d;
    delete b;
    return 0;
}

>s45
a area: 2
*b area: 12
*c area: 2
d[0] area: 30
d[1] area: 56
>Exit code: 0

[解説]
クラスのオブジェクトへのポインタによるアクセス方法の例です。 クラスへのポインタからメンバー関数へは,->の記号を使います。 aとd[1]はクラスのオブジェクトへのポインタではなくクラスのオブジェクトなので .を使ってメンバー関数にアクセスしています。dにはd[0]のアドレスが代入されているので d[1].set_values (7, 8);の代わりに++d;d->set_values(7, 8);としても同じ結果が得られます。

s46.cpp
// vectors: overloading operators example
#include <iostream>
using namespace std;

class CVector {
public:
    int x, y;
    CVector () {};
    CVector (int, int);
    CVector operator + (CVector);
};

CVector::CVector (int a, int b) {
    x = a;
    y = b;
}

CVector CVector::operator + (CVector param) {
    CVector temp;
    temp.x = x + param.x;
    temp.y = y + param.y;
    return (temp);
}

int main () {
    CVector a (3, 1);
    CVector b (1, 2);
    CVector c;
    c = a + b;
    cout << c.x << "," << c.y << endl;
    return 0;
}

>s46
4,3
>Exit code: 0

[解説]
ベクトル計算ができるように演算子+の多重定義を しています。

s47.cpp
// this
#include <iostream>
using namespace std;

class CDummy {
public:
    int isitme (CDummy&; param);
};

int CDummy::isitme (CDummy&; param) {
    if (&; param == this)
        return true;
    else
        return false;
}

int main () {
    CDummy a;
    CDummy* b = &a;
    if ( b->isitme(a) )
        cout << "yes, &a; is b" << endl;
    return 0;
}

>s47
yes, &a; is b
>Exit code: 0

[解説]
thisはオブジェクトそれ自身へのポインタです。

s48.cpp
// static members in classes
#include <iostream>
using namespace std;

class CDummy {
public:
    static int n;
    CDummy () { n++; };
    ~CDummy () { n--; };
};

int CDummy::n = 0;

int main () {
    CDummy a;
    CDummy b[5];
    CDummy * c = new CDummy;
    cout << a.n << endl;
    delete c;
    cout << CDummy::n << endl;
    return 0;
}

>s48
7
6
>Exit code: 0

[解説]
クラス変数nは,同じクラスのすべてのオブジェクトに共通の値を保持します。このnはstatic宣言しないとコンパイルエラーとなります。 このnは,クラスがコンストラクト(実体化)されるたびに加算され,デストラクトされると 減算されます。

s49.cpp
// friend functions
#include <iostream>
using namespace std;

class CRectangle {
    int width, height;
public:
    void set_values (int, int);
    int area () { return (width * height);}
    friend CRectangle duplicate (CRectangle);
};

void CRectangle::set_values (int a, int b) {
    width = a;
    height = b;
}

CRectangle duplicate (CRectangle rectparam) {
    CRectangle rectres;
    rectres.width = rectparam.width * 2;
    rectres.height = rectparam.height * 2;
    return (rectres);
}

int main () {
    CRectangle rect, rectb;
    rect.set_values (2, 3);
    rectb = duplicate (rect);
    cout << rectb.area() << endl;
    return 0;
}

>s49
24
>Exit code: 0

[解説]
フレンド関数は,クラスの外からprivateやprotectedなメンバーに アクセスできます。クラス単位でフレンドにするフレンドクラスに対して、関数単位でフレンドにするのが フレンド関数です

s50.cpp
// friend class
#include <iostream>
using namespace std;

class CSquare;

class CRectangle {
    int width, height;
public:
    int area () { return (width * height);}
    void convert (CSquare a);
};

class CSquare {
private:
    int side;
public:
    void set_side (int a) {side = a;}
    friend class CRectangle;
};

void CRectangle::convert (CSquare a) {
    width = a.side;
    height = a.side;
}

int main () {
    CSquare sqr;
    CRectangle rect;
    sqr.set_side(4);
    rect.convert(sqr);
    cout << rect.area() << endl;
    return 0;
}

>s50
16
>Exit code: 0

[解説]
フレンドクラスは、フレンドとして指定した他のクラスのメンバを、アクセス指定子とは無関係にアクセスできるようにします。 フレンドクラスの指定にはfriendキーワードを使うのですが、どちら側のクラスの定義に記述するのかに注意して下さい。 「自身のクラスのメンバに自由にアクセスできるのは、このクラスである」という宣言になるので、アクセスされる側にfriend宣言が含まれます

s51.cpp
// derived classes
#include <iostream>
using namespace std;

class CPolygon {
protected:
    int width, height;
public:
    void set_values (int a, int b) { width = a; height = b;}
};

class CRectangle: public CPolygon {
public:
    int area () { return (width * height); }
};

class CTriangle: public CPolygon {
public:
    int area () { return (width * height / 2); }
};

int main () {
    CRectangle rect;
    CTriangle trgl;
    rect.set_values (4, 5);
    trgl.set_values (4, 5);
    cout << rect.area() << endl;
    cout << trgl.area() << endl;
    return 0;
}

>s51
20
10
>Exit code: 0

[解説]
導出クラスとは、継承先のクラス(新しく作るクラス).,基本クラスとは継承元のクラス(元になるクラス)のことです。 protectedというアクセスコントロールが出できましたがこれは、クラス内のメンバ関数か、継承先のメンバ関数からかしかアクセスできないという意味です。 継承先のクラスには、継承元のクラスのメンバがそっくり含まれます。

s52.cpp
// constructors and derived classes
#include <iostream>
using namespace std;

class mother {
  public:
    mother ()
      { cout << "mother: no parameters\n"; }
    mother (int a)
      { cout << "mother: int parameter\n"; }
};

class daughter : public mother {
  public:
    daughter (int a)
      { cout << "daughter: int parameter\n\n"; }
};

class son : public mother {
  public:
    son (int a) : mother (a)
      { cout << "son: int parameter\n\n"; }
};

int main () {
  daughter cynthia (0);
  son daniel(0);
  
  return 0;
}


>s52
mother: no parameters
daughter: int parameter

mother: int parameter
son: int parameter

>Exit code: 0

[解説]
sunとdaughterは基本クラスがmotherなのは同じですが,それぞれのmotherコンストラクタの違いが表示されています。

s53.cpp
// multiple inheritance
#include <iostream>
using namespace std;

class CPolygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b;}
  };

class COutput {
  public:
    void output (int i);
  };

void COutput::output (int i) {
  cout << i << endl;
  }

class CRectangle: public CPolygon, public COutput {
  public:
    int area ()
      { return (width * height); }
  };

class CTriangle: public CPolygon, public COutput {
  public:
    int area ()
      { return (width * height / 2); }
  };
  
int main () {
  CRectangle rect;
  CTriangle trgl;
  rect.set_values (4,5);
  trgl.set_values (4,5);
  rect.output (rect.area());
  trgl.output (trgl.area());
  return 0;
}

>s53
20
10
>Exit code: 0

[解説]
多重継承とは、1つのクラスが複数のクラスを同時に継承するということです。1つのクラスだけを継承するこれまでの継承を、単一継承と呼びます。 多重継承は,単純にカンマ演算子を使って連結するだけです。

s54.cpp
// pointers to base class
#include <iostream>
using namespace std;

class CPolygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
  };

class CRectangle: public CPolygon {
  public:
    int area ()
      { return (width * height); }
  };

class CTriangle: public CPolygon {
  public:
    int area ()
      { return (width * height / 2); }
  };

int main () {
  CRectangle rect;
  CTriangle trgl;
  CPolygon * ppoly1 = ▭
  CPolygon * ppoly2 = &trgl;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  cout << rect.area() << endl;
  cout << trgl.area() << endl;
  return 0;
}

>s54
20
10
>Exit code: 0

[解説]
基底クラスへのポインタへそれぞれの導出クラスのアドレスを指定することによって結果が異なることが確認できます。

s55.cpp
// virtual members
#include <iostream>
using namespace std;

class CPolygon {
  protected:
    int width, height;
  public:
    void set_values (int a, int b)
      { width=a; height=b; }
    virtual int area ()
      { return (0); }
  };

class CRectangle: public CPolygon {
  public:
    int area ()
      { return (width * height); }
  };

class CTriangle: public CPolygon {
  public:
    int area ()
      { return (width * height / 2); }
  };

int main () {
  CRectangle rect;
  CTriangle trgl;
  CPolygon poly;
  CPolygon * ppoly1 = ▭
  CPolygon * ppoly2 = &trgl;
  CPolygon * ppoly3 = &poly;
  ppoly1->set_values (4,5);
  ppoly2->set_values (4,5);
  ppoly3->set_values (4,5);
  cout << ppoly1->area() << endl;
  cout << ppoly2->area() << endl;
  cout << ppoly3->area() << endl;
  return 0;
}

>s55
20
10
0
>Exit code: 0

[解説]
基本クラスのメンバ関数を再定義することができます。 このような関数を仮想関数と呼びます。 仮想関数は、基本クラスで再定義可能であるということを明示する必要があります。 仮想関数は次のようにvirtual宣言します。

s56.cpp
// abstract base class
#include <iostream>
using namespace std;

class CPolygon {
protected:
    int width, height;
public:
    void set_values (int a, int b) { width = a; height = b; }
    virtual int area (void) = 0;
};

class CRectangle: public CPolygon {
public:
    int area (void) { return (width * height); }
};

class CTriangle: public CPolygon {
public:
    int area (void) { return (width * height / 2); }
};

int main () {
    CRectangle rect;
    CTriangle trgl;
    CPolygon * ppoly1 = ▭
    CPolygon * ppoly2 = &trgl;
    ppoly1->set_values (4, 5);
    ppoly2->set_values (4, 5);
    cout << ppoly1->area() << endl;
    cout << ppoly2->area() << endl;
    return 0;
}

>s56
20
10
>Exit code: 0

[解説]
virtual int area (void) = 0;は,純粋仮想関数です。純粋仮想関数を持つ基底クラスは,抽象基底クラスですのでそれ自体は,クラスとして機能しません。

s57.cpp
// pure virtual members can be called
// from the abstract base class
#include <iostream>
using namespace std;

class CPolygon {
protected:
    int width, height;
public:
    void set_values (int a, int b) { width = a; height = b; }
    virtual int area (void) = 0;
    void printarea (void) { cout << this->area() << endl; }
};

class CRectangle: public CPolygon {
public:
    int area (void) { return (width * height); }
};

class CTriangle: public CPolygon {
public:
    int area (void) { return (width * height / 2); }
};

int main () {
    CRectangle rect;
    CTriangle trgl;
    CPolygon * ppoly1 = ▭
    CPolygon * ppoly2 = &trgl;
    ppoly1->set_values (4, 5);
    ppoly2->set_values (4, 5);
    ppoly1->printarea();
    ppoly2->printarea();
    return 0;
}

>s57
20
10
>Exit code: 0
[解説]
純粋仮想メンバーを抽象基底クラスのポインタから呼んでいます。

s58.cpp
// dynamic allocation and polymorphism
#include <iostream>
using namespace std;

class CPolygon {
protected:
    int width, height;
public:
    void set_values (int a, int b) { width = a; height = b; }
    virtual int area (void) = 0;
    void printarea (void) { cout << this->area() << endl; }
};

class CRectangle: public CPolygon {
public:
    int area (void) { return (width * height); }
};

class CTriangle: public CPolygon {
public:
    int area (void) { return (width * height / 2); }
};

int main () {
    CPolygon * ppoly1 = new CRectangle;
    CPolygon * ppoly2 = new CTriangle;
    ppoly1->set_values (4, 5);
    ppoly2->set_values (4, 5);
    ppoly1->printarea();
    ppoly2->printarea();
    delete ppoly1;
    delete ppoly2;
    return 0;
}

>s58
20
10
>Exit code: 0

[解説]
抽象基底クラスに導出クラスを動的に割り当てています。

s59.cpp
// function template
#include <iostream>
using namespace std;

template <class T>
T GetMax (T a, T b) {
    T result;
    result = (a > b) ? a : b;
    return (result);
}

int main () {
    int i = 5, j = 6, k;
    long l = 10, m = 5, n;
    k = GetMax<int>(i, j);
    n = GetMax<long>(l, m);
    cout << k << endl;
    cout << n << endl;
    return 0;
}

>s59
6
10
>Exit code: 0

[解説]
テンプレイト関数は 扱える変数型を一般化できます。テンプレイト関数GetMaxはTが比較条件演算ができる型なら動作します。int型とlong型のどちらでもを動作します。

s60.cpp
// function template
#include <iostream>
using namespace std;

template <class T>
T GetMax (T a, T b) {
  return ((a>b)? a : b);
}

int main () {
  int i=5, j=6, k;
  long l=10, m=5, n;
  k = GetMax(i, j);
  n = GetMax(l, m);
  cout << k << endl;
  cout << n << endl;
  return 0;
}

>s60
6
10
>Exit code: 0

[解説]
テンプレイト関数GetMaxは簡略な定義になっていますが機能は同じです。

s61.cpp
// class templates
#include <iostream>
using namespace std;

template <class T>
class mypair {
    T a, b;
public:
    mypair (T first, T second) {a = first; b = second;}
    T getmax ();
};

template <class T>
T mypair<T>::getmax () {
    T retval;
    retval = a > b ? a : b;
    return retval;
}

int main () {
    mypair <int> myobject (100, 75);
    cout << myobject.getmax() << endl;
    return 0;
}

>s61
100
>Exit code: 0

[解説]
テンプレイトクラスのint型オブジェクトmyobject(100,75)にgetmax()を適用し,100になります。

s62.cpp
// template specialization
#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
    T element;
public:
    mycontainer (T arg) {element = arg;}
    T increase () { return ++element;}
};

// class template specialization:
template <>
class mycontainer <char> {
    char element;
public:
    mycontainer (char arg) {element = arg;}
    char uppercase () {
        if ((element >= 'a') && (element <= 'z'))
            element += 'A' -'a';
        return element;
    }
};

int main () {
    mycontainer<int> myint (7);
    mycontainer<char> mychar ('j');
    cout << myint.increase() << endl;
    cout << mychar.uppercase() << endl;
    return 0;
}

>s62
8
J
>Exit code: 0

[解説]
テンプレイトクラスmycontainerでは++elementがreturnされますがこのままにはこのmycontainerは使えませんので型への特別化を templete <> class mycontainer {...}で行いクラスの適用範囲を広げることができます。

s63.cpp
// sequence template
#include <iostream>
using namespace std;

template <class T, int N>
class mysequence {
    T memblock [N];
public:
    void setmember (int x, T value);
    T getmember (int x);
};

template <class T, int N>
void mysequence<T, N>::setmember (int x, T value) {
    memblock[x] = value;
}

template <class T, int N>
T mysequence<T, N>::getmember (int x) {
    return memblock[x];
}

int main () {
    mysequence <int, 5> myints;
    mysequence <double, 5> myfloats;
    myints.setmember (0, 100);
    myfloats.setmember (3, 3.1416);
    cout << myints.getmember(0) << '\n';
    cout << myfloats.getmember(3) << '\n';
    return 0;
}

>s63
100
3.1416
>Exit code: 0

[解説]
テンプレイトクラスmysequenceのオブジェクトmyintsはint型配列memblock[5]を持ちます。 myints.setmember(0,100)で配列memblock[0]=100となります。 myints.getmember(0)でそれを返すので結果は100となります。 myfloatsはdouble型で同じ動作をしています。

s64.cpp
// namespaces
#include <iostream>
using namespace std;

namespace first {
int var = 5;
}

namespace second {
double var = 3.1416;
}

int main () {
    cout << first::var << endl;
    cout << second::var << endl;
    return 0;
}

>s64
5
3.1416
>Exit code: 0
[解説]
同じ変数でも名前空簡の違いによって異なった変数として使うことができます。名前空間::変数として名前空間を明示します。

s65.cpp
// using
#include <iostream>
using namespace std;

namespace first {
int x = 5;
int y = 10;
}

namespace second {
double x = 3.1416;
double y = 2.7183;
}

int main () {
    using first::x;
    using second::y;
    cout << x << endl;
    cout << y << endl;
    cout << first::y << endl;
    cout << second::x << endl;
    return 0;
}

>s65
5
2.7183
10
3.1416
>Exit code: 0

[解説]
名前空間を指定し,名前空間非明示の場合x=5,y=2.7183と名前空間を逆に明示した場合x=3.1416,y=10での違いを示しています。

s66.cpp
// using
#include <iostream>
using namespace std;

namespace first {
int x = 5;
int y = 10;
}

namespace second {
double x = 3.1416;
double y = 2.7183;
}

int main () {
    using namespace first;
    cout << x << endl;
    cout << y << endl;
    cout << second::x << endl;
    cout << second::y << endl;
    return 0;
}

>s66
5
10
3.1416
2.7183
>Exit code: 0

[解説]
名前空間の一般指定と変数への名前空間明示指定での結果の違いを示しています。

s67.cpp
// using namespace example
#include <iostream>
using namespace std;

namespace first {
int x = 5;
}

namespace second {
double x = 3.1416;
}

int main () {
    {
        using namespace first;
        cout << x << endl;
    }
    {
        using namespace second;
        cout << x << endl;
    }
    return 0;
}

>s67
5
3.1416
>Exit code: 0

[解説]
名前空間の一般指定での変数xの値の違いを示しています。

s68.cpp
// exceptions
#include <iostream>
using namespace std;

int main () {
    try {
        throw 20;
    } catch (int e) {
        cout << "An exception occurred. Exception No. " << e << endl;
    }
    return 0;
}

>s68
An exception occurred. Exception No. 20
>Exit code: 0

[解説]

s69.cpp
// standard exceptions
#include <iostream>
#include <exception>
using namespace std;

class myexception: public exception {
    virtual const char* what() const throw() {
        return "My exception happened";
    }
} myex;

int main () {
    try {
        throw myex;
    } catch (exception& e) {
        cout << e.what() << endl;
    }
    return 0;
}

>s69
My exception happened
>Exit code: 0

[解説]

s70.cpp
// bad_alloc standard exception
#include <iostream>
#include <exception>
using namespace std;

int main () {
    try {
        int* myarray = new int[1000000000];
    } catch (exception&; e) {
        cout << "Standard exception: " << e.what() << endl;
    }
    return 0;
}

>s70
Standard exception: St9bad_alloc
>Exit code: 0

[解説]

s71.cpp
// class type-casting
#include <iostream>
using namespace std;

class CDummy {
    float i, j;
};

class CAddition {
    int x, y;
public:
    CAddition (int a, int b) { x = a; y = b; }
    int result() { return x + y;}
};

int main () {
    CDummy d;
    CAddition * padd;
    padd = (CAddition*) & d;
    cout << padd->result() << endl;
    return 0;
}

>s71
2
>Exit code: 0
[解説]

s72.cpp
// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;

class CBase { virtual void dummy() {} };
class CDerived: public CBase { int a; };

int main () {
    try {
        CBase * pba = new CDerived;
        CBase * pbb = new CBase;
        CDerived * pd;

        pd = dynamic_cast<CDerived*>(pba);
        if (pd == 0)
            cout << "Null pointer on first type-cast" << endl;

        pd = dynamic_cast<CDerived*>(pbb);
        if (pd == 0)
            cout << "Null pointer on second type-cast" << endl;

    } catch (exception& e) {cout << "Exception: " << e.what();}
    return 0;
}

>s72
Null pointer on second type-cast
>Exit code: 0

[解説]

s73.cpp
// const_cast
#include <iostream>
using namespace std;

void print (char * str) {
    cout << str << endl;
}

int main () {
    const char * c = "sample text";
    print ( const_cast (c) );
    return 0;
}

>s73
sample text
>Exit code: 0

[解説]

s74.cpp
// typeid
#include <iostream>
#include <typeinfo>
using namespace std;

int main () {
    int * a, b;
    a = 0;
    b = 0;
    if (typeid(a) != typeid(b)) {
        cout << "a and b are of different types:\n";
        cout << "a is: " << typeid(a).name() << '\n';
        cout << "b is: " << typeid(b).name() << '\n';
    }
    return 0;
}

>s74
a and b are of different types:
a is: Pi
b is: i
>Exit code: 0

[解説]

s75.cpp
// typeid, polymorphic class
#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;

class CBase { virtual void f() {} };
class CDerived : public CBase {};

int main () {
    try {
        CBase* a = new CBase;
        CBase* b = new CDerived;
        cout << "a is: " << typeid(a).name() << '\n';
        cout << "b is: " << typeid(b).name() << '\n';
        cout << "*a is: " << typeid(*a).name() << '\n';
        cout << "*b is: " << typeid(*b).name() << '\n';
    } catch (exception& e) { cout << "Exception: " << e.what() << endl; }
    return 0;
}

>s75
a is: P5CBase
b is: P5CBase
*a is: 5CBase
*b is: 8CDerived
>Exit code: 0

[解説]

s76.cpp
// function macro
#include <iostream>
using namespace std;

#define getmax(a,b) ((a)>(b)?(a):(b))

int main() {
    int x = 5, y;
    y = getmax(x, 2);
    cout << y << endl;
    cout << getmax(7, x) << endl;
    return 0;
}

>s76
5
7
>Exit code: 0

[解説]

s77.cpp
// standard macro names
#include <iostream>
using namespace std;

int main() {
    cout << "This is the line number " << __LINE__;
    cout << " of file " << __FILE__ << ".\n";
    cout << "Its compilation began " << __DATE__;
    cout << " at " << __TIME__ << ".\n";
    cout << "The compiler gives a __cplusplus value of " 
    	<< __cplusplus << endl;
    return 0;
}

>s77
This is the line number 6 of file s77.cpp.
Its compilation began Sep 16 2007 at 09:28:48.
The compiler gives a __cplusplus value of 1
>Exit code: 0
[解説]

s78.cpp
// basic file operations
#include <iostream>
#include <fstream>
using namespace std;

int main () {
    ofstream myfile;
    myfile.open ("example.txt");
    myfile << "Writing this to a file.\n";
    myfile.close();
    return 0;
}

>s78
>Exit code: 0
[解説]

s79.cpp
// writing on a text file
#include <iostream>
#include <fstream>
using namespace std;

int main () {
    ofstream myfile ("example.txt");
    if (myfile.is_open()) {
        myfile << "This is a line.\n";
        myfile << "This is another line.\n";
        myfile.close();
    } else
        cout << "Unable to open file";
    return 0;
}

>s79
>Exit code: 0
[解説]

s80.cpp
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main () {
    string line;
    ifstream myfile ("example.txt");
    if (myfile.is_open()) {
        while (! myfile.eof() ) {
            getline (myfile, line);
            cout << line << endl;
        }
        myfile.close();
    }
    else
        cout << "Unable to open file";

    return 0;
}

>s80
This is a line.
This is another line.

>Exit code: 0

[解説]

s81.cpp
// obtaining file size
#include <iostream>
#include <fstream>
using namespace std;

int main () {
    long begin, end;
    ifstream myfile ("example.txt");
    begin = myfile.tellg();
    myfile.seekg (0, ios::end);
    end = myfile.tellg();
    myfile.close();
    cout << "size is: " << (end - begin) << " bytes.\n";
    return 0;
}

>s81
size is: 40 bytes.
>Exit code: 0
[解説]

s82.cpp
// reading a complete binary file
#include <iostream>
#include <fstream>
using namespace std;

ifstream::pos_type size;
char * memblock;

int main () {
    ifstream file ("example.txt", ios::in | ios::binary | ios::ate);
    if (file.is_open()) {
        size = file.tellg();
        memblock = new char [size];
        file.seekg (0, ios::beg);
        file.read (memblock, size);
        file.close();

        cout << "the complete file content is in memory" << endl;

        delete[] memblock;
    } else
        cout << "Unable to open file" << endl;
    return 0;
}

>s82
the complete file content is in memory
>Exit code: 0

[解説]

LESSON1| LESSON3