c++ - 多态

文章目录


一、多态的概念

1、概念:

多态就是具有多种形态,可以理解为同一个行为不同对象去完成表现出不同的状态,如:

二、多态使用

1、构成多态的条件

(1)派生类要对基类虚函数进行重写。

(2)通过基类指针或引用调用虚函数。

2、虚函数

关键字:virtual,加在函数声明前面,并且该函数是非静态成员函数。

如:

3、函数重写

(1)条件:

派生类重写的函数返回值、函数名称、函数参数与基类相同。

(2)使用

c 复制代码
class Person {
public:
//虚函数
	virtual void test01()
	{
		//...
	}
};
class Student : public Person {
public:
	//重写 virtual关键字在派生类中写不写都可
	virtual void test01()
	{
		//...
	}
};

(3)例外

协变:

派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指

针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。

c 复制代码
class Person {
public:
	virtual  Person& test01()
	{
		//...
	}
};
class Student : public Person {
public:
	//重写 返回值是继承关系
	virtual  Student& test01()
	{
		//...
	}
};

析构函数:

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,

都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,

看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处

理,编译后析构函数的名称统一处理成destructor。

如果出现以下情况就会出现子类没有析构

c 复制代码
class Person {
public:
	 ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person {
public:
	~Student() { cout << "~Student()" << endl; }
};

void test()
{
	//情况
	//不重写析构函数时
	Person* p = new Student;
	delete p;
}

如果重写之后调用调用子类的析构,子类的析构再去调用父类析构就不会出现以上情况了。

c 复制代码
class Person {
public:
	virtual ~Person() { cout << "~Person()" << endl; }
};
class Student : public Person {
public:
	~Student() { cout << "~Student()" << endl; }
};

void test()
{
	Person* p = new Student;
	delete p;
}

(3)重载、重定义(隐藏)、重写的区别

重载:同一作用域下,函数名相同,参数(类型、个数、顺序)不同。

重定义:作用域不同(派生类域、基类域),函数名相同。

重写:作用域不同(派生类域、基类域),必需是虚函数,函数名相同、返回类型相同、参数相同。

(4)使用多态

c 复制代码
class Person {
public:
	//虚函数
	virtual void test01() {
		cout << "Person" << endl;
	}
protected:
	int _a;
};

class Student : public Person {
public:
	virtual void test01() {
		cout << "Student" << endl;
	}
protected:
	int _b;
};

void Print(Person* pp)
{
	pp->test01();
}

void test()
{
	Person p;
	Student s;
	//基类对象,传给基类指针pp,pp还是基类 ->不构成多态,依然使用基类的函数
	Print(&p);

	//派生类对象,传给基类指针pp,pp指向的是派生类-> 构成多态,使用的是派生类重写的函数
	Print(&s);
}

4、抽象类

(1)纯虚函数

在虚函数声明后面加上 =0 就是纯虚函数了。

c 复制代码
virtual void test01() = 0;

(2)

拥有纯虚函数的类叫做抽象类,抽象类不能被实例化,当派生类继承抽象类后,必须重写抽象类中的纯虚函数,不然该派生类依旧还是抽象类,不能被实例化。

c 复制代码
//抽像类
class Person {
public:
	//纯虚函数
	virtual void test01() = 0;
};
class Student : public Person {
public:
	//重写纯虚函数
	virtual void test01()
	{
		cout << "virtual void test01()" << endl;
	}
};

三、多态的原理

1、虚函数表

一个类中存在虚函数是会生成一个指针,该指针指向的内容就是虚函数表。

在x86环境下:

c 复制代码
//抽像类
class Person {
public:
	//虚函数
	virtual void test01() {};
protected:
	int _a;
};

void test()
{
	Person p;
	cout << sizeof(Person) << endl;
}



当派生类继承基类时也会产生一个虚函数指针,该指针指向的内容一部分是从父类继承下来的,一部分是重写的。

test01()使用了派生类的,test02()没有重写,还是使用基类的。

2、多态原理

满足多态以后的函数调用,不是在编译时确定的,是运行起来以后到对象的中取找的。不满足多态的函数调用时编译时确认好的(运行时确定)。

3、动态绑定和静态绑定

  1. 静态绑定又称为前期绑定(早绑定),在程序编译期间确定了程序的行为,也称为静态多态,
    比如:函数重载
  2. 动态绑定又称后期绑定(晚绑定),是在程序运行期间,根据具体拿到的类型确定程序的具体
    行为,调用具体的函数,也称为动态多态。

4、多继承与多态

c 复制代码
class Person1{
public:
	//虚函数
	virtual void test01() {};

protected:
	int _a;
};

class Person2 {
public:
	//虚函数
	virtual void test02() {};

protected:
	int _b;
};

class Student : public Person1, public Person2 {
public:
	//重写Person1
	void test01()
	{}
	//重写Person2
	void test02() 
	{}
	void test03()
	{}
protected:
	int _b;
};

void test()
{
	Student s;
}

多继承时每个基类会生成相应的虚函数指针。

相关推荐
phltxy18 小时前
深度解析:Spring Cloud Gateway 从入门到实战
java·开发语言
HAPPY酷18 小时前
从Public到Private:UE5 C++类创建路径差异全解析
java·c++·ue5
无敌昊哥战神18 小时前
【LeetCode 37】解数独 (Sudoku Solver) —— 回溯法详解 (Python/C/C++)
c语言·c++·python·算法·leetcode
AI进化营-智能译站18 小时前
ROS2 C++开发系列08-传感器数据缓存与指令解析方式之数组、向量与字符串实战
开发语言·c++·缓存·ai
hello_读书就是赚钱19 小时前
提示词工程学习笔记
笔记·学习
shjita19 小时前
记录java执行中的一个错误细节
java·开发语言
AI进化营-智能译站19 小时前
ROS2 C++开发系列14-Lambda表达式处理传感器数据流|文件IO保存机器人实验日志
开发语言·c++·ai·机器人
itzixiao19 小时前
L1-067 洛希极限(10分)[java][python]
java·开发语言·算法
jinyishu_19 小时前
链表经典OJ题
c语言·数据结构·算法·链表
二哈赛车手19 小时前
新人笔记---多策略搭建策略执行链实现RAG检索后过滤
java·笔记·spring·设计模式·ai·策略模式