C++之多态

本文详细解析C++中的多态概念,包括静态多态与动态多态的区别,虚函数的实现机制,以及虚函数表的工作原理。通过实例演示了虚函数的重写过程,探讨了抽象类的作用,解释了虚函数与析构函数的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


面向对象三大特性之一:多态

引入

通俗来说,多态就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。

比如消费行为,当普通顾客购买时,一般都是全额付款。而当VIP付款时,总是享受折扣优惠;这也是多态~
这么看来之前所说的大数据杀熟也是一种多态行为了~ /滑稽

  • 静态多态:静态多态就是重载,因为是在编译期决议确定,所以称为静态多态。
  • 动态多态:动态多态就是通过继承重写基类的虚函数实现的多态,因为是在运行时决议确定,所以称为动态多态。

构成条件

多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。
比如Student继承了PersonPerson对象买成人票全价,Student对象买学生票半价。

那么在继承中要构成多态还有两个条件:

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

虚函数

虚函数:被virtual关键字修饰的类成员函数

virtual void VIPpurchase() {
   
    cout << "折扣40%" << endl;}

虚函数的重写(覆盖)

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

演示

class Person {
   
   
public:
	virtual void Purchase() {
   
   
		std::cout << "100yuan\n";
	}
};

class Student :public Person {
   
   
public:
	virtual void Purchase() {
   
   		//派生类重写虚函数
		std::cout << "50yuan\n";
	}
};

/*注意:
	在重写基类虚函数时,派生类的虚函数在不加 virtual 关键字时,虽然也可以构成重写(因为继承后
	基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范,不建议这样使用
*/
void Func(Person& p) {
   
   		//必须是基类的指针 / 引用
	p.Purchase();
}

int main() {
   
   
	Student s;
	Func(s);

	Person p;
	Func(p);

	return 0;
}

输出结果:

50yuan
100yuan

如代码所示,就完成了不同对象的多态行为。

虚函数重写特例

1. 协变

  • 派生类重写基类虚函数时,与基类虚函数返回值类型不同。

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

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; }
};

2. 析构函数的重写

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

虽然基类与派生类析构函数名字不同。虽然函数名不相同,看起来违背了重写的规则,其实不然。
这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor

class Person {
   
   
public:
	virtual ~Person() {
   
    cout << "~Person()" << endl; }
};
class Student : public Person {
   
   
public:
	virtual ~Student() {
   
    cout << "~Student()" << endl; }
};

// 只有派生类Student的析构函数重写了Person的析构函数
//	下面的delete对象调用析构函数,才能构成多态
//	才能保证p1和p2指向的对象正确的调用析构函数。

int main() {
   
   
	Person* p1 = new Person;
	Person* p2 = new Student;
	delete p1;
	delete p2;
	system("pause");
	return 0;
}

C++11:override 和 final 关键字

C++对函数重写的要求比较严格,但是有些情况下由于疏忽,可能会导致函数名字母次序写反而无法构成重载,而这种错误在编译期间是不会报出的,只有在程序运行时没有得到预期结果才来debug会得不偿失,因此:C++11提供了overridefinal两个关键字,可以帮助

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

giturtle

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

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

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

打赏作者

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

抵扣说明:

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

余额充值