Last Update 2023/11/04
概要
単一継承
sample.cpp
#include <iostream>
#include <iomanip>
// バイト列表示用関数
void byteseq(const unsigned char *cp, std::size_t nlen, const char *tname)
{
std::cout << std::uppercase << std::hex;
std::cout << tname << " = ";
for (std::size_t i=0; i<nlen; i++)
{
std::cout << std::setw(2) << std::setfill('0')
<< static_cast<int>(cp[i]) << " ";
}
std::cout << std::endl;
}
static int x = 1; // コンストラクタ実行時のユニーク値生成用
class Smpl1
{
unsigned int n1;
public:
Smpl1() { n1 = 0x01 + x * 0x10000; x++; }
unsigned int get1() { return n1; }
};
// Smpl1を基底クラスとする派生クラス
class Smpl2 : public Smpl1
{
unsigned int n2;
public:
Smpl2() { n2 = 0x02 + x * 0x10000; x++; }
unsigned int get2() { return n2; }
};
// Smpl2を基底クラスとする派生クラス
class Smpl3 : public Smpl2
{
unsigned int n3;
public:
Smpl3() { n3 = 0x03 + x * 0x10000; x++; }
unsigned int get3() { return n3; }
};
// Smpl3を基底クラスとする派生クラス
class Smpl4 : public Smpl3
{
unsigned int n4;
public:
Smpl4() { n4 = 0x04 + x * 0x10000; x++; }
unsigned int get4() { return n4; }
};
int main()
{
Smpl1 s1;
Smpl2 s2;
Smpl3 s3;
Smpl4 s4;
std::cout << "各クラス型のバイト列" << std::endl;
byteseq(reinterpret_cast<unsigned char *>(&s1), sizeof(s1), "s1");
byteseq(reinterpret_cast<unsigned char *>(&s2), sizeof(s2), "s2");
byteseq(reinterpret_cast<unsigned char *>(&s3), sizeof(s3), "s3");
byteseq(reinterpret_cast<unsigned char *>(&s4), sizeof(s4), "s4");
std::cout << std::endl;
std::cout << "s1のメンバ関数を実行" << std::endl;
std::cout << "s1.get1() = " << s1.get1() << std::endl;
std::cout << std::endl;
std::cout << "s2のメンバ関数(基底クラスを含む)を実行" << std::endl;
std::cout << "s2.get1() = " << s2.get1() << std::endl;
std::cout << "s2.get2() = " << s2.get2() << std::endl;
std::cout << std::endl;
std::cout << "s3のメンバ関数(基底クラスを含む)を実行" << std::endl;
std::cout << "s3.get1() = " << s3.get1() << std::endl;
std::cout << "s3.get2() = " << s3.get2() << std::endl;
std::cout << "s3.get3() = " << s3.get3() << std::endl;
std::cout << std::endl;
std::cout << "s4のメンバ関数(基底クラスを含む)を実行" << std::endl;
std::cout << "s4.get1() = " << s4.get1() << std::endl;
std::cout << "s4.get2() = " << s4.get2() << std::endl;
std::cout << "s4.get3() = " << s4.get3() << std::endl;
std::cout << "s4.get4() = " << s4.get4() << std::endl;
}
実行結果
$ gcc -Wall sample.cpp -lstdc++
$ ./a.out
各クラス型のバイト列
s1 = 01 00 01 00
s2 = 01 00 02 00 02 00 03 00
s3 = 01 00 04 00 02 00 05 00 03 00 06 00
s4 = 01 00 07 00 02 00 08 00 03 00 09 00 04 00 0A 00
s1のメンバ関数を実行
s1.get1() = 10001
s2のメンバ関数(基底クラスを含む)を実行
s2.get1() = 20001
s2.get2() = 30002
s3のメンバ関数(基底クラスを含む)を実行
s3.get1() = 40001
s3.get2() = 50002
s3.get3() = 60003
s4のメンバ関数(基底クラスを含む)を実行
s4.get1() = 70001
s4.get2() = 80002
s4.get3() = 90003
s4.get4() = A0004
複数の基本クラス
sample.cpp
#include <iostream>
#include <iomanip>
// バイト列表示用関数
void byteseq(const unsigned char *cp, std::size_t nlen, const char *tname)
{
std::cout << std::uppercase << std::hex;
std::cout << tname << " = ";
for (std::size_t i=0; i<nlen; i++)
{
std::cout << std::setw(2) << std::setfill('0')
<< static_cast<int>(cp[i]) << " ";
}
std::cout << std::endl;
}
static unsigned int x = 1; // コンストラクタ実行時のユニーク値生成用
class Smpl1
{
unsigned int n1;
public:
Smpl1() { n1 = 0x01 + x * 0x10000; x++; }
unsigned int get1() { return n1; }
};
class Smpl2
{
unsigned int n2;
public:
Smpl2() { n2 = 0x02 + x * 0x10000; x++; }
unsigned int get2() { return n2; }
};
// Smpl1、Smpl2を基底クラスとする派生クラス
// Smpl1は仮想基底クラス
class Smpl3 : virtual public Smpl1, public Smpl2
{
unsigned int n3;
public:
Smpl3() { n3 = 0x03 + x * 0x10000; x++; }
unsigned int get3() { return n3; }
};
// Smpl1、Smpl3を基底クラスとする派生クラス
// Smpl1、Smpl3共に仮想基底クラス
class Smpl4 : virtual public Smpl1, virtual public Smpl3
{
unsigned int n4;
public:
Smpl4() { n4 = 0x04 + x * 0x10000; x++; }
unsigned int get4() { return n4; }
};
// Smpl1、Smpl3、Smpl4を基底クラスとする派生クラス
// Smpl1、Smpl3共に仮想基底クラス
class Smpl5 : virtual public Smpl1, virtual public Smpl3, public Smpl4
{
unsigned int n5;
public:
Smpl5() { n5 = 0x05 + x * 0x10000; x++; }
unsigned int get5() { return n5; }
};
// Smpl2を基底クラス(非仮想)とする派生クラス
class Smpl6 : public Smpl2
{
unsigned int n6;
public:
Smpl6() { n6 = 0x06 + x * 0x10000; x++; }
unsigned int get6() { return n6; }
};
// Smpl5、Smpl6を基底クラスとする派生クラス
class Smpl7 : public Smpl5, public Smpl6
{
unsigned int n7;
public:
Smpl7() { n7 = 0x07 + x * 0x10000; x++; }
unsigned int get7() { return n7; }
};
int main()
{
Smpl1 s1;
Smpl2 s2;
Smpl3 s3;
Smpl4 s4;
Smpl5 s5;
Smpl6 s6;
Smpl7 s7;
std::cout << "各クラス型のバイト列" << std::endl;
std::cout << &s1 << " --- ";
byteseq(reinterpret_cast<unsigned char *>(&s1), sizeof(s1), "s1");
std::cout << &s2 << " --- ";
byteseq(reinterpret_cast<unsigned char *>(&s2), sizeof(s2), "s2");
std::cout << &s3 << " --- ";
byteseq(reinterpret_cast<unsigned char *>(&s3), sizeof(s3), "s3");
std::cout << &s4 << " --- ";
byteseq(reinterpret_cast<unsigned char *>(&s4), sizeof(s4), "s4");
std::cout << &s5 << " --- ";
byteseq(reinterpret_cast<unsigned char *>(&s5), sizeof(s5), "s5");
std::cout << &s6 << " --- ";
byteseq(reinterpret_cast<unsigned char *>(&s6), sizeof(s6), "s6");
std::cout << &s7 << " --- ";
byteseq(reinterpret_cast<unsigned char *>(&s7), sizeof(s7), "s7");
std::cout << std::endl;
std::cout << "s1のメンバ関数を実行" << std::endl;
std::cout << "s1.get1() = " << s1.get1() << std::endl;
std::cout << std::endl;
std::cout << "s2のメンバ関数を実行" << std::endl;
std::cout << "s2.get2() = " << s2.get2() << std::endl;
std::cout << std::endl;
std::cout << "s3のメンバ関数(基底クラスを含む)を実行" << std::endl;
std::cout << "s3.get1() = " << s3.get1() << std::endl;
std::cout << "s3.get2() = " << s3.get2() << std::endl;
std::cout << "s3.get3() = " << s3.get3() << std::endl;
std::cout << std::endl;
std::cout << "s4のメンバ関数(基底クラスを含む)を実行" << std::endl;
std::cout << "s4.get1() = " << s4.get1() << std::endl;
std::cout << "s4.get2() = " << s4.get2() << std::endl;
std::cout << "s4.get3() = " << s4.get3() << std::endl;
std::cout << "s4.get4() = " << s4.get4() << std::endl;
std::cout << std::endl;
std::cout << "s5のメンバ関数(基底クラスを含む)を実行" << std::endl;
std::cout << "s5.get1() = " << s5.get1() << std::endl;
std::cout << "s5.get2() = " << s5.get2() << std::endl;
std::cout << "s5.get3() = " << s5.get3() << std::endl;
std::cout << "s5.get4() = " << s5.get4() << std::endl;
std::cout << "s5.get5() = " << s5.get5() << std::endl;
std::cout << std::endl;
std::cout << "s6のメンバ関数(基底クラスを含む)を実行" << std::endl;
std::cout << "s6.get2() = " << s6.get2() << std::endl;
std::cout << "s6.get6() = " << s6.get6() << std::endl;
std::cout << std::endl;
std::cout << "s7のメンバ関数(基底クラスを含む)を実行" << std::endl;
std::cout << "s7.get1() = " << s7.get1() << std::endl;
std::cout << "s7.Smpl5::get2() = " << s7.Smpl5::get2() << std::endl; // Smpl2は非仮想基底クラス
std::cout << "s7.Smpl6::get2() = " << s7.Smpl6::get2() << std::endl; // 〃
std::cout << "s7.get3() = " << s7.get3() << std::endl;
std::cout << "s7.get4() = " << s7.get4() << std::endl;
std::cout << "s7.get5() = " << s7.get5() << std::endl;
std::cout << "s7.get6() = " << s7.get6() << std::endl;
std::cout << "s7.get7() = " << s7.get7() << std::endl;
}
実行結果
$ gcc -Wall sample.cpp -lstdc++
$ ./a.out
各クラス型のバイト列
0x7ffd3c4428dc --- s1 = 01 00 01 00
0x7ffd3c4428d8 --- s2 = 02 00 02 00
0x7ffd3c4428c0 --- s3 = 40 35 40 00 00 00 00 00 02 00 04 00 03 00 05 00 01 00 03 00 00 00 00 00
0x7ffd3c4428a0 --- s4 = E0 34 40 00 00 00 00 00 04 00 09 00 01 00 06 00 F8 34 40 00 00 00 00 00 02 00 07 00 03 00 08 00
0x7ffd3c442870 --- s5 = 30 34 40 00 00 00 00 00 04 00 0D 00 05 00 0E 00 01 00 0A 00 00 00 00 00 48 34 40 00 00 00 00 00 02 00 0B 00 03 00 0C 00
0x7ffd3c442868 --- s6 = 02 00 0F 00 06 00 10 00
0x7ffd3c442830 --- s7 = 38 33 40 00 00 00 00 00 04 00 14 00 05 00 15 00 02 00 16 00 06 00 17 00 07 00 18 00 01 00 11 00 50 33 40 00 00 00 00 00 02 00 12 00 03 00 13 00
s1のメンバ関数を実行
s1.get1() = 10001
s2のメンバ関数を実行
s2.get2() = 20002
s3のメンバ関数(基底クラスを含む)を実行
s3.get1() = 30001
s3.get2() = 40002
s3.get3() = 50003
s4のメンバ関数(基底クラスを含む)を実行
s4.get1() = 60001
s4.get2() = 70002
s4.get3() = 80003
s4.get4() = 90004
s5のメンバ関数(基底クラスを含む)を実行
s5.get1() = A0001
s5.get2() = B0002
s5.get3() = C0003
s5.get4() = D0004
s5.get5() = E0005
s6のメンバ関数(基底クラスを含む)を実行
s6.get2() = F0002
s6.get6() = 100006
s7のメンバ関数(基底クラスを含む)を実行
s7.get1() = 110001
s7.Smpl5::get2() = 120002
s7.Smpl6::get2() = 160002
s7.get3() = 130003
s7.get4() = 140004
s7.get5() = 150005
s7.get6() = 170006
s7.get7() = 180007
仮想関数
sample.cpp
#include <iostream>
class Smpl_base
{
unsigned int n;
public:
Smpl_base() { n = 1; }
unsigned int getn1() { return n; }
// 仮想関数として宣言
virtual unsigned int getn2() { return n + 1; }
};
// Smpl_baseを基底クラスとする派生クラス(1)
class Smpl1 : public Smpl_base
{
unsigned int n1;
public:
Smpl1() { n1 = 0x100; }
unsigned int getn1() { return n1; }
unsigned int getn2() { return n1 + 0x100; }
};
// Smpl_baseを基底クラスとする派生クラス(2)
class Smpl2 : public Smpl_base
{
unsigned int n2;
public:
Smpl2() { n2 = 0x1000; }
unsigned int getn1() { return n2; }
unsigned int getn2() { return n2 + 0x1000; }
};
int main()
{
Smpl_base sb;
Smpl1 s1;
Smpl2 s2;
// 各クラスオブジェクトへのポインタ
Smpl_base *psb = &sb;
Smpl1 *ps1 = &s1;
Smpl2 *ps2 = &s2;
// 基底クラスへの参照に派生クラスのオブジェクトを指定
Smpl_base& sbr1 = s1;
Smpl_base& sbr2 = s2;
std::cout << std::uppercase << std::hex;
std::cout << "クラスオブジェクトからのメンバ関数の呼び出し" << std::endl;
std::cout << "sb.getn1() = " << sb.getn1() << std::endl;
std::cout << "sb.getn2() = " << sb.getn2() << std::endl;
std::cout << "s1.getn1() = " << s1.getn1() << std::endl;
std::cout << "s1.getn2() = " << s1.getn2() << std::endl;
std::cout << "s2.getn1() = " << s2.getn1() << std::endl;
std::cout << "s2.getn2() = " << s2.getn2() << std::endl;
std::cout << std::endl;
std::cout << "オブジェクトへのポインタからのメンバ関数の呼び出し" << std::endl;
std::cout << "psb->getn1() = " << psb->getn1() << std::endl;
std::cout << "psb->getn2() = " << psb->getn2() << std::endl;
std::cout << "ps1->getn1() = " << ps1->getn1() << std::endl;
std::cout << "ps1->getn2() = " << ps1->getn2() << std::endl;
std::cout << "ps2->getn1() = " << ps2->getn1() << std::endl;
std::cout << "ps2->getn2() = " << ps2->getn2() << std::endl;
std::cout << std::endl;
std::cout << "s1のアドレスを代入した基底クラスへのポインタからのメンバ関数の呼び出し" << std::endl;
psb = &s1;
std::cout << "psb->getn1() = " << psb->getn1() << std::endl;
std::cout << "psb->getn2() = " << psb->getn2() << std::endl;
std::cout << std::endl;
std::cout << "s2のアドレスを代入した基底クラスへのポインタからのメンバ関数の呼び出し" << std::endl;
psb = &s2;
std::cout << "psb->getn1() = " << psb->getn1() << std::endl;
std::cout << "psb->getn2() = " << psb->getn2() << std::endl;
std::cout << std::endl;
std::cout << "基底クラスへの参照を使用したオブジェクトs1のメンバ関数の呼び出し" << std::endl;
std::cout << "sbr1.getn1() = " << sbr1.getn1() << std::endl;
std::cout << "sbr1.getn2() = " << sbr1.getn2() << std::endl;
std::cout << std::endl;
std::cout << "基底クラスへの参照を使用したオブジェクトs2のメンバ関数の呼び出し" << std::endl;
std::cout << "sbr2.getn1() = " << sbr2.getn1() << std::endl;
std::cout << "sbr2.getn2() = " << sbr2.getn2() << std::endl;
std::cout << std::endl;
}
実行結果
$ gcc -Wall sample.cpp -lstdc++
$ ./a.out
クラスオブジェクトからのメンバ関数の呼び出し
sb.getn1() = 1
sb.getn2() = 2
s1.getn1() = 100
s1.getn2() = 200
s2.getn1() = 1000
s2.getn2() = 2000
オブジェクトへのポインタからのメンバ関数の呼び出し
psb->getn1() = 1
psb->getn2() = 2
ps1->getn1() = 100
ps1->getn2() = 200
ps2->getn1() = 1000
ps2->getn2() = 2000
s1のアドレスを代入した基底クラスへのポインタからのメンバ関数の呼び出し
psb->getn1() = 1
psb->getn2() = 200 <--- 基底クラスが仮想関数の場合、s1のメンバ関数を実行
s2のアドレスを代入した基底クラスへのポインタからのメンバ関数の呼び出し
psb->getn1() = 1
psb->getn2() = 2000 <--- 基底クラスが仮想関数の場合、s2のメンバ関数を実行
基底クラスへの参照を使用したオブジェクトs1のメンバ関数の呼び出し
sbr1.getn1() = 1
sbr1.getn2() = 200 <--- 基底クラスが仮想関数の場合、s1のメンバ関数を実行
基底クラスへの参照を使用したオブジェクトs2のメンバ関数の呼び出し
sbr2.getn1() = 1
sbr2.getn2() = 2000 <--- 基底クラスが仮想関数の場合、s2のメンバ関数を実行
抽象クラス
sample.cpp
#include <iostream>
// 純粋仮想関数を持つ抽象クラス
class Smpl_base
{
unsigned int n;
public:
Smpl_base() { n = 1; }
unsigned int getn1() { return n; }
// 純粋仮想関数として宣言
virtual unsigned int getn2() = 0; // 「= 0」構文により宣言
};
// 抽象クラスSmpl_baseを基底クラスとする派生クラス(1)
class Smpl1 : public Smpl_base
{
unsigned int n1;
public:
Smpl1() { n1 = 0x100; }
unsigned int getn1() { return n1; }
unsigned int getn2() { return n1 + 0x100; } // 派生クラスでの純粋仮想関数の定義
};
// 抽象クラスSmpl_baseを基底クラスとする派生クラス(2)
class Smpl2 : public Smpl_base
{
unsigned int n2;
public:
Smpl2() { n2 = 0x1000; }
unsigned int getn1() { return n2; }
unsigned int getn2() { return n2 + 0x1000; } // 派生クラスでの純粋仮想関数の定義
};
int main()
{
Smpl1 s1;
Smpl2 s2;
// 抽象クラスへのポインタ
Smpl_base *psb;
// 抽象クラスへの参照に派生クラスのオブジェクトを指定
Smpl_base& sbr1 = s1;
Smpl_base& sbr2 = s2;
std::cout << std::uppercase << std::hex;
std::cout << "クラスオブジェクトからのメンバ関数の呼び出し" << std::endl;
std::cout << "s1.getn1() = " << s1.getn1() << std::endl;
std::cout << "s1.getn2() = " << s1.getn2() << std::endl;
std::cout << "s2.getn1() = " << s2.getn1() << std::endl;
std::cout << "s2.getn2() = " << s2.getn2() << std::endl;
std::cout << std::endl;
std::cout << "s1のアドレスを代入した抽象クラスへのポインタからのメンバ関数の呼び出し" << std::endl;
psb = &s1;
std::cout << "psb->getn1() = " << psb->getn1() << std::endl;
std::cout << "psb->getn2() = " << psb->getn2() << std::endl;
std::cout << std::endl;
std::cout << "s2のアドレスを代入した抽象クラスへのポインタからのメンバ関数の呼び出し" << std::endl;
psb = &s2;
std::cout << "psb->getn1() = " << psb->getn1() << std::endl;
std::cout << "psb->getn2() = " << psb->getn2() << std::endl;
std::cout << std::endl;
std::cout << "抽象クラスへの参照を使用したオブジェクトs1のメンバ関数の呼び出し" << std::endl;
std::cout << "sbr1.getn1() = " << sbr1.getn1() << std::endl;
std::cout << "sbr1.getn2() = " << sbr1.getn2() << std::endl;
std::cout << std::endl;
std::cout << "抽象クラスへの参照を使用したオブジェクトs2のメンバ関数の呼び出し" << std::endl;
std::cout << "sbr2.getn1() = " << sbr2.getn1() << std::endl;
std::cout << "sbr2.getn2() = " << sbr2.getn2() << std::endl;
std::cout << std::endl;
}
実行結果
$ gcc -Wall sample.cpp -lstdc++
$ ./a.out
クラスオブジェクトからのメンバ関数の呼び出し
s1.getn1() = 100
s1.getn2() = 200
s2.getn1() = 1000
s2.getn2() = 2000
s1のアドレスを代入した抽象クラスへのポインタからのメンバ関数の呼び出し
psb->getn1() = 1 <--- 抽象クラスのメンバ関数
psb->getn2() = 200
s2のアドレスを代入した抽象クラスへのポインタからのメンバ関数の呼び出し
psb->getn1() = 1 <--- 抽象クラスのメンバ関数
psb->getn2() = 2000
抽象クラスへの参照を使用したオブジェクトs1のメンバ関数の呼び出し
sbr1.getn1() = 1 <--- 抽象クラスのメンバ関数
sbr1.getn2() = 200
抽象クラスへの参照を使用したオブジェクトs2のメンバ関数の呼び出し
sbr2.getn1() = 1 <--- 抽象クラスのメンバ関数
sbr2.getn2() = 2000
実行環境
GNU bash, version 5.1.16
GCC-12.2.0
GNU C Library 2.36
GNU Binutils 2.39
GCC-12.2.0
GNU C Library 2.36
GNU Binutils 2.39
コード例・出力内容中の表記
・実行例中の太字表記部分は、コマンドなどの入力された文字列を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。
・「︙」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。