Cinco, estilo de programación orientado a objetos

  • La relación entre clases depende del modelo de programación orientada a objetos (modelo de programación orientada a objetos) que se va a establecer.
  • La programación orientada a objetos es el rasgo más importante que se hereda (herencia) y polimorfismo (polimorfismo). El primero organiza un grupo de clases relacionadas para compartir datos y comportamientos operativos comunes, mientras que el segundo nos permite manipular a un solo individuo en lugar de clases independientes, y nos da la flexibilidad de agregar y eliminar cualquier clase específica.
  • El mecanismo de herencia define la relación padre-hijo. La clase padre define todas las subclases de interfaz pública común ( interfaz pública) y la implementación privada (implementación privada). Cada subclase puede agregar o anular lo que hereda para lograr su propio comportamiento único.
  • En C ++, la clase padre se llama clase base (clase base), se llama clase derivada de subclase (clase derivada). La relación entre las clases padre e hijo se llama jerarquías de herencia (jerarquía de herencia). El llamado sistema de herencia se deduce de la parte más abstracta a la parte más concreta.
  • La clase base abstracta ( clase base abstracta) se refiere a aquellas clases base que no representan una categoría real, sino que solo existen para necesidades de diseño y se utilizan para definir comportamientos operativos comunes.
  • El polimorfismo permite que el puntero o la referencia de la clase base apunte de forma transparente a cualquier objeto de clase derivada. A menos que el programa se ejecute realmente en ese momento, es imposible determinar a qué objeto derivado se apunta y la ejecución de la función puede ser diferente cada vez.
  • Enlace dinámico ( enlace dinámico): la operación de análisis "en realidad se llama para averiguar cuál es una función de una clase derivada" se retrasará hasta que se lleve a cabo el tiempo de ejecución.
  • Enlace estático : antes de que se ejecute el programa, se ha resuelto qué función debe llamarse.
  • La característica de herencia nos permite definir un conjunto de clases relacionadas y compartir interfaces comunes. El polimorfismo nos permite usar un tipo independientemente del tipo ( independiente del tipo ) que opera de tal manera que los objetos de clase.
  • Polimorfismo y propiedades de enlace dinámico solo cuando el puntero funciona en uso o referencia.
  • De forma predeterminada, el análisis de la función miembro se realiza de forma estática en el momento de la compilación . Para hacerlo dinámico en tiempo de ejecución , tenemos que agregar una palabra clave antes de su declaración para virtualindicar que es una función virtual .
  • Cuando el programa define un objeto derivado, se ejecutarán el constructor de la clase base y la clase derivada; cuando se destruya el objeto derivado, también se ejecutarán el destructor de la clase base y la clase derivada (pero el orden se invierte, la primera se deriva y luego la base).
  • Al definir una clase derivada, para indicar claramente que la nueva clase hereda de una clase existente , su nombre debe ir :seguido de dos puntos , seguido de la palabra clave publicy el nombre de la clase base . (* La clase base se puede heredar de tres formas: pública, protegida o privada. Este libro solo trata sobre público).
  • Antes de que una clase haga una declaración de herencia, la definición de su clase base ya debe existir (el archivo de encabezado que contiene la definición de la clase base debe incluirse primero).
  • protectedSe puede acceder directamente a todos los miembros declarados como mediante clases derivadas, excepto que no pueden acceder directamente a miembros protegidos.
  • public, protected, privateMétodos de herencia Tres correspondientemente, que cambian los atributos de acceso de los miembros de la clase de base:
    • Herencia pública : los atributos de acceso de los miembros públicos de la clase base, miembros protegidos y miembros privados pasan a ser: público, protegido, privado en la clase derivada;
    • Herencia protegida : los atributos de acceso de los miembros públicos de la clase base, los miembros protegidos y los miembros privados de la clase derivada pasan a ser: protegido, protegido, privado;
    • Herencia privada : los atributos de acceso de los miembros públicos de la clase base, los miembros protegidos y los miembros privados se vuelven privados, privados y privados en la clase derivada.
  • Pero no importa qué tipo de método de herencia, los siguientes dos puntos no han cambiado:
    • Solo los miembros de esta clase (dentro de la clase) y amigos pueden acceder a los miembros privados, y las clases derivadas no pueden acceder a ellos;
    • Se puede acceder a los miembros protegidos mediante clases derivadas.
  • El modificador de acceso predeterminado para miembros y clases es private.
  • Cuando se utiliza una clase derivada, no es necesario distinguir deliberadamente entre miembros heredados y miembros autodefinidos. El uso de ambos es completamente transparente.
  • Los pasos para definir una clase base abstracta:
    • El primer paso: descubra los comportamientos operativos comunes de todas las subclases Estos comportamientos representan la interfaz pública de la clase base.
    • Paso dos: Intente averiguar qué comportamiento operativo y el tipo de relacionado (dependiente del tipo), es decir, el comportamiento de qué operaciones deben tener diferentes implementaciones dependiendo de la clase derivada. Estos comportamientos deberían convertirse en funciones virtuales en todo el sistema de herencia de clases . * Una función miembro estática no se puede declarar como función virtual.
    • Paso 3: Intente encontrar el nivel de acceso de cada operación . Si se puede acceder al programa general public; si no es necesario usarlo fuera de la clase base, entonces sí private(incluso la clase derivada de la clase base no puede acceder al miembro privado en la clase base); se puede acceder a la clase derivada pero no se permite el acceso al programa general protected.
  • La asignación de un valor de función virtual la 0convierte en una función virtual pura; para esta clase, esta función virtual no tiene un significado real. La función virtual pura no tiene una definición de función y la interfaz está incompleta.
  • Si alguna clase declara una (o más) funciones virtuales puras, el programa no puede generar ningún objeto para ella. Este tipo de clase solo se puede utilizar como un subobjeto de su clase derivada , y la premisa es que estas clases derivadas deben proporcionar definiciones exactas para todas las funciones virtuales.
  • De acuerdo con las reglas generales, cuando una clase base define una (o más) funciones virtuales, su destructor debe declararse como virtual:
//定义基类指针ps指向派生类Fibonacci的对象 
num_sequence *ps = new Fibonacci(12);
//...使用数列
delete ps; 


/*
当delete表达式应用于ps时,destructor会先应用于ps所指
的对象身上,于是此对象占用的内存空间归还。 

non-virtual函数在编译时便已完成解析,所以ps调用的
destructor一定是Fibonacci的,而不是基类的。 

正确做法是根据实际对象的类型选择调用哪一个destructor, 
因此解析操作应该在运行时进行。 
*/ 
  • La clase derivada se compone de dos partes: el subobjeto de la clase base (compuesto por el miembro de datos no estático de la clase base) + la parte de la clase derivada (compuesta por el miembro de datos no estático del derivado clase).
  • La función virtual de la clase derivada debe coincidir exactamente con el prototipo de función en la clase base. Al definir una función virtual fuera de la clase, no es necesario especificar la palabra clave virtual.
  • Al especificar el objeto de llamada a través del operador de alcance de clase, el mecanismo de función virtual se puede omitir , de modo que la función se puede resolver por completo en tiempo de compilación, en lugar de esperar hasta el tiempo de ejecución.
  • Cada clase derivada tiene un miembro con el mismo nombre que el miembro de la clase base, que ocultará el miembro de la clase base. Si desea utilizar el miembro heredado en una clase derivada , debe utilizar el operador de ámbito de clase para calificar .
  • Si la función del mismo nombre en la clase base y la clase derivada no es virtual , entonces cada vez que se llama a la función a través del puntero o referencia de la clase base, la copia analizada es la copia de la clase base.
  • El miembro de datos elige el puntero o la referencia:
    • La referencia debe inicializarse en la lista de inicialización de miembros del constructor. Una vez inicializado, ya no puede apuntar a otro objeto.
    • El puntero se puede inicializar en el constructor, o se puede inicializar a nulo y luego hacer que apunte a una dirección de memoria válida.
  • El constructor de la clase derivada no solo debe inicializar el miembro de datos de la clase derivada, sino que también debe proporcionar valores apropiados para el miembro de datos de su clase base .
  • A diferencia del constructor, el destructor de la clase base se llamará automáticamente después de que finalice el destructor de la clase derivada. No es necesario llamarlo explícitamente en la clase derivada.
  • Si heredamos una función virtual pura, esta clase derivada también se considerará una clase abstracta y no se podrán definir objetos para ella.
  • Si la cobertura proporcionada por la función virtual de clase base, entonces la nueva clase derivada define su función prototipo debe proporcionar declaración de clase base prototipo de función de cumplimiento completo : lista de parámetros, tipo de retorno, const (const-ness).
    • Excepción: cuando la función virtual de la clase base devuelve una forma de la clase base (normalmente puntero o referencia), la función del mismo nombre en la clase derivada puede devolver el tipo derivado de la clase base:
      class num_sequence {
              
              
      public:
      	//派生类的clone()函数可以返回一个指针
      	//指向num_sequence的任何一个派生类 
      	virtual num_sequence *clone() = 0;
      	
      	//...
      }; 
      
      class Fibonacci : public num_sequence  {
              
              
      public:
      	//Fibonacci派生自num_sequence
      	//在派生类中,关键字virtual并非必要
      	Fibonacci *clone() {
              
               return new Fibonacci( *this ); }
      	
      	//... 
      };
      
  • Cuando una clase derivada anula una función virtual y realiza una operación de declaración, no es necesario agregar palabras clave virtual. El compilador determinará si una función anulará la función del mismo nombre de su clase base basándose en la declaración del prototipo de las dos funciones .
  • Excepciones al mecanismo de función virtual: (1) en el constructor y destructor de la clase base, (2) cuando se usa el objeto de la clase base en lugar del puntero o referencia del objeto de la clase base.

Cuando construimos un objeto de clase derivada, primero se llama al constructor de la clase base. Si se llama a una función virtual en el constructor de la clase base, ¿se llamará a la definida por la clase derivada?
Respuesta: No. En este momento, el miembro de datos de la clase derivada no se ha inicializado y la llamada puede acceder al miembro de datos no inicializado en este momento. Por lo tanto, en el constructor de la clase base, nunca se llamará a la función virtual de la clase derivada. . Lo mismo es cierto para llamar a funciones virtuales en el destructor de la clase base.

Para poder mostrar varios tipos en un solo objeto, el polimorfismo requiere un nivel de direccionamiento indirecto.
En C ++, solo los punteros y referencias con clases base pueden soportar el concepto de programación orientada a objetos.

void print (LibMat object,
			const LibMat *pointer,
			const LibMat &reference)
{
    
    
	//以下必定调用LibMat::print()
	object.print();
	
	//以下一定会通过虚函数机制来进行解析,
	//我们无法预知哪一个派生类的print()被调用
	pointer->print();
	reference.print(); 
} 

int main()
{
    
    
	AudioBook iWish("Her Pride of 10",
					"Stanley Lippman",
					"Jeremy Irons");
	print( iWish, &iWish, iWish );
	//...
}

Como se muestra arriba, declaramos un objeto real ( print()el primer parámetro) para la clase base y al mismo tiempo asignamos suficiente espacio de memoria para acomodar el objeto real . Si un objeto de clase derivada ( AudioBook) se pasa más tarde , no hay suficiente memoria para colocar cada miembro de datos en la clase derivada.
Solo los subobjetos de la clase baseiWish interna (es decir , los componentes a los que pertenecen ) se copian en la memoria reservada para el objeto de parámetro, y los demás subobjetos se cortan. En cuanto a los otros dos parámetros y , se encuentra la dirección de memoria inicializada del objeto. Este es el punto en el que pueden completar la asignatura de razón.LibMat
pointerreferenceiWishAudioBook

  • typeidLos operadores, compatibles con el lenguaje de programación, son parte del mecanismo de identificación de tipo en tiempo de ejecución (RTTI). Consultemos el puntero de clase polimórfica o la referencia de clase para obtener el tipo real del objeto al que se refiere.
  • Archivo de encabezado #include <typeinfo>. typeidEl operador devuelve un objeto type_info , que almacena diversa información relacionada con el tipo. Cada clase polimórfica corresponde a un objeto type_info , y la name()función de este objeto devuelve un carácter constante * para representar el nombre de la clase.
    #include <typeinfo>
    
    inline const char* num_sequence:: what_am_i() const
    {
          
          
    	return typeid( *this ).name();
    }
    
  • La clase type_info también admite dos operaciones de comparación para igualdad y desigualdad.
  • static_cast<>De hecho, es potencialmente peligroso, porque el compilador no puede confirmar si la operación de conversión que realizamos es completamente correcta. dynamic_castEl operador proporciona conversión condicional y es un operador RTTI.
  • La clase base concreta es opuesta a la clase base abstracta, que puede representar los objetos que realmente existen en la aplicación.
  • La función miembro es una función especial. Ambos tienen tipos de retorno, nombres de funciones, listas de parámetros y definiciones de funciones. Sin embargo, la función miembro está asociada a una determinada clase, puede ser virtual, constante o estática .......
  • El constructor en sí es un tipo especial de función miembro.

Supongo que te gusta

Origin blog.csdn.net/pppppppyl/article/details/114155754
Recomendado
Clasificación