C++——多态

1.概念

多态是面向对象编程中的一个重要概念,它允许不同类型的对象对同一个消息做出不同的响应。简单来说,多态性是指同一个方法在不同的对象上具有不同的行为。

2.定义

2.1多态的构成条件

  1. 存在继承关系,即至少有一个基类和一个派生类。
  2. 基类声明了虚函数,即将基类中希望在派生类中重写的函数标记为 virtual
  3. 在派生类中重写(override)了基类的虚函数,即使用相同的函数名、参数列表和返回类型来覆盖基类中的虚函数。
  4. 使用基类的指针或引用来调用虚函数,通过基类指针或引用访问派生类对象。

2.2虚函数

虚函数:即被virtual修饰的类成员函数称为虚函数。

class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl;}
};

2.3虚函数的重写

虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同),称之类的虚函数重写了基类的虚函数

#include
using namespace std;
class Animal
{
public:
	virtual void BuyTicket()
	{
		cout << "动物" << endl;
	}
};
class Dog:public Animal
{
public:
	virtual void BuyTicket()
	{
		cout << "狗" << endl;
	}
};
void Func(Animal& a)
{
	a.BuyTicket();
}
int main()
{
	Animal a;
	Dog d;
	Func(a);
	Func(d);
	return 0;
}

2.4虚函数重写的特例

协变(基类与派生类函数返回值类型不同)

派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回值基类对象的指针或者引用,派生类虚函数的返回派生类对象的指针或者引用时,称为协变。

class A{};
class B : public A {};
class Person {
public:
	virtual A* f() {return new A;}
};
class Student : public Person {
public:
	virtual B* f() {return new B;}
};

析构函数的重写(基类与派生类析构函数的名字不同)

如果基类的析构函数称为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数不相同,看起来违背了重写的规则,其实编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor

class Person {
public:
	virtual ~Person() {cout << "~Person()" << endl;}
};
class Student : public Person {
public:
	virtual ~Student() { cout << "~Student()" << endl; }
};
int main()
{
	Person* p1 = new Person;
	Person* p2 = new Student;
	delete p1;
	delete p2;
	return 0;
}

2.5C++11 voerride和final

帮助用户检测是否重写

1.final:修饰虚函数,表示该虚函数不能再被重写

class Car
{
public:
	virtual void Drive() final {}
};
class Benz :public Car
{
public:
	virtual void Drive() {cout << "Benz-舒适" << endl;}
};

2.voerride:检测派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错

class Car{
public:
	virtual void Drive(){}
};
class Benz :public Car {
public:
	virtual void Drive() override {cout << "Benz-舒适" << endl;}
};

2.6重载、重写、重定义的对比

C++——多态_第1张图片

3抽象类

3.1概念

在虚函数后面写上=0,则这个函数为纯虚函数,包含纯虚函数的类叫抽象类(也叫接口类),抽象类不能实例化对象。派生类继承后也不能实例化出对象,只有重写了纯虚函数,派生类才能实例化出对象,纯虚函数规范了派生类必须重写,另外纯虚函数更体现了接口继承。

class Car
{
public:
	virtual void Drive() = 0;
};
class Benz :public Car
{
public:
virtual void Drive()
{
	cout << "Benz-舒适" << endl;
}
};
class BMW :public Car
{
public:
virtual void Drive()
{
	cout << "BMW-操控" << endl;
}
};
void Test()
{
	Car* pBenz = new Benz;
	pBenz->Drive();
	Car* pBMW = new BMW;
	pBMW->Drive();
}

3.2实现继承

普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实现。

3.3接口继承

虚函数的继承是一种接口继承,派生类继承的是基类函数的接口,目的是为了重写,达到多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数

4.多态的原理

4.1虚函数表

C++中的虚函数表是在实现多态性的机制中使用的一种数据结构。每个包含虚函数的类都会在编译过程中生成一个虚函数表。虚函数表是一个存储着虚函数地址的数组,它记录了每个虚函数在内存中的位置。

当一个对象被声明为虚函数的基类指针或引用指向时,通过该指针或引用调用虚函数时,程序会首先查找虚函数表,然后根据相应的索引来调用实际的虚函数。

虚函数表的形式和实现细节取决于具体的编译器和平台。一般来说,虚函数表是一个指针数组,每个指针指向实际的虚函数实现。编译器通常会将虚函数表放在类的头部,并通过一个隐藏的指针来访问它。

需要注意的是,虚函数表是用于动态绑定的,而不是静态绑定。在运行时,通过虚函数表来查找并调用正确的虚函数,实现了多态性的特性。

4.2多态的原理

C++多态的实现原理是通过虚函数和动态绑定来实现的。多态性允许基类指针或引用指向派生类对象,并在运行时调用相应的派生类函数。

首先,需要在基类中将需要多态的函数声明为虚函数。虚函数使用关键字virtual进行声明,这样在派生类中也可以重定义相同的函数,并且基类指针或引用可以在运行时确定调用的函数。

当通过基类指针或引用调用虚函数时,编译器会在运行时通过虚函数表动态绑定来确定要调用的实际函数的地址。每个包含虚函数的类都会在编译过程中生成一个虚函数表,其中记录了每个虚函数的地址。虚函数表是一个指针数组,每个指针指向实际的虚函数实现。

通过基类指针或引用调用虚函数时,程序会首先查找虚函数表,然后根据相应的索引来调用实际的虚函数。这就实现了多态性,即基类指针或引用可以在运行时动态地绑定到派生类的对象,并调用正确的派生类函数。

4.3静态绑定

静态绑定又称为前期绑定,在程序编译期间确定了程序的行为,也成为静态多态

4.4动态绑定

动态绑定又称后期绑定,是在程序运行期间,根据具体拿到的类型确定程序的具体行为,调用具体的函数,也称为动态多态

4.5单继承和多继承

单继承指的是一个派生类只能继承一个基类。在C++中,通过使用关键字"public"来指定派生类从基类继承的方式。一个派生类可以直接访问其所继承的公有成员。单继承能够确保较好的代码结构和简洁性,同时也避免了多继承可能带来的冲突和歧义。

多继承指的是一个派生类可以从多个基类继承。在C++中,可以使用逗号分隔符将多个基类列在继承列表中。多继承使得一个类可以获取多个基类的特性和行为。但同时,多继承也可能导致派生类在继承多个基类时出现命名冲突和二义性问题,需要程序员进行显式的解决。

中,通过使用关键字"public"来指定派生类从基类继承的方式。一个派生类可以直接访问其所继承的公有成员。单继承能够确保较好的代码结构和简洁性,同时也避免了多继承可能带来的冲突和歧义。

多继承指的是一个派生类可以从多个基类继承。在C++中,可以使用逗号分隔符将多个基类列在继承列表中。多继承使得一个类可以获取多个基类的特性和行为。但同时,多继承也可能导致派生类在继承多个基类时出现命名冲突和二义性问题,需要程序员进行显式的解决。

你可能感兴趣的:(c++,java,jvm)