1. ポリモーフィズムの基本概念
ポリモーフィズムは C++ オブジェクト指向の 3 つの主要な機能の 1 つです。ポリモーフィズムは 2 つのカテゴリに分類されます
: 1. 静的ポリモーフィズム: 関数のオーバーロードと演算子オーバーロードは静的ポリモーフィズムに属し、関数名を再利用します。2. 動的ポリモーフィズム: 派生クラスと仮想関数は実行時ポリモーフィズムを実装します
静的ポリモーフィズムと動的ポリモーフィズムの違い:
· 静的ポリモーフィズムの関数アドレスは早期にバインドされます – 関数アドレスはコンパイル段階で決定されます·動的多態性関数アドレスの遅延バインディング - 関数アドレスは実行フェーズ中に決定されます 以下のケースを通して多態性について説明します。
動的多態性が条件を満たしている
1. 継承関係がある
2. サブクラスが親クラスの仮想関数をオーバーライドする。動的ポリモーフィズムは、
親クラスのポインターまたは参照を使用してサブクラス オブジェクトを実行します。書き換え: 関数の戻り値の型、関数名、パラメータ リストが完成しました。これを書き換えと呼びます。
静的多態性コード:
#include <iostream>
using namespace std;
class dongwu {
public:
void speak() {
cout << "动物叫" << endl;
}
};
class cat :public dongwu {
void speak() {
cout << "猫叫" << endl;
}
};
//早绑定,编译阶段就确定函数的地址
void speak(dongwu& p) {
p.speak();
}
void fun() {
cat p;
speak(p);
}
int main() {
fun();
cat p;
//发生隐式转换,只能把儿子转为父亲,退化
dongwu m = p;
m.speak();
return 0;
}
変換に注意してください。早期バインディングの特徴は、息子の関数ではなく、現在の型の関数を実行することです。
動的動的コード:
#include <iostream>
using namespace std;
class dongwu {
public:
//virtual虚函数关键字
virtual void speak() {
cout << "动物叫" << endl;
}
};
class cat :public dongwu {
//子类的virtual可加可不加
virtual void speak() {
cout << "猫叫" << endl;
}
};
//晚绑定,执行子类的函数
void speak(dongwu& p) {
p.speak();
}
void fun() {
cat p;
speak(p);
}
int main() {
fun();
return 0;
}
2. ポリモーフィズムの基本原理
まず次のコードを見てみましょう。
#include <iostream>
using namespace std;
class father1 {
public:
void speak() {
cout << "动物叫" << endl;
}
};
class father2 {
public:
virtual void speak() {
cout << "动物叫" << endl;
}
};
int main() {
cout << sizeof(father1) << endl;
cout << sizeof(father2) << endl;
return 0;
}
クラスのメンバー関数に仮想関数キーワードを追加すると、クラスのサイズが変化していることがわかります。このクラスの内部構造。このとき、クラス内には仮想関数テーブルへのポインタ仮想関数(テーブル)ポインタが追加され、仮想関数テーブルには仮想関数のエントリアドレスが格納されます。
そして、派生クラスが基本クラスを継承する際、メンバー関数の名前が同じでなければ、親クラスの構造を完全に継承します。
ただし、派生クラスが基本関数の仮想関数をオーバーライドすると、派生クラス内の仮想関数テーブルが変更され、このとき、仮想関数テーブルは派生クラスの仮想関数を指し、基本関数の仮想関数は変わります。クラスが上書きされます。
このとき、派生クラスを暗黙的に基底クラスに変換すると、仮想関数テーブルの内容は変化せず、このとき仮想関数が呼び出されると、派生クラスの仮想関数が実行されます。
3. ポリモーフィズムの利点
1. 明確な組織構造
2. 高い可読性
3. 初期および後期の拡張およびメンテナンスのための高メンテナンス
一般的なコンピュータのカテゴリ:
#include <iostream>
using namespace std;
class jisuanqi {
public:
int a, b;
int jisuan(string fu) {
if (fu == "+") {
return a + b;
}
else if (fu == "-") {
return a - b;
}
else if (fu == "*") {
return a * b;
}
}
};
void fun() {
jisuanqi q;
q.a = 200;
q.b = 100;
cout << q.a << " - " << q.b << " = " << q.jisuan("-") << endl;
cout << q.a << " + " << q.b << " = " << q.jisuan("+") << endl;
cout << q.a << " * " << q.b << " = " << q.jisuan("*") << endl;
}
int main() {
fun();
return 0;
}
ポリモーフィック コンピューター クラス:
#include <iostream>
using namespace std;
class jisuanqi {
public:
int a;
int b;
virtual int jisuan() {
return 0;
}
};
class add :public jisuanqi {
virtual int jisuan() {
return a+b;
}
};
class jian :public jisuanqi {
virtual int jisuan() {
return a - b;
}
};
class cheng:public jisuanqi {
virtual int jisuan() {
return a * b;
}
};
void fun() {
jisuanqi* p = new add;
p->a = 200;
p->b = 100;
cout << p->a << " + " << p->b << " = " << p->jisuan()<<endl;
delete p;
p = new jian;
p->a = 200;
p->b = 100;
cout << p->a << " - " << p->b << " = " << p->jisuan()<<endl;
delete p;
p = new cheng;
p->a = 200;
p->b = 100;
cout << p->a << " * " << p->b << " = " << p->jisuan()<<endl;
delete p;
}
int main() {
fun();
return 0;
}
4. 純粋仮想関数と抽象クラス
ポリモーフィズムでは通常、親クラスに仮想関数を実装することは無意味で、主にサブクラスで書き換えた内容を呼び出すため、仮想関数を純粋な仮想関数に変更することができます。クラスに純粋仮想関数がある場合、そのクラスは抽象クラスとも呼ばれます。
純粋仮想関数の構文: 仮想戻り値型関数名: (パラメータ リスト) = 0;
抽象クラスの特性:
· オブジェクトをインスタンス化できません
· サブクラスは抽象クラス内の純粋仮想関数をオーバーライドする必要があります。それ以外の場合は、この関数も抽象クラスに属します。
コード:
#include <iostream>
using namespace std;
class father {
public:
//纯虚函数
virtual void fun() = 0;
};
class son :public father{
public:
void fun() {
cout << "我是sond" << endl;
}
};
void fun() {
//多态f必须是指针或者引用
//father f; 报错不可实例化
father* f = new son;
f->fun();
}
int main() {
fun();
return 0;
}
ドリンクケース製作:
#include <iostream>
using namespace std;
class father {
public:
virtual void zhushui() = 0;
virtual void chongpao() = 0;
virtual void daoru() = 0;
virtual void jialiao() = 0;
void fun() {
zhushui();
chongpao();
daoru();
jialiao();
}
};
class tea :public father{
void zhushui() {
cout << "煮山泉水" << endl;
};
void chongpao() {
cout << "冲茶" << endl;
};
void daoru() {
cout << "倒入茶杯中" << endl;
};
void jialiao() {
cout << "加入枸杞" << endl;
};
};
class kafei : public father{
void zhushui() {
cout << "煮水" << endl;
};
void chongpao() {
cout << "冲咖啡" << endl;
};
void daoru() {
cout << "倒入咖啡杯中" << endl;
};
void jialiao() {
cout << "加入奶和糖" << endl;
};
};
//函数接口
void fun(father* p) {
p->fun();
delete p;
}
int main() {
fun(new tea);
cout << "----------" << endl;
fun(new kafei);
return 0;
}
5. 仮想破壊と純粋仮想破壊
ポリモーフィズムを使用する場合、サブクラスにヒープ領域に割り当てられた属性がある場合、親クラス ポインタは解放時にサブクラスのデストラクタ コードを呼び出すことができません
。親クラスのデストラクターを仮想デストラクターまたは純粋な仮想デストラクターに変更します。
仮想破壊と純粋仮想破壊の共通点:
・親クラスのポインタがサブクラスオブジェクトを解放する問題を解決できる ・両方とも特定の関数の実装が必要
仮想破壊と純粋仮想破壊の違い:
·純粋仮想破壊の場合、クラスは抽象クラスとなり、オブジェクトをインスタンス化できません。
コード:
#include <iostream>
using namespace std;
class father {
public:
//纯虚函数
virtual void fun() =0;
father() {
cout << "father构造函数" << endl;
}
~father() {
cout << "father析构函数" << endl;
}
};
class son :public father {
public:
//堆区开辟数据
son(int age) {
cout << "son构造函数" << endl;
this->age = new int(age);
}
~son() {
cout << "son析构函数" << endl;
if (this->age != NULL) {
delete age;
age = NULL;
}
}
void fun() {
cout << *age<< "son的fun函数调用" << endl;
}
int* age;
};
void fun() {
father* p = new son(21);
delete p;
}
int main() {
fun();
return 0;
}
図に示すように、ポリモーフィズムが発生した場合、サブクラスにヒープ領域に空き領域がある場合、基底クラスはサブクラスのデストラクタを呼び出しません。メモリリークの原因となります。このとき、問題を解決するには、仮想破壊または純粋仮想破壊が必要です。
仮想デストラクター コード:
#include <iostream>
using namespace std;
class father {
public:
//纯虚函数
virtual void fun() =0;
father() {
cout << "father构造函数" << endl;
}
virtual ~father() {
cout << "father析构函数" << endl;
}
};
class son :public father {
public:
//堆区开辟数据
son(int age) {
cout << "son构造函数" << endl;
this->age = new int(age);
}
~son() {
cout << "son析构函数" << endl;
if (this->age != NULL) {
delete age;
age = NULL;
}
}
void fun() {
cout << *age<< "son的fun函数调用" << endl;
}
int* age;
};
void fun() {
father* p = new son(21);
delete p;
}
int main() {
fun();
return 0;
}
純粋な仮想破壊:
#include <iostream>
using namespace std;
class father {
public:
//纯虚函数
virtual void fun() =0;
father() {
cout << "father构造函数" << endl;
}
virtual ~father() = 0;
};
//纯虚函数必须
father::~father()
{
cout << "father析构函数" << endl;
}
class son :public father {
public:
//堆区开辟数据
son(int age) {
cout << "son构造函数" << endl;
this->age = new int(age);
}
~son() {
cout << "son析构函数" << endl;
if (this->age != NULL) {
delete age;
age = NULL;
}
}
void fun() {
cout << *age<< "son的fun函数调用" << endl;
}
int* age;
};
void fun() {
father* p = new son(21);
delete p;
}
int main() {
fun();
return 0;
}
ケースコンピュータ
#include <iostream>
using namespace std;
class CPU {
public:
//纯虚函数
virtual void func() = 0;
};
class Memory_Module {
public:
//纯虚函数
virtual void func() = 0;
};
class Graphics_card {
public:
//纯虚函数
virtual void func() = 0;
};
class CPU_intel : public CPU {
public:
void func() {
cout << "intel的CPU工作" << endl;
}
};
class Graphics_card_intel : public Graphics_card {
public:
void func() {
cout << "intel的显卡工作" << endl;
}
};
class Memory_Module_intel : public Memory_Module {
public:
void func() {
cout << "intel的内存条工作" << endl;
}
};
class CPU_lenovo: public CPU {
public:
void func() {
cout << "联想的CPU工作" << endl;
}
};
class Graphics_card_lenovo : public Graphics_card {
public:
void func() {
cout << "联想的显卡工作" << endl;
}
};
class Memory_Module_lenovo : public Memory_Module {
public:
void func() {
cout << "联想的内存条工作" << endl;
}
};
class computer {
public:
//当传入的是子类时发生多态
computer() {};
computer(CPU* CPU , Memory_Module* m, Graphics_card* g) {
this->cpu = CPU;
this->m = m;
this->g = g;
}
void work() {
cpu->func();
m->func();
g->func();
}
private:
CPU* cpu;
Memory_Module* m;
Graphics_card* g;
};
void fun() {
CPU_lenovo* c1 = new CPU_lenovo;
CPU_intel* c2 = new CPU_intel;
Graphics_card_intel* g1 = new Graphics_card_intel;
Graphics_card_lenovo* g2 = new Graphics_card_lenovo;
Memory_Module_intel* m1 = new Memory_Module_intel;
Memory_Module_lenovo* m2 = new Memory_Module_lenovo;
cout << "第一台电脑" << endl;
computer* com = new computer(c1,m1,g1);
com->work();
cout << "********************************" << endl;
cout << "第二台电脑" << endl;
computer* com1 = new computer(c2, m2, g2);
com1->work();
}
int main() {
fun();
return 0;
}