ダイヤモンド継承の問題: 派生クラスが同時に複数の基本クラスから同じ関数を継承するときに発生する問題は、どの関数のバージョンを呼び出すかを決定できません。解決策: 仮想継承: 基本クラスの仮想テーブル ポインターを作成して、関数呼び出しが常に最も具体的な基本クラス実装を指すようにします。実際のケース: Cylinder クラスは Circle および Rectangle から継承し、仮想継承を使用してひし形の継承を回避し、Cylinder クラスの getArea() 関数実装が常に呼び出されるようにします。
C 関数の継承の詳細な説明: 「ダイヤモンド継承」の扱い
はじめに
関数の継承は、派生クラスが基本クラスの関数にアクセスして再利用できるようにする C の強力な機能です。しかし、複数の基底クラスが同じ機能を持つ場合、「ダイヤモンド継承」と呼ばれる問題が発生する可能性があります。この記事ではダイヤモンドの相続とその解決策について解説し、実際の事例を紹介します。
ダイヤモンドの継承
ダイヤモンドの継承は、派生クラスが 2 つ以上の基本クラスから同じ関数を同時に継承するときに発生します。その結果、派生クラスで呼び出された関数のバージョンを特定できなくなります。
class Base1 { public: void print() { std::cout << "Base1 print" << std::endl; } }; class Base2 { public: void print() { std::cout << "Base2 print" << std::endl; } }; class Derived : public Base1, public Base2 { public: void print() { // 调用哪个基类的 print() 函数? } };
上記の例では、Derived
クラスはBase1
とBase2
を継承しており、どちらの基本クラスも同じprint( )### 関数。
Derived::print()が呼び出されるとき、
Base1::print()と
Base2::print()のどちらが呼び出されるのかを判断できません。
ダイヤモンド継承を回避する
ダイヤモンド継承を回避する一般的な解決策は、仮想継承を使用することです。仮想継承では、基本クラス オブジェクトをコピーする代わりに、基本クラスへの vtable ポインターを作成します。これにより、派生クラスへの関数呼び出しが常に最も具体的な基本クラス実装を指すようになります。class Base1 { public: virtual void print() { std::cout << "Base1 print" << std::endl; } }; class Base2 { public: virtual void print() { std::cout << "Base2 print" << std::endl; } }; class Derived : public virtual Base1, public virtual Base2 { public: void print() override { std::cout << "Derived print" << std::endl; } };
Base1と
Base2が仮想継承を使用します。これにより、
Derived::print()が常に
Derivedクラスの実装を呼び出すようになります。
実践例
グラフィックの面積を計算する例を考えてみましょう。面積を計算するためのgetArea()関数を定義する基本クラス
Shapeがあります。また、形状固有の面積計算を提供する 2 つの派生クラス
Circleと
Rectangleもあります。
class Shape { public: virtual double getArea() = 0; }; class Circle : public Shape { public: Circle(double radius) : _radius(radius) {} double getArea() override { return 3.14 * _radius * _radius; } private: double _radius; }; class Rectangle : public Shape { public: Rectangle(double width, double height) : _width(width), _height(height) {} double getArea() override { return _width * _height; } private: double _width; double _height; };
Circleと
Rectangleを継承する派生クラス
Cylinderを作成しました。ただし、
Circleと
Rectangleの両方に
getArea()関数があるため、
Cylinderはダイヤモンド継承の問題に直面します。
class Cylinder : public Circle, public Rectangle { public: Cylinder(double radius, double height) : Circle(radius), Rectangle(radius, height) {} };
class Cylinder : public virtual Circle, public virtual Rectangle { public: Cylinder(double radius, double height) : Circle(radius), Rectangle(radius, height) {} };
Cylinderクラスの
getArea()関数が常に呼び出されます。派生した最も具体的なクラスの実装 (つまり、
Cylinder)。
以上がC++関数継承の詳細解説:「ダイヤモンド継承」問題を回避するには?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。