Maison > développement back-end > C++ > Explication détaillée de l'héritage des fonctions C++ : Comment éviter le problème de « l'héritage diamant » ?

Explication détaillée de l'héritage des fonctions C++ : Comment éviter le problème de « l'héritage diamant » ?

WBOY
Libérer: 2024-05-02 11:45:02
original
647 Les gens l'ont consulté

Problème d'héritage Diamond : le problème se produit lorsqu'une classe dérivée hérite de la même fonction de plusieurs classes de base en même temps et ne peut pas déterminer quelle version de fonction appeler. Solution : Héritage virtuel : créez un pointeur de table virtuelle de la classe de base pour garantir que les appels de fonction pointent toujours vers l'implémentation de la classe de base la plus spécifique. Cas pratique : La classe Cylindre hérite de Cercle et Rectangle, utilise l'héritage virtuel pour éviter l'héritage diamant et garantit que l'implémentation de la fonction getArea() de la classe Cylindre est toujours appelée.

C++ 函数继承详解:如何避免“钻石继承”问题?

Héritage de fonction C++ Explication détaillée : Gestion de « l'héritage diamant »

Introduction

L'héritage de fonction est une fonctionnalité puissante en C++ qui permet aux classes dérivées d'accéder et de réutiliser les fonctions de la classe de base. Cependant, lorsque plusieurs classes de base ont les mêmes fonctions, un problème appelé « héritage diamant » peut survenir. Cet article abordera l’héritage des diamants et ses solutions, et présentera des cas pratiques.

Héritage Diamant

L'héritage Diamant se produit lorsqu'une classe dérivée hérite de la même fonction de deux classes de base ou plus en même temps. Cela entraîne l’impossibilité de déterminer quelle version de fonction a été appelée dans la classe dérivée.

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() 函数?
    }
};
Copier après la connexion

Dans l'exemple ci-dessus, la classe Derived hérite de Base1 et Base2, les deux classes de base ont le même print () Fonction . Lors de l'appel de Derived::print(), il ne peut pas être déterminé si Base1::print() ou Base2::print() a été appelé . Derived 类从 Base1Base2 继承,这两个基类都有相同的 print() 函数。当调用 Derived::print() 时,无法确定是否调用 Base1::print()Base2::print()

避免钻石继承

避免钻石继承的一个常见解决方案是使用虚继承。虚继承会创建基类的虚表指针,而不是复制基类的对象。这确保了针对派生类的函数调用总是指向最具体的基类实现。

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;
    }
};
Copier après la connexion

在上面的示例中,Base1Base2 使用了虚继承。这确保了 Derived::print() 将始终调用 Derived 类的实现。

实战案例

考虑一个计算图形面积的示例。我们有一个基类 Shape,它定义了计算面积的 getArea() 函数。我们还有两个派生类 CircleRectangle,它们提供形状特定的面积计算。

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;
};
Copier après la connexion

为了实现“套筒”形状,我们创建了一个派生类 Cylinder,它从 CircleRectangle 继承。然而,由于 CircleRectangle 都有 getArea() 函数,因此 Cylinder 将面临钻石继承问题。

class Cylinder : public Circle, public Rectangle {
public:
    Cylinder(double radius, double height) : Circle(radius), Rectangle(radius, height) {}
};
Copier après la connexion

为了避免钻石继承,我们使用虚继承:

class Cylinder : public virtual Circle, public virtual Rectangle {
public:
    Cylinder(double radius, double height) : Circle(radius), Rectangle(radius, height) {}
};
Copier après la connexion

现在,Cylinder 类的 getArea() 函数总是调用它派生的最具体类(即 Cylinder

🎜Éviter l'héritage des diamants🎜🎜🎜Une solution courante pour éviter l'héritage des diamants consiste à utiliser l'héritage virtuel. L'héritage virtuel crée un pointeur vtable vers la classe de base au lieu de copier l'objet de la classe de base. Cela garantit que les appels de fonction à une classe dérivée pointent toujours vers l’implémentation de classe de base la plus spécifique. 🎜rrreee🎜Dans l'exemple ci-dessus, Base1 et Base2 utilisent l'héritage virtuel. Cela garantit que Derived::print() appellera toujours l'implémentation de la classe Derived. 🎜🎜🎜Cas pratique🎜🎜🎜Considérons un exemple de calcul de l'aire d'un graphique. Nous avons une classe de base Shape qui définit la fonction getArea() pour calculer la surface. Nous avons également deux classes dérivées, Circle et Rectangle, qui fournissent des calculs de surface spécifiques à la forme. 🎜rrreee🎜Pour implémenter la forme "manche", nous avons créé une classe dérivée Cylinder, qui hérite de Circle et de Rectangle. Cependant, puisque Circle et Rectangle ont tous deux les fonctions getArea(), Cylinder sera confronté à des problèmes d'héritage de diamant. 🎜rrreee🎜Pour éviter l'héritage diamant, nous utilisons l'héritage virtuel : 🎜rrreee🎜Maintenant, la fonction getArea() de la classe Cylinder appelle toujours la classe la plus spécifique dont elle dérive (c'est-à-dire implémentation de Cylindre). 🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal