Herencia de herencia en forma de diamante en C ++ [gráfico super detallado + código]

 

 


Prefacio

Decíamos en el artículo anterior que todo en el mundo tiene un sistema de herencia. Más o menos subclases heredan ciertas características de la clase padre, pero la mayoría de ellas son herencia unidireccional, pero hay algunas excepciones que son herencia múltiple, como:

Podemos ver en la imagen que los anfibios han heredado parte de las características de los animales acuáticos y algunas de las características de los animales terrestres. ¿Nuestro código también tendrá este tipo de herencia múltiple? Levántate y echa un vistazo.


Sugerencia: El siguiente es el contenido de este artículo, los siguientes casos son para referencia

1. ¿Qué es la herencia múltiple?

1. Herencia única

  Echemos un vistazo a un diagrama para comprender primero la herencia única y luego veamos la diferencia

En otras palabras, cuando una subclase tiene solo una clase principal directa, la relación de herencia se denomina herencia única.

 

2. Herencia múltiple

A esta herencia la llamamos herencia múltiple cuando una subclase tiene dos o más padres directos

Echemos un vistazo al código para ver qué problemas existen en la herencia múltiple.

//基类A
class A 
{
public:
    A() :m_data(1)
    {
    }
    ~A(){}

public:
    int m_data;      //同名变量
   
};
//基类B
class B
{
public:
    B() :m_data(1)
    {
    }
    ~B(){}

public:
    int m_data;      //同名变量
    
};

class C  : public A, public B
{

};

int main()
{
    C Data;
   //Data.m_data  = 10;   //错误, 提示指向不明确  不能够分辨m_data到底是谁的
   //只有通过域成员运算符给其明确指出才可以访问,
    Data.A::m_data = 5; 
    Data.B::m_data =10;
    
    std::cout << Data.A::m_data << "   " << Data.B::m_data << std::endl;

    return 0;
}

 

Por el código anterior es obvio que vemos fuera , problemas de ambigüedad de sistema de herencia múltiple . Significa que si hay un miembro de datos con el mismo nombre, entonces no se puede leer directamente por el nombre de la variable y debe ser distinguido por el operador del miembro de dominio (: :)

Es como si una persona le dijera que le envíe algo al maestro. Con tantos maestros, no se puede estar seguro de a qué maestro se refiere. Debe nombrarlo por su nombre para que podamos distinguirlo. Una verdad

Segundo, herencia de diamantes

Primero hagamos un dibujo para entender lo que se llama herencia de diamantes.

 

A este tipo de herencia le llamamos herencia de diamantes.

Entonces, ¿qué tipo de problemas surgirán con este sistema de herencia? Echemos un vistazo específicamente a través del siguiente código.

//  菱形继承 菱形继承是多继承的一种特殊情况。
//菱形继承的问题:从下面的对象成员模型构造,可以看出菱形继承有数据冗余和二义性的问题。


class A
{
public:
	int m_a = 1;
};
class B :public A
{
public:
	int m_b = 2;
};
class C :public A
{
public:
	int m_c = 3;
};
class D :public B, public C
{
public:
	int m_d = 4;
};
void main()
{
	D d;
	d.m_d = 40;
	d.m_c = 30;
	d.m_b = 20;
	//.m_a = 10;//  二义性
	// 不能够访问  因为B 和C分别继承了A的m_a
	//但是D 继承了B和C的m_a 所以D不能够分辨m_a到底是谁的
	d.B::m_a = 100;
	d.C::m_a = 200;
	// 这样的话 就造成了m_a 有两个空间  一个B的100  一个C的200
}

Con base en la situación anterior, no es difícil ver que también hay ambigüedad de datos en la herencia de diamantes, que aquí se debe a que indirectamente se tiene la misma clase base . Además de la ambigüedad de este tipo de herencia de diamantes , habrá redundancia de datos y pérdida de espacio de memoria .

Qué es el desperdicio de espacio y la redundancia de datos, hagamos un dibujo para mostrarlo.

Entonces, ¿cómo resolver este problema?

1. La introducción de clases base virtuales

La clase base virtual se introduce en C ++ , cuya función es  retener solo un miembro de la clase base cuando se hereda indirectamente la clase base común.

Echemos un vistazo al código.

class A
{
public:
	int m_a = 1;
};
class B :virtual public A
{
public:
	int m_b = 2;
};
class C :virtual public A
{
public:
	int m_c = 3;
};
class D :public B, public C
{
public:
	int m_d = 4;
};
void main()
{
	D d;
	d.m_d = 40;
	d.m_c = 30;
	d.m_b = 20;
	d.m_a = 100;//  让B C虚拟继承 A 加关键字virtual
}

Podemos ver que el problema de la ambigüedad y la redundancia de datos está muy bien resuelto, entonces, ¿cómo lo hace específicamente?

2. La introducción de la mesa base virtual

Aquí hay una tabla señalada por los dos punteros de B y C. Estos dos punteros se denominan punteros de tabla base virtual y estas dos tablas se denominan tablas base virtuales. El desplazamiento almacenado en la tabla base virtual. A se puede encontrar por el desplazamiento.

Específicamente, hacemos un dibujo.

El BC aquí es como dos personas en dos lugares diferentes, pero tienen que ir al lugar A y guardar la dirección de A, luego puedes usar el mapa para navegar, pero debido a que las dos personas están en lugares diferentes, ve a A La distancia definitivamente será diferente, es decir, el desplazamiento de A definitivamente será diferente ( será más fácil de entender de esta manera).

 

 

para resumir

Mucha gente dice que la sintaxis de C ++ es complicada, pero de hecho, la herencia múltiple es una manifestación. Con herencia múltiple, hay herencia de diamantes, y con herencia de diamantes, hay herencia virtual de diamantes, y la implementación subyacente es muy complicada. Por lo tanto, generalmente no se recomienda diseñar herencia múltiple y no debe diseñar herencia de diamantes. De lo contrario, habrá problemas de complejidad y la herencia virtual de la herencia en forma de diamante también traerá una pérdida de rendimiento (porque se abren más direcciones para almacenar el desplazamiento) .

 

Gracias por leer. Corríjame si hay algún error.

Supongo que te gusta

Origin blog.csdn.net/qq_45615577/article/details/115345490
Recomendado
Clasificación