解密C++多态机制:发挥对象的多样性,实现更加智能的程序设计

在这里插入图片描述

一.多态

1.多态的用处

众所周知C++语言的三大特性:封装、多态、继承。其中多态就是去完成某个行为,但是会根据不同的对象产生不同的状态,所以叫多态。

2.多态的实现

在继承中实现多态还需要两个条件:

  1. 使用基类的指针或者引用来调用虚函数
  2. 必须在派生类对虚函数进行重写
    代码演示如下:
class A
{
    
    
public:
	virtual void func()
	{
    
    
		cout << "A::func()" << endl;
	}
};

class B : public A
{
    
    
public:
	void func()
	{
    
    
		cout << "B::func()" << endl;
	}
};


int main()
{
    
    
	B b;
	A& a = b;
	a.func();
	return 0;
}

在这里插入图片描述

3.虚函数

用virtual修饰的类成员函数叫做虚函数,虽然与虚拟继承用的是同一关键字但是两者并无关联。

	virtual void func(){
    
    cout << "A::func()" << endl;}

派生类的重写:
重写需要在派生类中编写与基类相同的虚函数:返回类型相同(协变除外)、函数名相同、参数相同(缺省值可不同),然后函数具体实现的不同,来完成多态。

协变
协变允许基类派生类虚函数的返回值不同,但是要求返回值是互为父/子类的指针或者引用。如下所示:

class A
{
    
    
public:
	A(int a = 1)
		:_a(a) {
    
    }

	virtual A* func(int val = 0)
	{
    
    
		cout << val<< endl;
		return new A;
	}

private:
	int _a;
};

class B : public A
{
    
    
public:
	B(int b = 1)
		:_b(b) {
    
    }

	virtual B* func(int val = 1)
	{
    
    
		cout << val<< endl;
		return new B;
	}
private:
	int _b;
};


int main()
{
    
    
	B b;
	A& a = b;
	a.func();
	return 0;
}

在这里插入图片描述

上图中,如果返回的不是本身自己父子类的指针/引用,则可以交换顺序!
需要注意的是在派生类重写基类的虚函数可以不加virtual

析构函数的重写
如果基类重写的析构函数,在派生类可以不加virtual也可以完成重写(因为编译器将析构函数的名称统一处理成destructor。)

4.override 和 final

这两个关键字都是C++11的新语法,final修饰虚函数 使得虚函数不可以重写
override 可以在派生类函数检查是否重写的基类虚函数,如果没有就 报错
如果不想类被继承可以采用:将构造函数设为私有、将类用final修饰为最终类

5.重载重写与重定义

重载:两个函数在同一作用域、函数名/参数相同
重写:两个函数分别在基类和派生类的作用域、函数名/参数/返回值都必须相同(协变例外)、两个函数必须是虚函数
隐藏(重定义)两个函数分别在基类和派生类的作用域、函数名相同、两个基类和派生类的同名函数不构成重写就是重定义

6.虚函数表

如果在类中定义了虚函数,那么类中就会有个虚表用来存放虚表指针。
虚函数表本质是一个存虚函数指针的指针数组
虚表中存放着虚函数,同类型对象会共用一块虚表。
子类自己的虚函数只会放到第一个父类的虚表后面,其他父类的虚表不需要存储,因为存储了也不能调用
有虚函数的类前4/8字节存储的是虚表的地址。
去虚表找 看是什么对象 (多态时)
虚函数重写只重写函数的实现 缺省值会使用父类的

猜你喜欢

转载自blog.csdn.net/qq_43289447/article/details/131956431
今日推荐