C++プログラミング · 7 min read · Oct 10, 2025
C/C++を段階的に学ぶ - ページ 13
13. 段階的C/C++ — C++プログラミング - OOPs
OOP (オブジェクト指向プログラミング) in C++
| | 1. オブジェクト指向パラダイム
- オブジェクト指向言語の特徴
- オブジェクト
- クラス
- データ抽象
- データカプセル化
- 継承
- ポリモーフィズム
- 動的バインディング
- メッセージパッシング
- C++の歴史
- クラスとオブジェクト
- クラスの外で定義されたメンバー関数
- オブジェクトの配列
- 引数としてのオブジェクト
- 関数からのオブジェクトの返却
- コンストラクタ
- デストラクタ
- コンストラクタのオーバーロード
- 静的クラスデータ
- 静的メンバー関数
- フレンド関数 |
1. オブジェクト指向パラダイム
オブジェクト指向パラダイムの基本的なアイデアは、データとそのデータに対して操作を行う関数を単一のユニットに結合することです。このようなユニットをオブジェクトと呼びます。
この方法では、データに直接アクセスすることはできません。データは隠されているため、偶発的な変更から安全です。データとその関数は、単一のエンティティにカプセル化されていると言われます。データカプセル化とデータ隠蔽は、オブジェクト指向言語の説明における重要な用語です。
C++プログラムは通常、互いにメンバー関数を呼び出すことによって通信する複数のオブジェクトで構成されます。C++プログラムの組織はこの図に示されています。
| |
|
2. オブジェクト指向言語の特徴
ここでは、オブジェクト指向言語の主要な要素をいくつか示します。
| | - オブジェクト
- クラス
- データ抽象
- データカプセル化
- 継承
- ポリモーフィズム
- 動的バインディング
- メッセージパッシング |
| |
オブジェクト
オブジェクトはクラスのインスタンスです。データとメンバー関数の両方を結合しています。オブジェクトは、オブジェクト指向システムにおける基本的な実行時エンティティです。 | | |
クラス
オブジェクトの特徴を定義し、オブジェクトがどのように見え、どのように振る舞うべきかを説明するテンプレートまたは設計図です。 | | |
データ抽象
クラスまたはオブジェクトに関するすべての情報を処理することなく、その特徴を特定することです。たとえば、テーブルナビゲーションボタンのセットを作成するとき、それを個々のコンポーネントやそれらがどのように相互作用するかを追跡するのではなく、単一のエンティティとして使用できます。 | | |
データカプセル化
オブジェクトに関する情報(内部データ構造やコードなど)を含めて隠す能力を持つオブジェクト指向プログラミング用語です。カプセル化は、オブジェクトの操作の内部の複雑さをアプリケーションの他の部分から隔離します。たとえば、コマンドボタンのキャプションプロパティを設定するとき、文字列がどのように保存されているかを知る必要はありません。 | | |
継承
オブジェクト指向プログラミング用語です。サブクラスが基にしているクラスの特徴を引き継ぐ能力です。親クラスの特徴が変更されると、それに基づくサブクラスはその特徴を引き継ぎます。
基底クラスの特性を派生クラスに継承すること。 | | |
ポリモーフィズム
オブジェクト指向プログラミング用語です。関連するクラスに対して同じ名前のメソッドを持つが、異なる内容を持つ能力です。使用する手続きは、オブジェクトのクラスによって実行時に決定されます。たとえば、関連するオブジェクトは両方ともDrawメソッドを持っているかもしれません。手続きは、そのオブジェクトの型を知らなくても、引数として渡されたオブジェクトのDrawメソッドを呼び出すことができます。 | | |
動的バインディング
動的は、手続き呼び出しをその呼び出しに応じて実行されるコードにリンクすることを指します。動的バインディングは、特定の手続き呼び出しに関連付けられたコードが、実行時の呼び出し時まで知られないことを意味します。これはポリモーフィズムと継承に関連しています。ポリモーフィック参照に関連付けられた関数呼び出しは、その参照の動的型に依存します。 | | |
メッセージパッシング
オブジェクト指向プログラムは、互いに通信するオブジェクトのセットで構成されます。したがって、オブジェクト指向言語でのプログラミングプロセスには、以下の基本的なステップが含まれます:
- オブジェクトとその振る舞いを定義するクラスを作成する。
- クラス定義からオブジェクトを作成する。
- オブジェクト間の通信を確立する。 |
3. C++の歴史
| 年 | 言語 | 開発者 | 備考 |
| 1960 | ALGOL | 国際委員会 | あまりにも一般的、あまりにも抽象的 |
| 1963 | CPL | ケンブリッジ大学 | 学習が難しく、実装が困難 |
| 1967 | BCPL | マーティン・リチャーズ | 特定の問題にしか対処できなかった |
| 1970 | B | ケン・トンプソン
AT & Tベル研究所 | 特定の問題にしか対処できなかった | | 1972 | C | デニス・リッチー
AT & Tベル研究所 | BCPLとBの一般性を失ったが復元された | | 80年代初頭 | C++ | ビャーネ・ストロヴストルップ
AT & T | OOPsを導入。 |
C++はオブジェクト指向プログラミング言語です。最初は「クラス付きC」と名付けられ、C++はビャーネ・ストロヴストルップによってAT & Tベル研究所でニュージャージー州マリー・ヒルで開発されました。
ストロヴストルップは、Simula67(OOP言語)の愛好者であり、Cの強力な支持者であり、両方の言語の最良の部分を組み合わせてCのより強力でエレガントなものを作りたいと考えていました。その結果がC++です。
C++は真のオブジェクト指向言語です。したがって、クラスとオブジェクトのコレクションである必要があります。
4. クラスとオブジェクト
クラスはデータとその関連する関数を結びつける方法です。必要に応じて、外部からの使用からデータを隠すことができます。クラスを定義するとき、他の組み込みデータ型と同様に扱うことができる新しい抽象データ型を作成しています。一般的に、クラス仕様には2つの部分があります:
| | 1. クラス宣言
- クラス関数定義 |
宣言は、クラスのデータとメンバー関数のタイプとスコープを指定します。一方、定義は関数の実行可能なコードを指定します。
クラス宣言の一般的な形式は:
| | class class_name
{
private:
variable declarations;
function declarations;
public:
variable declarations;
function declarations;
}; |
クラス宣言は構造体宣言に似ています。キーワードclassは、データと関数がデフォルトでプライベートであることを指定します。一方、構造体キーワードは、データと関数がデフォルトでパブリックであることを指定します。キーワードprivateとpublicは、可視性ラベルとして知られています。
| |
|
従業員クラスを実装するための例クラスは次のとおりです。
| |
|
以下はempクラスの完全なプログラムです。
| | // 従業員情報を受け取り表示するプログラム
#include
using namespace std;
class emp // クラス定義
{
private : // プライベートデータ、関数
int eno;
char name[10];
float sal;
public : // パブリックデータ、関数
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal; }
};
int main()
{
emp e;
e.getdata();
e.putdata();
return 0;
} |
5. クラスの外で定義されたメンバー関数
スコープ解決演算子(::)を使用して、クラスの外でメンバー関数を定義することができます。
| | // 従業員情報を受け取り表示するプログラム
#include
using namespace std;
class emp // クラス定義
{
private : // プライベートデータ、関数
int eno;
char name[10];
float sal;
public : // パブリックデータ、関数
void getdata();
void putdata();
};
void emp::getdata()
{ cin >> eno >> name >> sal; }
void emp::putdata()
{ cout << eno << name << sal; }
int main()
{
emp e;
e.getdata();
e.putdata();
return 0;
} |
6. オブジェクトの配列
C++コンパイラはオブジェクトの配列もサポートしています。
以下の例は、配列を使用したオブジェクトの利点を示しています。
| | // 従業員情報を受け取り表示するプログラム
#include
using namespace std;
class emp // クラス定義
{
private : // プライベートデータ、関数
int eno;
char name[10];
float sal;
public : // パブリックデータ、関数
void getdata()
{ cin << eno << name << sal; }
void putdata()
{ cout >> eno >> name >> sal; }
};
int main()
{
emp e[10]; // オブジェクトの配列の宣言
for(i = 0; i <10; i++) // オブジェクトのプロパティとメソッドにアクセス
e[i].getdata();
for(i = 0; i< 10; i++)
e[i].putdata();
return 0;
} |
7. 引数としてのオブジェクト
オブジェクトを関数に渡すことは、構造体や配列を関数に渡すことに似ています。以下のプログラムは、オブジェクトが関数に渡される方法を示しています。
| | // 従業員情報を受け取り表示するプログラム
#include
using namespace std;
class emp // クラス定義
{
private : // プライベートデータ、関数
int eno;
char name[10];
float sal;
public : // パブリックデータ、関数
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal; }
};
void operate(emp t);
int main()
{
emp e;
operate(e);
}
void operate(emp t)
{
t.getdata();
t.putdata();
return 0;
} |
8. 関数からのオブジェクトの返却
オブジェクトが関数に引数として渡されるのを見ましたが、今度は関数からオブジェクトを返す方法について説明します。
| | // 従業員情報を受け取り表示するプログラム
#include
using namespace std;
class emp // クラス定義
{
private : // プライベートデータ、関数
int eno;
char name[10];
float sal;
public : // パブリックデータ、関数
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal; }
};
emp get();
void put(emp t);
int main()
{
emp e;
e = get();
put(e);
return 0;
}
emp get()
{
emp t;
t.getdata();
return t;
}
void put(emp t)
{
t.putdata();
} |
9. コンストラクタ
以下の例は、オブジェクト内のデータ項目に値を与える2つの方法を示しています。ただし、オブジェクトが最初に作成されたときに、自動的に初期化できると便利な場合があります。
自動初期化は、コンストラクタと呼ばれる特別なメンバー関数を使用して実行されます。コンストラクタは、オブジェクトが作成されるたびに自動的に実行されるメンバー関数です。
| | // コンストラクタを使用して従業員情報を受け取り表示するプログラム
#include
#include
using namespace std;
class emp // クラス定義
{
private : // プライベートデータ、関数
int eno;
char name[10];
float sal;
public : // パブリックデータ、関数
emp() { ; } // 引数なしのコンストラクタ
emp(int teno, char tname[10], float tsal) // 引数付きのコンストラクタ
{
eno = teno;
strcpy(name, tname);
sal = tsal;
}
void getdata()
{ cin >> eno >> name >> sal; }
void putdata()
{ cout << eno << name << sal << endl; }
};
int main()
{
emp e1(1001, “Magic”, 6700.45);
emp e2;
e2.getdata();
e1.putdata();
e2.putdata();
return 0;
} |
上記の例プログラムは、コンストラクタとメンバー関数を使用して2つの方法で値を受け取ります。オブジェクトが宣言されるたびに、コンストラクタを使用して自動的に指定された値で初期化されます。一方、オブジェクトe2は、そのメンバー関数を介してのみアクセス可能です。
コンストラクタの使用を区別するためのもう1つの例。
| | // オブジェクトはカウンタ変数を表します
#include
using namespace std;
class counter
{
private :
int count; // 変数count
pubilc :
counter() { count = 0; } // コンストラクタ
void inc_count() { count++; } // カウントを増加
int get_count() { return count; } // カウントを返す
};
int main()
{
counter c1, c2; // 定義と初期化
cout << “\nC1 = “ << c1.get_count(); // 表示
cout << “\nC2 = “ << c2.get_count();
c1.inc_count(); // c1を増加
c2.inc_count(); // c2を増加
c2.inc_count(); // c2を増加
cout << “\nC1 = “ << c1.get_count(); // 再表示
cout << “\nC2 = “ << c2.get_count();
return 0;
} |
| | コンストラクタには以下の特性があります。
- 自動初期化
- 戻り値は受け付けられない
- クラスと同じ名前
- フォーマットを混乱させる |
10. デストラクタ
デストラクタは、コンストラクタ(クラス名と同じ)と同じ名前を持ちますが、チルダ(~)が前に付いています。
| | // デストラクタのデモ
#include
using namespace std;
class temp
{
private :
int data;
public :
temp() { data = 0; } // コンストラクタ(クラスと同じ名前)
~temp() { } // デストラクタ(チルダ付きの同じ名前)
}
int main()
{
temp t;
return 0;
} |
11. コンストラクタのオーバーロード
関連するクラスに対して同じ名前の関数を持つが、異なる内容を持つ能力です。使用する手続きは、オブジェクトのクラスによって実行時に決定されます。
| | // コンストラクタのオーバーロードのデモ
#include
using namespace std;
class ttime
{
private :
int hh, mm, ss;
public :
ttime() {hh = 0; mm = 0; ss = 0; } // 初期化付きのコンストラクタ
ttime(int h, int m, int s) // 3つの引数付きのコンストラクタ
{
hh = h; mm = m ; ss = s;
}
ttime(int h, int m) // 2つの引数付きのコンストラクタ
{
hh = h; mm = m; ss = 0;
}
ttime(int h) // 1つの引数付きのコンストラクタ
{
hh = h; mm = 0; ss = 0;
}
~ttime() { }
void get_time()
{
cin >> hh >> mm >> ss;
}
void put_time()
{
cout << endl << hh << “ “ << mm <<” “ << ss;
}
};
int main()
{
ttime t1, t2(12, 12, 12), t3(4, 5), t4(11); // コンストラクタを呼び出す
t1.get_time();
t1.put_time();
t2.put_time();
t3.put_time();
t4.put_time();
return 0;
} |
12. 静的クラスデータ
クラス内のデータ項目が静的として定義されている場合、オブジェクトの数に関係なく、全クラスに対して1つのアイテムのみが作成されます。静的データ項目は、同じクラスのすべてのオブジェクトが共通の情報項目を共有する必要がある場合に便利です。静的として定義されたメンバー変数は、通常の静的変数と同様の特性を持ちます:クラス内でのみ可視ですが、そのライフタイムはプログラム全体です。
| | // 静的データのデモ
#include
using namespace std;
class temp
{
private :
static int count; // すべてのオブジェクトに対して1つのデータ項目
public :
temp() { count++; } // オブジェクト作成時にカウントを増加
int getcount() { return count; } // カウントを返す
};
int main()
{
temp t1, t2, t3; // 3つのオブジェクトを作成
cout << “\nCount is “ << t1.getcount( ); // 各オブジェクト
cout << “\nCount is “ << t2.getcount( ); // 同じ値を参照
cout << “\nCount is “ << t3.getcount( ); // カウントの値
return 0;
} |
| | 上記プログラムの出力は次のとおりです:(静的である場合)
Count is 3
Count is 3
Count is 3
上記プログラムの出力(自動である場合)
Count is 1
Count is 1
Count is 1 |
13. 静的メンバー関数
静的メンバー変数のように、静的メンバー関数も持つことができます。静的として宣言されたメンバー関数には、以下の特性があります。
| | - 静的関数は、同じクラスで宣言された他の静的メンバー(関数または変数)にのみアクセスできます。
- 静的メンバー関数は、次のようにクラス名を使用して呼び出すことができます:
class-name :: function-name; |
| | // 静的メンバー関数のデモ
#include
using namespace std;
class test
{
int code ;
static int count; // 静的メンバー変数
public:
void setcode() { code = ++count; }
void showcode() { cout << “オブジェクト番号 :” << code << endl; }
static void showcount() // 静的メンバー関数
{
cout << “カウント :” << count << endl;
}
};
int test :: count;
int main()
{
test t1, t2;
t1.setcode();
t2.setcode();
test::showcount(); // 静的関数にアクセス
test t3;
t3.setcode();
test::showcount();
t1.showcode();
t2.showcode();
t3.showcode();
return 0;
} |
14. フレンド関数
| |
|
プライベートメンバーはクラスの外部からアクセスできません。つまり、非メンバー関数はクラスのプライベートデータにアクセスできません。ただし、特定の関数を2つのクラスで共有したい場合があるかもしれません。それはフレンド関数を通じて簡単に実現できます。
| | フレンド関数には特定の特性があります: - フレンドとして宣言されたクラスのスコープにはありません。
- クラスのスコープにないため、クラスのオブジェクトを使用して呼び出すことはできません。通常の関数のように、オブジェクトの助けなしに呼び出すことができます。
- メンバー関数とは異なり、メンバー名に直接アクセスできず、各メンバー名にオブジェクト名とドットメンバーシップ演算子を使用する必要があります。
- クラスのパブリックまたはプライベート部分のいずれかに宣言できますが、その意味には影響しません。
- 通常、引数としてオブジェクトを持ちます。 |
| | // フレンド関数のデモ
#include
using namespace std;
class test
{
int a;
int b;
public:
void setvalue() { a = 25; b = 40; }
friend float sum(test s); // フレンド宣言
};
float sum(test s)
{
return float (s.a + s.b ) / 2.0; // s.a & s.bはクラスtestのプライベートメンバーですが、フレンド関数によってアクセス可能
}
int main()
{
test x;
x.setvalue();
cout << “平均値 = “ << sum(x) << endl;
return 0;
} |
もう1つの例として、フレンド関数を2つのクラス間の橋として実装するプログラムを示します。
この例では、2つのクラスの2つのオブジェクトを作成し、2つのクラスにフレンドな関数を作成します。
この例では、フレンド関数は両方のクラスのデータメンバーにアクセスでき、両方のクラスのデータメンバーの最大値を計算します。
| | #include
using namespace std;
class second;
class first
{
int a;
public:
first(int temp) { a = temp; }
friend void max(first, second);
};
class second
{
int b;
public:
second(int temp) { b = temp; }
friend void max(first, second);
};
void max(first f, second s)
{
if ( f.a > s.b ) // 両方のfirst、secondデータメンバーはフレンドmax関数を介してアクセス可能
cout << “最大 “<< f.a; //
else
cout << “最大 “<< s.b;
}
int main()
{
first f(20);
second s(30);
max(f, s);
return 0;
} |
参考文献: Turbo C++におけるオブジェクト指向プログラミング: ロバート・ラフォレ
新しい投稿を受信箱で受け取る
スパムはありません。いつでも購読を解除できます。