上一篇C++多态篇1一静态联编,动态联编、虚函数与虚函数表vtable中,我在最后分析了虚函数与虚函数表的内存布局,在下一篇详细剖析虚函数及虚函数表的过程中,我发现有关函数重载,函数覆盖,函数重写和函数协变的知识也要理解清楚才能对虚函数表在内存中的布局,对派生类的对象模型以及对多态的实现有更深的理解。
所以这一篇我作为一篇过渡篇,也同时对我以前写过的一篇博文进行一个收尾。在C++继承详解之二——派生类成员函数详解(函数隐藏、构造函数与兼容覆盖规则)文章中,我对函数覆盖,重载,重写提了一下,但是没有深入内存中查看内存布局,所以这一篇对前面剩下的问题做一个总结和详细解答。
注意:
因为都是我自己画的图,因为图很多,截图也挺多,写一篇文章不容易,所以有的图我画的挺大但是上传出来可能就有点小,或者颜色搭配不合理导致看不清,大家谅解一下。。ctrl+滑轮向上或者ctrl+向上键将网页放大一下看吧,感谢感谢
一、函数重载,覆盖,隐藏,协变的概念和区别
1.函数重载
首先,什么是函数重载?
成员函数被重载的特征
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无
相信对C++有一定了解的朋友都知道函数重载的条件是:
在同一个作用域内
在C++继承详解之二——派生类成员函数详解(函数隐藏、构造函数与兼容覆盖规则)的开头我也提到了,在派生类中定义一个函数名相同,参数名不同的函数,不是与基类中同名函数进行了函数重载,而是发生了函数隐藏。大家可以去我那篇文章开头看一下那个例子。
因为首先函数重载的第一个条件就没有满足,即:在相同的范围中(在同一个类中),派生类和基类是两个不同的类域,即不是同一个作用域,所以在继承中,基类和派生类之间永远不可能进行函数重载。
class Base
{
public:
Base(int data = 0)
:b(data)
{
cout << "Base()" << endl;
}
~Base()
{
cout << "~Base()" << endl;
}
void B()
{
cout << "Base::B()" << endl;
}
void B(int b)
{
cout << "Base::B(int)" << endl;
}
//B()与B(int b)构成了函数重载
//因为上面两个函数是在同一作用域中
int b;
};
class Derive :public Base
{
public:
Derive()
{
cout << "Derive()" << endl;
}
~Derive()
{
cout << "~Derive()" << endl;
}
void B(int a, int b)
{
cout << "Derive::B(int,int)" << endl;
}
//不会与Base类中的两个B名的函数构成重载
//因为作用域不同
};
下面这个图仅仅代表函数之间的关系,不代表内存布局!
那么上面的原则中提到:
virtual关键字在函数重载中可有可无
那么我们看一下加不加virtual对函数重载的影响。
(1).不加virtual
//定义一个测试函数
void Test()
{
Base b;
b.B();
b.B(1);
}
//main函数调用测试函数
运行结果为:
(2).加virtual
a.一个函数加virtual
class Base
{
public:
Base(int data = 0)
:b(data)
{
cout << "Base()" << endl;
}
~Base()
{
cout << "~Base()" << endl;
}
void B()
{
cout << "Base::B()" << endl;
}