C++ 多态

多态

多态的概念: 当不同的对象调用同一个函数产生出不同的状态。


构成多态的条件

多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。比如B继承了A。A对象产生的行为和B对象不同。

要构成多态还有两个条件:

  • 1.必须通过基类的指针或者引用调用虚函数
  • 2.被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

在这里插入图片描述



虚函数

被virtual 关键字修饰的成员函数。

class Person {
public:
	virtual void show() {
		cout << "父类" << endl;	
	}
	
};

只有非静态成员函数才可以是虚函数,解决菱形继承使用到的虚继承和这里没有关系。



虚函数的重写

虚函数的重写(覆盖)指的是子类中有一个跟父类完全相同的虚函数(即子类虚函数与父类虚函数的返回值类型、函数名字、参数列表完全相同,称子类的虚函数重写了父类的虚函数。

class Person {
public:
	virtual void show() {
		cout << "父类" << endl;	
	}
	
};

class Student : public Person {
public:
	//子类的virtual 关键字可以不写,子类已经继承了父类的虚函数,默认已带有virtual属性
	virtual void show() {
		cout << "子类" << endl;
	}
};



重写中的特例


协变

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


class A {};
class B :public A {};

class Person {
public:
	virtual A* show() {
		cout << "父类" << endl;
	}

};

class Student :virtual public Person {
public:
	virtual B* show() {
		cout << "子类" << endl;
	}
};

析构函数

子类和父类中的析构函数虽然名字不同,但是同样构成隐藏(重定义),编译器对类析构和子类析构作统一处理,都默认看为 destructor() ,为同一个函数。

class Person {
public:
	~Person(){}
};

class Student :virtual public Person {
public:
	~Student(){}	//构成隐藏
};

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



override & final

final

final关键字修饰虚函数,禁止虚函数被重写,如果发生重写编译器会报错。

class Person {
public:
	virtual A* show() final {
		cout << "父类" << endl;
	}
};

class Student :virtual public Person {
public:
	virtual B* show() {
		cout << "子类" << endl;
	}
};

override

检查子类虚函数是否重写父类的虚函数,如果未重写则编译器报错。

class Person {
public:
	virtual void show(int i)  {
		cout << "父类" << endl;
	}
};

class Student :virtual public Person {
public:
	virtual void show(char c) override {
		cout << "子类" << endl;
	}
};

此时编译器报错



重载、重写、重定义的区别


重载

  • 两个函数在同一作用域
  • 函数名相同/参数列表不同

重写(覆盖)

  • 两个函数分别在基类和派生类的作用域
  • 函数名/参数/返回值都必须相同(协变除外),两个函数必须是虚函数

重定义(隐藏)

  • 两个函数分别在基类和派生类的作用域
  • 函数名相同
  • 两个基类和派生类的同名函数不构成重写就是重定义


抽象类

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

class Person {
public:
	virtual void show() = 0;
};


接口继承和实现继承

普通函数的继承是一种实现继承,子类继承了父类函数,可以使用函数,继承的是函数的实现。虚函数的继承是一种接口继承,子类继承的是父类虚函数的接口,目的是为了重写,达成多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

necesse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值