Notas de estudio de C++ 18 clases y herencia de objetos

18.0 Prefacio

La herencia es una de las tres características de la arquitectura orientada a objetos .
Existe una relación especial entre algunas clases, como la figura a continuación:
inserte la descripción de la imagen aquí
Encontramos que al definir estas clases, los miembros del nivel inferior no solo tienen la similitud del nivel superior, sino que también tienen sus propias características.

En este momento, podemos considerar el uso de técnicas de herencia para reducir la duplicación de código .


18.1 Sintaxis básica de la herencia

Por ejemplo, vemos que muchos sitios web tienen un encabezado común, un fondo común e incluso una lista izquierda común, solo el contenido central es diferente.

A continuación, usamos el método de escritura común y el método de escritura heredado para realizar el contenido de la página web y ver el significado y los beneficios de la herencia.

gramática:

class 子类:继承方式 父类 
  • Beneficios de la herencia: menos código reemitido
  • Las subclases también se conocen como clases derivadas.
  • La clase padre también se convierte en la clase base.

Ejemplo:

#include<iostream>
using namespace std;

//普通方法实现网络页面
//Java
class Java
{
    
    
public:
	Java()
	{
    
    
		this->header();
		this->footer();
		this->left();
		this->content();
	}
	void header()
	{
    
    
		cout << "首页、公开课、登录、注册、...(公共头部)" << endl;
	}
	void footer()
	{
    
    
		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
	}
	void left()
	{
    
    
		cout << "Java、Python、C++、...(公共分类列表)" << endl;
	}
	void content()
	{
    
    
		cout << "Java学科视频" << endl;
	}
};
void test1_01()
{
    
    
	cout << "Java下载视频页面如下:" << endl;
	Java ja;
}
//Python
class Python
{
    
    
public:
	Python()
	{
    
    
		this->header();
		this->footer();
		this->left();

	}
	void header()
	{
    
    
		cout << "首页、公开课、登录、注册、...(公共头部)" << endl;
	}
	void footer()
	{
    
    
		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
	}
	void left()
	{
    
    
		cout << "Java、Python、C++、...(公共分类列表)" << endl;
	}
	void content()
	{
    
    
		cout << "Python学科视频" << endl;
	}
};
void test1_02()
{
    
    
	cout << "Python下载视频页面如下:" << endl;
	Python py;
}

//继承方法实现网络页面
//C++
class BasePage
{
    
    
public:
	BasePage()
	{
    
    
		this->header();
		this->footer();
		this->left();
	}
	void header()
	{
    
    
		cout << "首页、公开课、登录、注册、...(公共头部)" << endl;
	}
	void footer()
	{
    
    
		cout << "帮助中心、交流合作、站内地图...(公共底部)" << endl;
	}
	void left()
	{
    
    
		cout << "Java、Python、C++、...(公共分类列表)" << endl;
	}
};

//继承的好处:减少重发代码
//语法:class 子类:继承方式 父类
//子类也称为派生类
//父类也成为基类
class Cpp:public BasePage
{
    
    
public:
	Cpp()
	{
    
    
		this->content();
	}
	void content()
	{
    
    
		cout << "C++学科视频" << endl;
	}
};

void test1_03()
{
    
    
	cout << "C++下载视频页面如下:" << endl;
	Cpp cpp;
}

int main()
{
    
    
	test1_01();
	cout << "----------------" << endl;
	test1_02();
	cout << "----------------" << endl;
	test1_03();
	system("pause");
	return 0;
}

Los miembros de la clase derivada incluyen dos partes:
una se hereda de la clase base y la otra son los miembros agregados.
Heredado de la clase base muestra su generalidad, mientras que los miembros recién agregados muestran su individualidad.


18.2 Método de herencia

Hay tres tipos de herencia:

  • herencia pública
  • herencia protegida
  • herencia privada

inserte la descripción de la imagen aquí

Ejemplo:

#include<iostream>
using namespace std;
//继承方式

//公共继承
class Base1 
{
    
    
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C;
};
class Son1 :public Base1
{
    
    
public:
	void func()
	{
    
    
		m_A = 10;	//父类中的公共权限成员,到子类依旧是公共权限成员
		m_B = 10;	//父类中的保护权限成员,到子类依旧是保护权限成员
		//m_C = 10; //父类中的私有权限成员,子类无法访问
	}
};
void test2_01()
{
    
    
	Son1 s1;
	s1.m_A = 100;
	//s1.m_B = 100; //保护权限,访问不到
}

//保护继承
class Son2 :protected Base1
{
    
    
public:
	void func()
	{
    
    
		m_A = 100;  //父类中的公共权限成员,到子类中变成了保护权限成员
		m_B = 100;	//父类中的保护权限成员,到子类中依旧是保护权限成员
		//m_C = 100;//父类中的私有权限成员,子类无法访问
	}
};
void test2_02()
{
    
    
	Son2 s2;
	//s2.m_A = 100; //保护权限,访问不到
	//s2.m_B = 100; //保护权限,访问不到
}

//私有继承
class Son3 :private Base1
{
    
    
public:
	void func()
	{
    
    
		m_A = 100;  //父类中的公共权限成员,到子类中变成了私有权限成员
		m_B = 100;	//父类中的保护权限成员,到子类中变成了私有权限成员
		//m_C = 100;//父类中的私有权限成员,子类无法访问
	}
};
//可以通过再创建一个类来继承此类查看成员是否为私有权限
class GrandSon3 :public Son3
{
    
    
public:
	void func()
	{
    
    
		//m_A = 100;//父类中的私有权限成员,子类无法访问
		//m_B = 100;//父类中的私有权限成员,子类无法访问
	}
};

int main()
{
    
    
	system("pause");
	return 0;
}

18.3 Modelos de objetos en herencia

18.3.1 La subclase hereda todos los miembros de la clase principal

Pregunta: ¿Cuáles de los miembros heredados de la clase principal pertenecen al objeto de la subclase?

Respuesta: La subclase heredará todas las propiedades de los miembros no estáticos de la clase principal.

#include<iostream>
using namespace std;

//继承中的对象模型
class Base
{
    
    
public:
	int m_A;
protected:
	int m_B;
private:
	int m_C; //私有成员属性被编译器隐藏了,只是访问不到,但是确实被继承了
};

class Son :public Base
{
    
    
public:
	int m_D;
};

void test3_01()
{
    
    
	//父类中的所有非静态成员属性都会被子类继承下去
	cout << "size of Son = " << sizeof(Son) << endl;
}

int main()
{
    
    
	test3_01();
	system("pause");
	return 0;
}
  1. Visualización del modelo de objetos mediante la herramienta del símbolo del sistema para desarrolladores

inserte la descripción de la imagen aquí
2. Vaya a la letra de la unidad E: (la letra de la unidad donde se encuentra el cpp)
3. Vaya a la ruta del archivo cd la ruta de la carpeta donde se encuentra el cpp
4. Vea el comando cl [nombre de archivo].cpp /d1reportSingleClassLayoutXXX donde XXX es el nombre de la clase.
como muestra la imagen:
inserte la descripción de la imagen aquí

Se puede ver que todas las propiedades de los miembros no estáticos en la clase principal serán heredadas por la subclase.

18.3.2 El puntero de la clase padre apunta al objeto de la subclase

C++ admite la conversión de tipos entre la clase principal y la subclase, y el puntero de la clase principal puede apuntar directamente al objeto de la subclase. Si el puntero de la clase principal se usa para apuntar al objeto de la subclase, entonces el objeto de la subclase se convertirá en un objeto de la clase principal, que perderá sus miembros originales y tendrá los miembros de la clase principal, lo que equivale a la conversión de tipos.

Ejemplo:

#include<iostream>
using namespace std;

//动物类
class Animal
{
    
    
public:
	void speak()
	{
    
    
		cout << "动物在说话" << endl;
	}
};
class Cat :public Animal
{
    
    
public:
	void speak()
	{
    
    
		cout << "小猫在说话" << endl;
		m_A = 100;
	}
};

//执行说话的函数
void doSpeak(Animal& animal) //Animal& animal = cat; 传入的是子类,用父类接收,此时此对象转换为了父类
{
    
    
	cout << (typeid(animal).name()) << endl;
	animal.speak();
	//cout << animal.m_A << endl;  变成了父类对象,没有了子类的成员。
}

void test3_02()
{
    
    
	Cat cat;
	Animal an;
	doSpeak(cat);
}
int main()
{
    
    
	test3_02();
	system("pause");
	return 0;
}

18.4 Orden de construcción y destrucción en la herencia

Después de que la subclase herede la clase principal, cuando se crea el objeto de la subclase, también se llamará al constructor de la clase principal.

Pregunta: ¿Quién viene primero en el orden de construcción y destrucción de la clase padre y la subclase?
Respuesta: Primero se construye la clase principal, luego se construye la subclase, y el orden de destrucción es opuesto al orden de construcción (pila: primero en entrar, último en salir).

Ejemplo:

#include<iostream>
using namespace std;
class Base4
{
    
    
public:
	Base4()
	{
    
    
		cout << "Base4构造函数" << endl;
	}
	~Base4()
	{
    
    
		cout << "Base4析构函数" << endl;
	}
};
class Son :public Base4
{
    
    public:
	Son()
	{
    
    
		cout << "Son构造函数" << endl;
	}
	~Son()
	{
    
    
		cout << "Son析构函数" << endl;
	}
};
void test4_01()
{
    
    
	Son son;
}
int main()
{
    
    
	test4_01();
	system("pause");
	return 0;
}

18.5 Herencia de miembros con el mismo nombre

Pregunta: Cuando hay miembros con el mismo nombre en la subclase y la clase principal, ¿cómo acceder a los datos con el mismo nombre en la subclase o la clase principal a través del objeto de la subclase?

  • Para acceder a los miembros de la subclase con el mismo nombre, puede acceder directamente a ellos. gramática:对象.成员
  • Para acceder a los miembros con el mismo nombre de la clase principal, debe agregar un ámbito. gramática:对象.父类::成员

Permítanme hablar sobre esto aquí: cuando una subclase hereda la clase principal, la subclase ya tiene todas las variables miembro y funciones miembro de la clase principal.

Variable miembro :

  1. Si no hay una variable miembro con el mismo nombre que la clase principal en la subclase, la subclase y la clase principal comparten una variable miembro en este momento y la sintaxis para acceder a este miembro fuera de la clase es: 对象.成员变量o 对象.父类::成员变量.
  2. Para distinguir las variables miembro con el mismo nombre en la subclase y la clase padre , en la subclase, cuando desee acceder a las variables miembro de la clase padre, use la sintaxis: 父类::成员变量o this->父类::成员变量. Acceder a las variables miembro de la subclase fuera de la clase : 对象.成员变量; acceder a las variables miembro de la clase padre对象.父类::成员变量 : .

Función miembro :

  1. Si no hay una función miembro con el mismo nombre que la clase principal en la subclase, entonces la subclase y la clase principal comparten una función miembro en este momento , use 对象.成员函数o 对象.父类::成员函数.
  2. La función miembro con el mismo nombre en la subclase ocultará todas las funciones miembro con el mismo nombre en la clase principal (se ocultarán todas las funciones sobrecargadas con el mismo nombre) , y debe usar la sintaxis de ámbito para llamar a la función de la clase principal con el mismo nombre.
  3. En resumen, en una subclase, cuando desee llamar a una función miembro de la clase principal, use la sintaxis: 父类::成员函数o this->父类::成员函数. Llame a la función miembro de la subclase fuera de la clase : 对象.成员函数; Llame a la función miembro de la clase padre : 对象.父类::成员函数.

Ejemplo:

#include<iostream>
using namespace std;

class Base5
{
    
    
public:
	Base5()
	{
    
    
		m_A = 100;
	}
	void func()
	{
    
    
		cout << "Base5-func()调用" << endl;
	}
	void func(int a)
	{
    
    
		cout << "Son5_01-func(int a)调用" << endl;
	}
	int m_A;
};
class Son5_01 :public Base5
{
    
    
public:
	Son5_01()
	{
    
    
		m_A = 300;
	}
	//int m_A;   //如果不创建m_A的成员变量,那么构造函数将直接对父类中的m_A进行赋值.
	void func()
	{
    
    
		cout << "Son5_01-func()调用" << endl;
	}

};
class Son5_02 :public Base5
{
    
    
public:
	Son5_02()
	{
    
    	
		//Base5::m_A = 50;  //如果需要改变父类的成员变量,指明作用域即可.
		m_A = 200;
	}
	void funcc()
	{
    
    
		Base5::func();  //在子类中调用父类函数
	}
	int m_A;   //创建m_A的成员变量后,则是对自己的成员m_A进行赋值.
};


void test5_01()
{
    
    
	Son5_01 son;
	cout << "Son5_01下: m_A = " << son.m_A << endl;
	cout << "Base5下: m_A = " << son.Base5::m_A << endl;
}
void test5_02()
{
    
    
	Son5_02 son;
	cout << "Son5_02下: m_A = " << son.m_A << endl;
	cout << "Base5下: m_A = " << son.Base5::m_A << endl;
}


void test5_03()
{
    
    
	cout << "在类外中调用子类和父类函数" << endl;
	Son5_01 son;
	son.func();
	//son.func(100); 父类中的同名成员函数都被隐藏了.
 	son.Base5::func();
 	son.Base5::func(100);
}
void test5_04()
{
    
    
	cout << "在子类中调用父类函数" << endl;
	Son5_02 son;
	son.funcc();
}
int main()
{
    
    
	test5_01();
	test5_02();
	test5_03();
	test5_04();
	system("pause");
	return 0;
}

18.6 Herencia de miembros estáticos con el mismo nombre

Pregunta: ¿Cómo se puede acceder a miembros estáticos con el mismo nombre en herencia en objetos de subclase?

Los miembros estáticos y los miembros no estáticos con el mismo nombre se manejan de la misma manera.

  • Para acceder a los miembros de la subclase con el mismo nombre, puede acceder directamente a ellos. gramática:对象.成员
  • Para acceder a los miembros con el mismo nombre de la clase principal, debe agregar un ámbito. gramática:对象.父类::成员

Nota: Al acceder a los miembros de la clase principal
por nombre de clase子类::父类::成员 , la sintaxis es: .

Ejemplo:

#include<iostream>
using namespace std;

class Base6
{
    
    
public:
	static int m_A; //类内定义
	static void func()
	{
    
    
		cout << "Base6-static void func()" << endl;
	}
};
int Base6::m_A=100;//类外初始化
class Son6 :public Base6
{
    
    
public:
	static int m_A;
	static void func()
	{
    
    
		cout << "Son6-static void func()" << endl;
	}
};
int Son6::m_A = 200;

void test6_01()
{
    
    
	//通过对象访问
	cout << "通过对象访问" << endl;
	Son6 s;
	cout << "Son6下的m_A为:" << s.m_A << endl;
	cout << "Base6下的m_A为:" << s.Base6::m_A << endl;
	//通过类名访问
	cout << "通过类名访问" << endl;
	cout << "Son6下的m_A为:" << Son6::m_A << endl;
	cout << "Base6下的m_A为:" << Son6::Base6::m_A << endl;//第一个::代表通过类名访问,第二个::代表作用域
}

void test6_02()
{
    
    
	//通过对象访问
	cout << "通过对象访问" << endl;
	Son6 s;
	s.func();
	s.Base6::func();
	//通过类名访问
	cout << "通过类名访问" << endl;
	Son6::func();
	Son6::Base6::func();
}
int main()
{
    
    	
	test6_01();
	test6_02();

	system("pause");
	return 0;
}

18.7 Sintaxis de herencia múltiple

C++ permite que una clase herede de varias clases

gramática:

class 子类 : 继承方式 父类1 , 继承方式 父类2 ...{
    
    };

La herencia múltiple puede hacer que aparezcan miembros con el mismo nombre en la clase principal, que debe distinguirse por ámbito.

No se recomienda utilizar la herencia múltiple en el desarrollo real de C++.

#include<iostream>
using namespace std;

class Base7_01
{
    
    
public:
	Base7_01()
	{
    
    
		m_A = 100;
	}
	int m_A;
};
class Base7_02
{
    
    
public:
	Base7_02()
	{
    
    
		m_A = 200;
	}
	int m_A;
};
class Son7 :public Base7_01, public Base7_02
{
    
    
public:
	Son7()
	{
    
    
		m_C = 300;
		m_D = 400;
	}
	int m_C;
	int m_D;
};

void test7_01()
{
    
    
	Son7 s;
	cout << "sizeof s = " << sizeof(s) << endl;  //4*4
	cout << "Base7_01的m_A = " << s.Base7_01::m_A << endl;
	cout << "Base7_02的m_A = " << s.Base7_02::m_A << endl;
}

int main()
{
    
    
	test7_01();
	system("pause");
	return 0;
}

18.8 Herencia de diamantes (herencia de diamantes)

Concepto de herencia de diamantes:

  • Dos clases derivadas heredan de la misma clase base,
  • Otra clase hereda estas dos clases derivadas al mismo tiempo,
  • Este tipo de sucesión se conoce como sucesión de diamantes, o sucesión de diamantes.

Caso típico de herencia de diamantes:
inserte la descripción de la imagen aquí
Problema de herencia de diamantes:

  1. Las ovejas heredan los datos de los animales, y los camellos también heredan los datos de los animales. Cuando el caballo de lodo de pasto usa los datos, habrá ambigüedad (usando el alcance para resolver).
  2. El caballo de hierba barro hereda dos copias de los datos del animal, de hecho debemos tener claro que solo necesitamos una copia de estos datos (la herencia virtual lo soluciona).

Herencia virtual: virtualdespués de agregar palabras clave antes de la herencia, se convierte en herencia virtual.

gramática:

class 子类 : virtual 权限 父类{
    
    };

Ejemplo:

#include<iostream>
using namespace std;

//动物
class Animal
{
    
    
public:
	int m_Age;
};

//利用虚继承 解决菱形继承的问题
// //继承之前加上关键字 virtual 变为虚继承
// Animal类称为 虚基类
//羊
class Sheep :virtual public Animal
{
    
    };
//骆驼
class Tuo :virtual public Animal
{
    
    };
//羊驼
class SheepTuo :public Sheep, public Tuo 
{
    
    };

void test8_01()
{
    
    
	SheepTuo st;
	//st.m_Age = 18; 不明确
	st.Sheep::m_Age = 18;
	st.Tuo::m_Age = 28;
	st.m_Age = 100;
	//当菱形继承,两个父类拥有相同数据,需要加以作用域区分
	cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;
	cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;
	cout << "sizeof(st) = " << sizeof(st) << endl;
}
int main()
{
    
    
	test8_01();
	system("pause");
	return 0;
}

Cuando varias subclases heredan la clase principal mediante la herencia virtual, la clase principal común en este momento se llama: clase base virtual . En este momento, solo hay una variable miembro en estas clases con relación de herencia, por lo que es una variable miembro ya sea que se use o
no al acceder a . La herencia virtual consiste en almacenar un puntero de clase base virtual en la subclase - vbptr (puntero base virtual), este puntero apunta a una tabla de clase base virtual - vbtable (tabla base virtual). Se almacena un desplazamiento para cada subclase en la tabla de clase base virtual. Cuando cada subclase accede a las variables miembro, al acceder al desplazamiento en la tabla de clase base virtual a través de este puntero de clase base virtual se accederá a la clase base virtual. La única variable miembro.对象.成员对象.父类::成员

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_49030008/article/details/123321914
Recomendado
Clasificación