C ++ notas de estudo quatorze: polimorfismo das três principais características da orientação a objetos

1. O conceito básico de polimorfismo

O polimorfismo é uma das três principais características do C ++ orientado a objetos

O polimorfismo é dividido em duas categorias

  • Polimorfismo estático: a sobrecarga de função e a sobrecarga de operador pertencem ao polimorfismo estático, e os nomes de função são reutilizados
  • Polimorfismo dinâmico: classes derivadas e funções virtuais para atingir o polimorfismo em tempo de execução

A diferença entre polimorfismo estático e polimorfismo dinâmico:

  • A ligação inicial de endereços de função polimórfica estática-endereços de função são determinados durante a compilação
  • Endereço de função polimórfica dinâmica ligação tardia - o endereço da função é determinado em tempo de execução

Vamos explicar o polimorfismo por meio de um caso

class Animal
{
    
    
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	virtual void speak()
	{
    
    
		cout << "动物在说话" << endl;
	}
};

class Cat :public Animal
{
    
    
public:
	void speak()
	{
    
    
		cout << "小猫在说话" << endl;
	}
};

class Dog :public Animal
{
    
    
public:

	void speak()
	{
    
    
		cout << "小狗在说话" << endl;
	}

};
//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编

void DoSpeak(Animal & animal)
{
    
    
	animal.speak();
}
//
//多态满足条件: 
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象

void test01()
{
    
    
	Cat cat;
	DoSpeak(cat);


	Dog dog;
	DoSpeak(dog);
}


int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Dois, funções virtuais puras e classes abstratas

No polimorfismo, geralmente a implementação de funções virtuais na classe pai não tem sentido, e o conteúdo principal é chamar a subclasse para reescrever

Portanto, a função virtual pode ser alterada para uma função virtual pura

Sintaxe de função virtual pura:virtual 返回值类型 函数名 (参数列表)= 0 ;

Quando há funções virtuais puras na classe, essa classe também é chamadaAula abstrata

Recursos abstratos :

  • Não é possível instanciar o objeto
  • A subclasse deve reescrever a função virtual pura na classe abstrata, caso contrário, ela também pertence à classe abstrata
class Base
{
    
    
public:
	//纯虚函数
	//类中只要有一个纯虚函数就称为抽象类
	//抽象类无法实例化对象
	//子类必须重写父类中的纯虚函数,否则也属于抽象类
	virtual void func() = 0;
};

class Son :public Base
{
    
    
public:
	virtual void func() 
	{
    
    
		cout << "func调用" << endl;
	};
};

void test01()
{
    
    
	Base * base = NULL;
	//base = new Base; // 错误,抽象类无法实例化对象
	base = new Son;
	base->func();//此时调用的是子类Son的func函数
	delete base;//因为是在堆区(使用了new)记得销毁
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Três, destruição fictícia e destruição pura fictícia

Ao usar polimorfismo, se houver propriedades na subclasse que são abertas para a área de heap, o ponteiro da classe pai não pode ser chamado para o código destruidor da subclasse quando for lançado

Solução: mude o destruidor na classe pai para destruição virtual ou destruição virtual pura

A semelhança entre a análise fictícia e a análise fictícia pura:

  • Pode resolver o ponteiro da classe pai e liberar o objeto da subclasse
  • Precisa ter implementação de função específica

A diferença entre destruição fictícia e destruição fictícia pura:

  • Se for pura destruição fictícia, a classe pertence a uma classe abstrata e o objeto não pode ser instanciado

Gramática de análise fictícia:

virtual ~类名(){}

Sintaxe de análise fictícia pura:

virtual ~类名() = 0;

类名::~类名(){}

class Animal {
    
    
public:

	Animal()
	{
    
    
		cout << "Animal 构造函数调用!" << endl;
	}
	virtual void Speak() = 0;

	//析构函数加上virtual关键字,变成虚析构函数
	//virtual ~Animal()
	//{
    
    
	//	cout << "Animal虚析构函数调用!" << endl;
	//}

    //纯虚析构函数和纯虚函数不一样。前者必须在外部进行实现,不能为空 
	virtual ~Animal() = 0;
};

Animal::~Animal()
{
    
    
	cout << "Animal 纯虚析构函数调用!" << endl;
}

//和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。

class Cat : public Animal {
    
    
public:
	Cat(string name)
	{
    
    
		cout << "Cat构造函数调用!" << endl;
		m_Name = new string(name);
	}
	virtual void Speak()
	{
    
    
		cout << *m_Name <<  "小猫在说话!" << endl;
	}
	//只需要在父类中写(纯)虚析构函数即可,子类中不需要
    ~Cat()
	{
    
    
		cout << "Cat析构函数调用!" << endl;
		if (this->m_Name != NULL) {
    
    
			delete m_Name;
			m_Name = NULL;
		}
	}

public:
	string *m_Name;
};

void test01()
{
    
    
	Animal *animal = new Cat("Tom");
	animal->Speak();

	//通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
	//怎么解决?给基类增加一个虚析构函数
	//虚析构函数就是用来解决通过父类指针释放子类对象
    
    
	//如果把这句话注释掉,那么父类、子类的析构函数都不会被调用,所以,这就说明;
    //在这种父类指针指向子类对象的多态结构中,子类对象其实是一直依赖着父类指针,
    //自己其实并没有单独生成,所以也不会自己在函数执行完调用析构;
    //而父类因为是在堆区,所以也不会自动释放
    delete animal;
}

int main() {
    
    

	test01();

	system("pause");

	return 0;
}

Acho que você gosta

Origin blog.csdn.net/qq_39507748/article/details/109567951
Recomendado
Clasificación