C ++ Primer Capítulo 13 Herencia de clases

1. La clase derivada no puede acceder directamente a los miembros privados de la clase base y debe hacerlo a través del método de la clase base. La clase derivada puede acceder directamente (llamar) a los métodos de clase pública de la clase base.

   Al crear un objeto de clase derivada, el programa primero crea el objeto de clase base. El constructor de clase derivada debe usar el constructor de clase base. 

class TablePlayer{ //基类声明,在.h文件中
private: 
  string  firstname;
  string lastname;
public:
  TablePlayer(const string & fn="none", const string & ln="none");
  void Name() const;
};
//方法的实现在.cpp文件中
TablePlayer::TablePlayer(const string & fn, const string & ln) : firstname(fn), 
                         lastname(ln) {}   //成员初始化列表法
void TablePlayer::Name() const
{ std::cout<<lastname<<","<<firstname }   

class ReatedPlayer: public TablePlayer{ //公有派生类
private:
  unsigned int rating;
public:
  ReatedPlayer(unsigned int r, const string & fn="none",
               const string & ln="none") 
  ReatedPlayer(unsigned int r,const TablePlayer & tp); //
  unsigned int Rating() const {return rating; }
};
//派生类的构造函数
ReatedPlayer::ReatedPlayer(unsigned int r, const string & fn,
        const string & ln) : TablePlayer(fn,ln) //将fn,ln参数从派生类构造函数传递到基类构造函数
{
  rating=r;
}

ReatedPlayer::ReatedPlayer(unsigned int r, const string & fn,
        const string & ln) //未调用基类构造函数时,等效于使用默认构造函数  : TablePlayer() 
{
  rating=r;
}

 ReatedPlayer::ReatedPlayer(unsigned int r,const TablePlayer & tp):TablePlayer(tp)
{ 
  rating=r;
}
 ReatedPlayer::ReatedPlayer(unsigned int r,const TablePlayer & tp):
     TablePlayer(tp),rating(r) {} 
int main (void){
 using std::cout; using std::endl;
 TablePlayer player1("Bob", "Boomede");
 RatedPlayer rplayer1(1140, "Mallay","Duck"); //创建派生类对象
 rplayer1.Name(); //派生类可以直接调用基类的公有类方法
}

2. Los objetos y direcciones de clases derivadas se pueden asignar a punteros y referencias de clase base. Pero no puede asignar objetos y direcciones de clases base a referencias y punteros de clases derivadas

 TablePlayer & rt = rplayer; TablePlayer * pt = & rplayer; (合法)

3. Tres tipos de herencia en C ++: herencia pública, herencia protegida y herencia privada. Herencia pública (es una relación significa que el objeto de clase derivada también es un objeto de clase base)

  La herencia puede agregar atributos a la clase base, pero no puede eliminar los atributos de la clase base.

4. El comportamiento del mismo método en la clase derivada y en la clase base es diferente, es decir, el comportamiento del mismo método varía con el contexto, este comportamiento se denomina polimorfismo.

  •    Hay dos formas de implementar la herencia pública polimórfica: 1) Redefinir la clase base en la clase derivada 2) Usar métodos virtuales (anteponer la palabra clave virtual al declarar la función).
  •  Declare los métodos redefinidos de la clase derivada como métodos virtuales en la clase base (el programa elegirá la versión del método según el tipo de objeto en lugar del tipo de referencia o puntero)
  • Una vez que un método se declara como función virtual en la clase base, automáticamente se convertirá en una función virtual en la clase derivada (también se puede agregar virtual para indicar cuáles son funciones virtuales).
  • También es una convención declarar un destructor virtual para la clase base. [Asegúrese de llamar al destructor en el orden correcto cuando libere el objeto de clase derivada. Primero llame al destructor de la clase derivada, luego llame al constructor de la clase base] Análisis: eliminar pt; Al liberar memoria, primero aplique el destructor predeterminado de la clase derivada, libere la memoria del objeto de la clase derivada y luego llame al destructor virtual en la clase base Para liberar memoria. Si no declara el destructor virtual en la clase base y llama directamente al destructor de la clase base, solo se liberará una parte de la memoria y la memoria apuntada por el nuevo miembro de la clase en la clase derivada no se liberará.
/*基类Brass公有成员函数ViewAcct声明前无virtual*/
 Brass dom(" Dominic Banker",1121,4182.45);//基类对象
 BrassPlus dot("Doroty Banker",1238,2592.00);//派生类对象
 Brass & b1=dom; 
 Brass & b2=dot; //派生类可以直接赋给基类
 b1.ViewAcct(); // 用Brass::ViewAcct() 
 b2.ViewAcct(); // 用Brass::ViewAcct()
/*基类Brass公有成员函数ViewAcct声明前有virtual*/
 b1.ViewAcct(); // 用Brass::ViewAcct() 
 b2.ViewAcct(); // 用BrassPlus::ViewAcct() 根据对象类型而非引用选择版本

5. En la implementación de la función miembro de la clase derivada: al llamar a la función pública de la clase base, puede llamar directamente como doubal bal = Balance (), si la función virtual ViewAcct () en la clase derivada necesita llamar a la función virtual ViewAcct () de la clase base, Para usar el solucionador de alcance, debe escribirse como Brass :: ViewAcc ()

6. Puede utilizar una matriz para representar varios tipos de objetos, que es polimorfismo.

  Brass * p_client [N]; // El puntero Brass [i] puede apuntar a un objeto Brass o BrassPlaus

 p_client [i] = new Brass (temp, tempnum, tempbal); 

 p_client [j] = new BrassPlaus (temp, tempnum, tempbal, tmax, trate); // Satisfacer diferentes condiciones con las correspondientes declaraciones de asignación

El polimorfismo lo proporciona el siguiente código:

para (int i = 0; i <N; i ++) {p_client [i] -> ViewAcct (); }

 

7. Construya en el proceso de compilación, llamado construcción estática; (puede determinar directamente qué función compilar)

   El compilador debe generar el código de función virtual correcto cuando el programa se está ejecutando , lo que se denomina enlace dinámico .

8. El enlace dinámico puede redefinir los métodos de clase y el enlace estático tiene una alta eficiencia.

9. La forma en que el compilador maneja las funciones virtuales:

  •    Agregue un miembro oculto a cada objeto. Este miembro tiene un puntero a una matriz de direcciones de función, que se denomina tabla de función virtual ( vtbl: tabla de función virtual). La tabla de función virtual almacena la dirección de la función virtual declarada para el objeto de clase. La tabla de direcciones de funciones virtuales es una matriz.
  • [ Hay un puntero implícito en el objeto de la clase base, que apunta a la tabla de direcciones de todas las funciones virtuales en la clase base. El objeto de la clase derivada implicará un puntero a la tabla de direcciones independientes.          Si la clase derivada proporciona una nueva definición de la función virtual, la tabla de función virtual se guardará como una nueva dirección, si la clase derivada no redefine la función virtual, la vtbl guardará la dirección original de la función de la clase base ]
  • (No importa si hay 1 o 10 funciones virtuales en la clase, solo se agrega 1 miembro de dirección al objeto, pero el tamaño de la tabla es diferente)

10. Los amigos no pueden ser funciones virtuales (los amigos no son miembros de la clase, solo los miembros pueden ser funciones virtuales)

11. El método de herencia redefinido no está sobrecargado.

  •    El método de herencia redefinido debe garantizar que sea exactamente el mismo que el prototipo de la clase base. Pero si hay un tipo de retorno y el retorno es una referencia o puntero de clase base, el método de herencia de la clase derivada se modifica para devolver una referencia o puntero a la clase derivada. clase Vivienda {público: Vivienda virtual & construcción (int n)}; clase Vivienda: Vivienda pública {público: Vivienda virtual & construcción (int n)};
  • Si la declaración de la clase base está sobrecargada, debe redefinir todas las versiones sobrecargadas en la clase derivada. Class Dwelling {público: virtual void showperks () const; virtual void showperks (int a) const;}; class Hovel: public Dwelling {público: virtual void showperks () const; virtual void showperks (int a) const;}; 

12. Los miembros de la clase derivada pueden acceder directamente a los miembros protegidos de la clase base, pero no pueden acceder directamente a los miembros privados de la clase base.

  •        Para el mundo exterior, los miembros protegidos son similares a los miembros privados, para las clases derivadas, los miembros protegidos son similares a los miembros públicos;
  •        Es mejor utilizar el control de acceso privado para los miembros de datos de la clase y no utilizar el control de acceso protegido; al mismo tiempo, la clase derivada puede acceder a los datos de la clase base mediante el método de la clase base;
  •         Para las funciones miembro, el control de protección es útil, ya que permite que las clases derivadas accedan a funciones internas que no pueden ser utilizadas por el público.

13. Clase base abstracta compleja (ABC: clase base abstracta): solo define la interfaz, no la implementación. Se utiliza al menos una interfaz de función virtual pura, y las clases derivadas de ABC utilizarán funciones virtuales convencionales para implementar esta interfaz de acuerdo con las características específicas de la clase derivada . Para ser un verdadero ABC, debe contener al menos una función virtual pura. El = 0 en el prototipo hace que la función virtual sea una función virtual pura.

[Cuando la clase N y la clase M tienen ciertos puntos en común, pero la clase M no necesita heredar por completo los datos y métodos de la clase N, puede poner los elementos comunes de M y N en ABC, y luego derivar la clase N y la clase M de ABC . El puntero de clase ABC puede gestionar objetos de clase M y clase N al mismo tiempo] El  uso de prototipos = 0 indica que la clase es una clase base abstracta. C ++ permite definir funciones virtuales puras .

Por ejemplo: dos clases de elipse y círculo, el punto común es el método de coordenadas centrales, que es el mismo que el método Move (), pero el Area () es diferente.

           El método Area () no se puede implementar en ABC. C ++ mejora las funciones no implementadas mediante el uso de funciones virtuales puras El final de la declaración de función virtual pura es = 0 ;

            Cuando se incluye una función virtual pura en la declaración de clase, no se debe crear un objeto de esa clase. 

//椭圆和圆的ABC类  
class BaseEllipse{   //声明中含有纯虚函数,不能创建BaseEllipse类对象
  private: 
     double x; //椭圆和圆的共性
     double y;
  public:
     BaesEllipse(double x0=0,double y0=0) :x(x0),y(y0){}
     virtual ~BaesEllipse();
     void Move(int nx,ny) { x=nx; y=ny; } //椭圆和圆的共性
     virtual double Area() const=0; //纯虚函数  椭圆和圆的不同     
}; 

14. El constructor, el destructor, la función de asignación y la función de amigo no se pueden heredar.

 

Supongo que te gusta

Origin blog.csdn.net/lvliang2017232003/article/details/88804365
Recomendado
Clasificación