[C++] Características básicas de la herencia (definición, conversión de asignaciones, amigos, miembros estáticos, herencia virtual, funciones de miembros predeterminadas, alcance)


1. Definición de herencia

Permite a los programadores ampliar y agregar funciones manteniendo las características de la clase original, generando así una nueva clase, llamada clase derivada.

1. Definir el formato

Insertar descripción de la imagen aquí
Persona es la clase principal, también llamada clase base. Student es una subclase, también llamada clase derivada.

2. Cambios en los métodos de acceso de los miembros de la clase base heredada.

Insertar descripción de la imagen aquí
Resumir:

  1. Los miembros privados de una clase base no son visibles en las clases derivadas sin importar cómo se hereden . Invisible aquí significa que los miembros privados de la clase base todavía se heredan en el objeto de clase derivada, pero la sintaxis restringe el acceso del objeto de clase derivada ya sea dentro o fuera de la clase.
    Insertar descripción de la imagen aquí

  2. No se puede acceder a los miembros privados de la clase base en la clase derivada. Si no desea que se acceda al miembro de la clase base directamente fuera de la clase, pero necesita ser accesible en la clase derivada, se define como protegido . Se puede ver que el calificador de miembro protegido se debe a herencia.

  3. Los miembros privados de la clase base no son visibles en la subclase. El método de acceso de otros miembros de la clase base en la subclase == Min (calificador de acceso del miembro en la clase base, método de herencia), público > protegido > privado.

  4. El método de herencia predeterminado cuando se usa la clase de palabras clave es privado , y el método de herencia predeterminado cuando se usa struct es público , pero es mejor escribir el método de herencia explícitamente.

  5. En aplicaciones reales, generalmente se usa la herencia pública, rara vez se usa la herencia protegida/privada y no se recomienda la herencia protegida/privada.

2. Conversión de asignación de objetos de clase base y clase derivada

1. Los objetos de clase derivados se pueden asignar a objetos de clase base/punteros de clase base/referencias de clase base. Aquí hay un término vívido llamado rebanar o cortar. Significa cortar la parte de la clase principal de la clase derivada y asignársela.
2. Los objetos de clase base no se pueden asignar a objetos de clase derivada.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

3. Alcance de la herencia

1. En el sistema de herencia, las clases base y las clases derivadas tienen alcances independientes.

2. Hay miembros con el mismo nombre en la subclase y en la clase principal.

Si hay miembros con el mismo nombre en la subclase y en la clase principal, los miembros de la subclase bloquearán el acceso directo de la clase principal a los miembros con el mismo nombre. Esta situación se llama ocultación, también llamada redefinición. (En funciones de miembros de subclase, puede usar la clase base::miembros de la clase base para acceso explícito)
Insertar descripción de la imagen aquí

3. Ocultación de funciones miembro.

Cabe señalar que si se trata de ocultar una función miembro, solo los nombres de las funciones deben ser los mismos para constituir la ocultación.
Insertar descripción de la imagen aquí

4. Tenga en cuenta que en la práctica es mejor no definir miembros con el mismo nombre en el sistema de herencia.

Cuarto, la función miembro predeterminada de la clase derivada.

Clase base (clase principal):

class Person {
    
    
public:
	Person(const char*name)
		:_name(name)
	{
    
    
		cout << "Person()" << endl;
	}
	Person(const Person& p)
		:_name(p._name)
	{
    
    
		cout << "Person(const Person&p)" << endl;
	}
 
	Person& operator=(const Person& p) {
    
    
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p) {
    
    
			_name = p._name;
		}
		return *this;
	}

	~Person() {
    
    
		cout << "~Person()" << endl;
	}
protected:
	string _name;
};

Clases derivadas (subclases)

class Student :public Person {
    
    
public:
	Student(const char*name="张三", int id = 0)
		//派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。
		:Person(name)
		,_id(id)
	{
    
    }

	Student(const Student& s) 
		// 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
		:Person(s)//切割
		,_id(s._id)
	{
    
    }

	Student& operator=(const Student& s) {
    
    
		//派生类的operator = 必须要调用基类的operator = 完成基类的复制
		if (this != &s) {
    
    
			Person::operator=(s);//发生切割
			_id = s._id;
		}
		return *this;
	}
		~Student()
	{
    
    
		// 析构函数的函数名被
		// 特殊处理了,统一处理成destructor

		// 显示调用父类析构,无法保证先子后父
		// 所以子类析构函数完成就,自动调用父类析构,这样就保证了先子后父
		 
		//析构函数:先析构子类后析构父类
		//构造函数:先构造父类后构造子类
	}

protected:
	int _id;
};

Resultados de ejecución:
Insertar descripción de la imagen aquí
Resumen:

  1. El constructor de la clase derivada debe llamar al constructor de la clase base para inicializar esa parte de los miembros de la clase base. Si la clase base no tiene un constructor predeterminado , se debe llamar explícitamente durante la fase de lista de inicialización del constructor de la clase derivada.
  2. El constructor de copia de la clase derivada debe llamar al constructor de copia de la clase base para completar la inicialización de la copia de la clase base.
  3. El operador de la clase derivada debe llamar al operador de la clase base para completar la copia de la clase base.
  4. El destructor de la clase derivada llamará automáticamente al destructor de la clase base para limpiar los miembros de la clase base después de ser llamado. Porque esto puede
    garantizar que el objeto de clase derivada limpie primero los miembros de la clase derivada y luego los miembros de la clase base.
  5. Al inicializar un objeto de clase derivada, primero se llama al constructor de la clase base y luego al constructor de la clase derivada.
  6. Para limpiar el destructor de objetos de clase derivada, primero llame al destructor de la clase derivada y luego llame al destructor de la clase base.

Insertar descripción de la imagen aquí

5. Herencia y amistad

Las relaciones de amigos no se pueden heredar, lo que significa que los amigos de la clase base no pueden acceder a miembros privados y protegidos de las subclases.
Insertar descripción de la imagen aquí
Para un funcionamiento normal, las clases derivadas también deben agregar amigos.

6. Herencia y miembros estáticos.

Si la clase base define miembros estáticos, solo habrá uno de esos miembros en todo el sistema de herencia. No importa cuántas subclases se deriven, solo hay una instancia de miembro estático.

Insertar descripción de la imagen aquí

7. Herencia virtual de diamantes

1. Herencia de diamantes

Insertar descripción de la imagen aquí
Problemas con la herencia de diamantes: a partir de la construcción del modelo de miembro de objeto a continuación, podemos ver que la herencia de diamantes tiene problemas con la redundancia y ambigüedad de los datos. Habrá dos copias del miembro Persona en el objeto Asistente.
Insertar descripción de la imagen aquí

2.Herencia virtual

La herencia virtual puede resolver los problemas de ambigüedad y redundancia de datos de la herencia de diamantes. Como se muestra en la relación de herencia anterior, el uso de la herencia virtual cuando el Estudiante y el Profesor heredan la Persona puede resolver el problema. Cabe señalar que la herencia virtual no debe utilizarse en ningún otro lugar.
Insertar descripción de la imagen aquí

3. El principio de herencia virtual del rombo:

class A
{
    
    
public:
 int _a;
};
// class B : public A
class B : virtual public A
{
    
    
public:
 int _b;
};
// class C : public A
class C : virtual public A
{
    
    
public:
 int _c;
};
class D : public B, public C
{
    
    
public:
 int _d;
};
int main()
{
    
    
 D d;
 d.B::_a = 1;
 d.C::_a = 2;
 d._b = 3;
 d._c = 4;
 d._d = 5;
 return 0;
}

1. Distribución de la memoria de la herencia de diamantes.

La siguiente figura es el modelo de miembro de objeto de memoria de la herencia de diamantes: aquí puede ver la redundancia de datos
Insertar descripción de la imagen aquí

2. Distribución de memoria de herencia virtual

La siguiente figura es el modelo de miembro de objeto de memoria de la herencia virtual de diamante: aquí podemos analizar que en el objeto D, A se coloca en la parte inferior de la composición del objeto. Esta A pertenece tanto a B como a C. Entonces, ¿cómo funcionan B y C? ¿Encontrar la A común? Aquí hay una tabla señalada por los dos punteros 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 continuación se puede encontrar el desplazamiento.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/m0_74774759/article/details/132104793
Recomendado
Clasificación