C++---重载、重写(覆盖)、重定义(隐藏)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shanghx_123/article/details/83095033

我们经常会被重载、重写、重定义经常被我搞混,今天就专门总结区别一下。

1.重载

1.重载概念: 重载指的都是函数重载,函数重载就是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列 表(参数个数、类型、顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。
2.构成重载的条件: 函数名相同,参数列表必须不同(参数个数,类型,顺序),返回类型可以相同,也可以不相同。
3.用法: 通过传入不同的参数(个数,类型,顺序),来调用不同的函数。
4. C++中函数重载是一种静态绑定(早绑定),也就是在程序编译期间确定了程序的行为,在这期间,编译器会根据所传递的参数类型,个数,顺序来确定具体应该调用哪个函数,如果有对应的函数就调用,否则会发生隐式类型转换或报错。
我们拿个例子来介绍;

int Add(int left, int right)
{
	return left + right;
}
double Add(double left, double right)
{
	return left + right;
}
long Add(long left, long right)
{
	return left + right;
}
int main()
{
	Add(10, 20);
	Add(10.0, 20.0);
	Add(10L, 20L);

	return 0;
}

代码中函数的名字相同参数列表不同,就构成了函数重载,在调用时,编译器会相应的调用对应的函数。

重写(覆盖)

1.重写概念: 重写是针对基类中虚函数的。在派生类中实现一个与基类虚函数原型(返回值类型、函数名字、参数列表)相同的虚函数,即派生类与基类中虚函数的原型完全相同,这样就构成了对基类虚函数的重写。
2.构成重写的条件: 父类函数必须为虚函数,并且子类的虚函数和父类虚函数原型完全相同(返回值是类型,函数名,参数列表)。如果子类的虚函数和父类的虚函数原型完全相同,此时子类的虚函数前面的virtual关键字是可以省略的,这样的话编译器会默认加上,但是最好加上。
3.特例: 我们上面说的只是普通的重写,重写还有两个特例,这两种情况也会构成重写。
a.协变: 基类中虚函数返回基类对象的指针或引用,派生类与基类同名虚函数返回派生类对象的指针或引用,此种情况也构成重写,但是此时派生类与基类虚函数返回值类型不同。
b.析构函数 : 基类中的析构函数如果是虚函数,只要派生类的析构函数显式提供,就构成重写,此种情况派生类与基类虚函数函数名字不同。

举个例子:

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "买票全价" << endl;
	}
};
class Student : public Person
{
public:
	virtual void BuyTicket()
	{
		cout << "买票半价" << endl;
	}
};

void Func(Person & p)
{
	p.BuyTicket();
}
void Test()
{
	Person Mike;
	Func(Mike);
	Student Johnson;
	Func(Johnson);
}

在这里插入图片描述
传入不同的对象,会调用相应的购票函数。函数重写就是构成多态的一个条件。
构成多态有两个条件:

  1. 基类中必须包含虚函数,并且派生类一定要对基类中的虚函数进行重写
  2. 通过基类对象的指针或者引用调用虚函数
    上面的代码中重写函数就构成了多态,此时只需要在Func函数传入不同的对象,就会调用不同的买票函数,从而实现了多态。

关于为什么传入不同的对象会调用不同的函数?
其原因在于多态调用是一种动态绑定,也就是说在程序运行期间,根据具体拿到的类型确定程序的行为,从而调用相应的函数。多态调用是和对象有关的。而上面所说的静态绑定则是和类型有关。
关于多态调用的底层实现原理在我之前博客讲过:—>多态底层调用实现原理

重定义(隐藏)

1.概念: 子类和父类中有同名成员(成员变量,成员函数),子类成员将屏蔽父类对同名成员的直接访问。也就是说隐藏唯一 一个即针对于变量又针对于函数。
2.访问规则: 在子类成员函数中,可以使用 (基类::基类成员) 来访问,也就是要加作用域限定符( :: )。
3.隐藏的结果: 因为子类继承了父类,所以此时子类就拥有了两个同名函数,这两个函数不一定具有相同的功能,此时不管是在子类内部还是外部通过子类的对象调用该同名成员时,调用的都是子类本来具有的同名成员,若要通过子类的对象调用父类的同名成员,则需要在同名成员前加上作用域限定符。隐藏会导致调用成员时调用不到自己想要的成员,所以在实际中在继承体系里面最好不要定义同名的成员。
4.注意: 在父类和子类这两个作用域中,不能构成重写的都是重定义(隐藏)。

猜你喜欢

转载自blog.csdn.net/shanghx_123/article/details/83095033