函数重载
在同一个作用域中,两个函数的函数名相同,参数个数,参数类型,参数顺序至少有一个不同,函数返回值的类型可以相同,也可以不相同。
C++中支持函数重载是因为C++中会对函数进行名字修饰。Name Mangling是一种在编译过程中,将函数、变量的名称重新改编的机制,简单来说就是编译器为了区分各个函数,将函数通过某种算法,重新修饰为一个全局唯一的名称。
C语言只是简单的在函数名前添加下划线。因此当工程中存在相同函数名的函数时,就会产生冲突。所以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;
}
这里的Add(10, 20);
会去调用int Add(int left, int right)
函数。
这里的Add(10.0, 20.0);
会去调用double Add(double left, double right)
函数。
这里的Add(10L, 20L);
会去调用long Add(long left, long right)
函数。
重定义
重定义(也叫做隐藏)是指在继承体系中,子类重新定义父类中有相同名称的非虚函数 ( 参数列表可以不同 ) ,此时子类的函数会屏蔽掉父类的那个同名函数。
如果想要调用父类的那个成员函数必须要加上父类的域作用限定符。
重定义规则如下:
- 如果派生类的函数和基类的函数同名,但是参数不同,此时,不管有无virtual,基类的函数被隐藏。
- 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字,此时,基类的函数被隐藏(如果相同有Virtual就是重写覆盖了)。
重定义代码
class A
{
public:
A(){}
void show()
{
cout << "A::show()" << endl;
}
};
class B:public A
{
public:
B(){}
void show()
{
cout << "B::show()" << endl;
}
};
int main()
{
A* a = new A;
B* b = new B;
A* c = new B;
a->show();
b->show();
c->show();
return 0;
}
- 这里的a是指向父类对象的父类指针,因此调用show函数时,调的是父类的show函数。
- b是指向子类对象的子类指针,因此调用show函数时,此时父类和子类的show函数构成了重定义,因此子类对象去调用的时候会屏蔽掉父类的同名函数,因此调的是子类对象的show函数。
- c是指向子类对象的父类指针,指针的类型是父类指针,不是多态看类型,因此调用的是父类的show函数。
重写
重写(也叫做覆盖)是指在继承体系中子类定义了和父类函数名,函数参数,函数返回值完全相同的虚函数。此时构成多态,根据对象去调用对应的函数。
重写需要注意:
- 被重写的函数不能是static的。必须是virtual的
- 重写函数必须有相同的类型,名称和参数列表
- 重写函数的访问修饰符可以不同。尽管virtual是private的,派生类中重写改写为public,protected也是可以的
重写代码
class A
{
public:
A(){}
virtual void show(){ cout << "A::show()" << endl; }
//virtual void print(){ cout << "A::print()" << endl; }
virtual void fun(){ cout << "A::fun()" << endl; }
};
class B :public A
{
public:
B(){}
virtual void show(){ cout << "B::show()" << endl; }
//virtual int print(){ cout << "B::print()" << endl; }
virtual void fun(int i){ cout << "B::fun()" << endl; }
};
int main()
{
A* a = new B;
a->show();
a->fun();
B* b = new B;
b->fun(1);
return 0;
}
-
这里的show函数都是虚函数,并且函数参数返回值都相同,所以构成重写,构成多态。所以是多态看对象,那么这里的a指向的是子类的对象,因此
a->show();
打印出来的是子类的show函数。 -
print函数返回值类型不同,不构成多态,也不满足协变,因此报错。
-
fun函数的参数不同,所以虽然是虚函数但是也不构成重写,这里构成了隐藏。因此
a->fun();
中,不是多态看类型,所以调的是父类的fun函数,b->fun(1);
中,b指向的是子类的对象,因此会自动屏蔽掉父类的同名函数去调子类的fun函数。