1 重载
重载:是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型。
示例:
class A{
public:
void test(int a);
void test(double a);//重载
void test(int a, double b);//重载
void test(double a, int b);//重载
int test(int a); //错误,重载的返回类型必须相同
};
那么这里什么叫做不关心函数返回类型呢?如下所示:
#include <iostream>
using namespace std;
class A
{
public:
A(){};
~A(){};
int test(int a,int b) {return a+b; }
char test(int a) {return '5'+a; }
};
int main()
{
A *a=new A();
cout << a->test(1) << endl;
return 0;
}
这里调用一个参数的char test(int a)是完全可以的,但是如果重载函数为char test(int a,int b)的话,由于其参数列表与int test(int a,int b)相同,那么就会提示char test(int a,int b)不能被重载,可想而知,在我们调用test这个函数的时候,如果以test(a,b)去调用,那系统又怎么知道该调用int test(int a,int b)还是char test(int a,int b)呢?
由此我们也能看出,重载并非不能改变返回值类型,相反,只要合法,你可以随意改变返回值类型,不过不管你是否改变返回值类型,你的重载函数的参数列表是必须改变的,换句话说,重载函数即是在函数名相同的情况下改变参数列表,函数返回类型是否更改并无影响,这也就是为什么重载不关心函数返回类型了。
2 隐藏
隐藏:是指派生类的函数屏蔽了与其同名的基类函数,注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。
示例:
#include <iostream>
using namespace std;
class Base
{
public:
void test(int a,int b){ cout << "Base called!" << endl; }
};
class Derive : public Base
{
public:
void test(int a){ cout << "Derive called!" << endl; }
};
int main()
{
Derive d;
d.test(1);// "Derive called!" 调用子类的fun函数
d.test(1, 1);// 错误,此时fun函数只能接收1个参数
return 0;
}
也就是说,只要在子类中存在父类中的同名函数,那么通过子类对象是无法调用父类相应的同名函数,只能调用当前子类的同名函数。
3 重写(覆盖)
重写(覆盖):是指派生类中存在重新定义的函数。其函数名和参数列表都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。
示例:
#include<iostream>
using namespace std;
class Base
{
public:
virtual void test(int a){ cout << "Base called !" << i << endl;}
};
class Derived : public Base
{
public:
virtual void test(int a){ cout << "Derived called! " << i << endl;}
};
int main()
{
Base b;
Base * pb = new Derived();
pb->test(3); // Derived called!
return 0;
}
总结一下:
不管是重载还是隐藏还是重写,相应情况下的两个函数的函数名都必须相同,在此前提下,三者的区别如下:
- 重载函数与被重载函数必须在同一类中;隐藏函数与被隐藏函数、重写与被重写的函数是存在于父类与子类中;
- 对于隐藏和重写,重写仅发生在父类函数有virtual修饰,且父子函数的参数列表完全相同,除此情况外无论父类函数是否有virtual修饰,都是隐藏。
- 子类中一旦发生了隐藏或重写,则相应函数在父类中的所有重载函数都无法在子类中调用。
#include <iostream>
using namespace std;
class A
{
public:
A(){};
~A(){};
virtual int test(int a,int b)
{
cout<<"int A::test(int a,int b) called!"<<endl;
return 0;
}
virtual char test(int a)
{
cout<<"char A::test(int a) called!"<<endl;
return '0';
}
};
class B:public A
{
public:
B(){};
~B(){};
int test(int a,int b,int c) //隐藏
{
cout<<"int B::test(int a,int b,int c) called!"<<endl;
return 0;
}
char test(int a) //重写
{
cout<<"char B::test(int a) called!"<<endl;
return '0';
}
};
int main()
{
B b;
b.test(3,2,1); //"int B::test(int a,int b,int c) called!" 调用B中的test隐藏函数
b.test(1); //"char B::test(int a) called!" 调用B中的test重写函数
return 0;
}