多态中虚函数同名参数不同

1 篇文章 0 订阅

案例

class A {
public:
		A() {};
	virtual ~A() {};
	virtual void says(int x, int y) ;
};
void A::says(int x, int y)
{
	std::cout << "A!\n";
}


class B :public A {
public:
	B() {};
	~B() {};
	virtual void says(int x,int y) {
		std::cout << "B!\n";
	}
};

class C :public B {
public:
	C() {};
	~C() {};
	virtual void says(int x) {
		std::cout << "C!\n";
	}
};
int main()
{
	A * ap= new C;
	ap->says(a, a);
	return 0;
}

这时候会进入B的says,子类覆盖父类同名函数,在多态的场景中可能还需要考虑函数参数个数.

// 多态中如果函数名相同,但是参数不同,那么不视为同一个参数,会查找上一个父类中的对应函数
#include <iostream>

class Base {
public:
//	Base() {};
	virtual ~Base() {};
	virtual void says(int x, int y) = 0;
};
void Base::says(int x, int y)
{
	std::cout << "Base Derived!\n";
}

class Derived :public Base {
public:
	Derived() {};
	~Derived() {};
	virtual void says(int x, int y) {
		std::cout << "Hello Derived!\n";
	}
};

class DerivedSecond :public Derived {
public:
	DerivedSecond(){};
	~DerivedSecond(){};
	virtual void says(int x,int y) {
		std::cout << "Hello DerivedSecond2!\n";
	}
};

class DerivedThird :public DerivedSecond {
public:
	DerivedThird() {};
	~DerivedThird() {};
	virtual void says(int y) {
		std::cout << "Hello DerivedThird!\n";
	}
};

int main()
{
	Base *bp = new DerivedSecond;
	int a = 2;
	bp->says(a,a);//Hello DerivedSecond2

	Base *bp2 = new DerivedThird;
	bp2->says(a, a);//Hello DerivedSecond2,这里调用了父类DerivedSecond::says(int x,inty)

	DerivedThird dso;
	dso.says(a);
	//dso.says(a,a);//报错,这里覆盖了父类的DerivedSecond::says(int x,inty)

    std::cout << "Hello World!\n";
}

函数重名但是参数不同,构成函数隐藏,但是不构成函数多态(重写)

扩展

发现了几个讲多态的不错的文章,放到这里记录下
https://blog.csdn.net/weixin_46935110/article/details/127584034
https://blog.csdn.net/qq_41300114/article/details/104690689

多态条件:

  1. 前提:继承条件下;
  2. 父类存在虚函数,且子类完成该虚函数的重写。 函数重写:子类父类存在接口完全相同的函数(函数名,参数,返回值完全相同)例外:协变
  3. 调用虚函数的类型必须是指针或者引用,一般使用父类对象的指针或引用指向子类对象.
  • 多态:看指针/引用实际指向的对象是什么, 实际执行的就是对应对象的方法。
  • 非多态看类型: 看指针/引用所代表的类型,是什么类型就执行对应类型的方法。

注意:

  • 如果父类没有虚函数的声明,即使子类有虚函数的声明,子类和父类的对应函数构成函数隐藏,不是函数重写,所以不会产生多态行为。但是如果子类有对应的子类,子类的函数和子子类的函数会构成函数重写,会产生多态行为。总之只有继承体系的上层中有对应的虚函数,此体系中的对应函数就会产生多态行为。
  • 如果父类有虚函数的声明,子类对应的函数就是虚函数,构成多态。
  • 建议所有的虚函数都添加 virtual 的声明

关于析构函数:

  • 基类的析构函数最好写成虚函数。
  • 多态场景下,会自动调用子类对应的析构函数,子类内部会自动调用父类析构,会避免内存泄漏问题。

对比 函数重载,函数隐藏,函数重写:

  • 函数重载:函数名相同,参数不同,在相同作用域下。
  • 函数隐藏(重定义):函数名相同,参数无所谓,继承场景下即在不同的作用域。
  • 函数重写(覆盖): 函数名相同,参数相同,返回值相同/协变,继承场景,并且是虚函数。如果虚函数不构成重写,只要函数名相同,则至少会构成函数隐藏。

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

虚函数表:
在这里插入图片描述

  • 派生类对象s中也有一个虚表指针,s对象由两部分构成,一部分是父类继承下来的成员,虚表指针也就是存在部分的另一部分是自己的成员。
  • 基类p对象和派生类s对象虚表是不一样的,这里我们发现fun1完成了重写,所以d的虚表中存的是重写的Student::fun1,所以虚函数的重写也叫作覆盖,覆盖就是指虚表中虚函数的覆盖。重写是语法的叫法,覆盖是原理层的叫法。
  • 另外fun2继承下来后是虚函数,所以放进了虚表,fun3也继承下来了,但是不是虚函数,所以不会放进虚表。
  • 虚函数表本质是一个存虚函数指针的指针数组,这个数组最后面放了一个nullptr。
  • 总结一下派生类的虚表生成:a.先将基类中的虚表内容拷贝一份到派生类虚表中 b.如果派生类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函数 c.派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后。
  • 虚表指针一般存放在对象的头4的字节中(32位程序),如果64位,为头8个字节。虚表指针存放的位置和平台有关,不同平台可能位置会有差异。虚表存在代码段

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值