C++重载与重写的各种问题
知识复习
在探究C++虚函数造成的各种重写的问题之前,我们先复习一下C++中的函数重载
1.const在函数重载中的定义
对于下几种情况,哪几个算是函数重载呢?
//情况1
void fun(int a);
void fun(const int a);
//情况2
void fun(int* a);
void fun(const* a);
//情况3
void fun(int* a)
void fun(int const * a);
//情况4
void fun(int *a)
void fun(int *const a);
答案是:2,3是函数重载,1,4是重定义
情况1
我们可以假设这样的调用情况
fun(1)
那么对于第一种定义,我们可以看到
int a=1
是可以的,而第二种定义
const int a=1
同样也没问题,所以这里我们也就可以理解这里为什么是重定义了
情况2
我们可以假设这样的调用情况
const int b=1;fun(&b);
那么对于第一种定义,我们可以看到
int* a=&b
是不可以的,因为const int*
是不可以向int *
装换的,而第二种定义
const int* a=&b
毫无问题,所以我们可以通过这种方法将两种方法区分出来,那么传入int*
调用的是那种呢?是第一种,因为,第一种显然更匹配一些。
情况3
哈哈,const int *
和int const *
是等价的,所以如同情况2一样
情况4
这种情况就和情况1类似,这里就不多做解释了
总结
在C++中,函数重载还是重定义靠的是,是否有一种调用情况能将两种函数区分开来,如果能就是重载,否则就是重定义。
const在重载与重写中的作用
我们考虑这样的情况,以下两个函数哪个是重载,哪个是重写?
class A
{
public:
void test_const(int a)
{
}
void test_const_function(int a)
{
}
};
class B:public A
{
public:
//情况1
void test_const(int a)
{
}
//情况2
void test_const_function(int a) const
{
}
}
答案是情况1是重写,情况2是重载
情况1
这个很简单,相当于上边的情况1,因为我们无法区分调用在传入相同参数调用哪个函数,所以是重定义,但是用在虚函数上边就变成了重写。
情况2
但这是为什么呢?
其实是因为在类里边
void test_const_function(int a)
{
}
|
|
|会被改写成
|
v
void test_const_function(A&a,int a)
{
}
void test_const_function(int a) const
{
}
|
|
|会被改写成
|
v
void test_const_function(const A&a,int a)
{
}
那么就变成了上边情况2,所以变成了重载,重写失败。
默认参数在重载与重写中的作用
情况如下,那些会调用成功呢?
class A
{
void test_default_parament(int a,int b=4)
{
cout<<"A:"<<a<<" B:"<<b<<endl;
}
}
class B:public A
{
void test_default_parament(int a=0,int b=0)
{
cout<<"A:"<<a<<" B:"<<b<<endl;
}
}
int main()
{
B* bpoint=new B
A* apoint=bpointer;
//情况1
apoint-> test_default_parament(1,2);
//情况2
apoint-> test_default_parament(1);
//情况3
apoint-> test_default_parament();
}
答案是情况1和情况2,情况3会被认为缺少参数
分析
根本原因是默认参数时静态绑定的
apoint-> test_default_parament(1);
|
|
|
V
apoint-> test_default_parament(1,4)
//绑定父类的默认参数
apoint-> test_default_parament(1);
|
|
|
V
apoint-> test_default_parament(1,0)
//绑定子类函数的默认参数
说以略微思考一下,就可以知道为什么上边会调用失败了吧,更深一步,我们也可以知道函数具体输出的结果
总结
最好的方法是,不要在虚函数中使用默认参数,如果我们真的想用怎么办呢,世界之大,方法总会有的么。
private,public在重载与重写中的作用
有以下几种情况,哪几种会调用成功呢?
class A
{
public:
virtual void Test_public()
{
cout<<"father"<<endl;
}
private:
virtual void Test_private()
{
cout<<"father"<<endl;
}
};
class B:public A
{
public:
virtual const int Test_private()
{
}
private:
virtual void Test_public()
{
}
};
int main()
{
B* bpointer=new B;
A* apointer=bpointer;
bpointer->Test_private();
bpointer->Test_public();
apointer->Test_public();
apointer->Test_private();
return 0;
}
嘿嘿,这里不给出答案了,比较难打,但是代码写的比较全,各位可以运行一下
为什么呢?其实本质这里也是一样的,对于操作权限都是静态绑定的
总结
- 函数权限,默认参数都是静态绑定的
- 函数重载和重定义都是依靠是否能有一种调用情况区分调用函数的