Loose-Info.com
Last Update 2023/11/04
TOP - 各種テスト - C++ - 派生クラス

概要

単一継承
複数の基本クラス
仮想関数
抽象クラス


単一継承


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


コード例・出力内容中の表記

・実行例中の太字表記部分は、コマンドなどの入力された文字列を示します。
・「」や「...」の着色省略表記は、 実際のソースコードや出力内容などを省略加工した部分を示します。