在这一篇文章开始之前,我先解决一个问题。
在上一篇C++继承详解之一——初探继承中,我提到了在派生类中可以定义一个与基类成员函数同名的函数,这样派生类中的函数就会覆盖掉基类的成员函数。
在谭浩强的C++程序设计这本书第十一章,351页最下面有这么一段话:
可在派生类中声明一个与基类成员同名的成员函数,则派生类中的新函数会覆盖基类的同名成员,但应注意:如果是成员函数,不仅应是函数名相同,而且函数的参数表(参数的个数和类型)也应相同,如果不相同,就会成为函数重载而不是覆盖了、用这样的方法可以用新成员取代基类的成员。
但是经过我的实验,这段话就是错误的,派生类中定义与基类成员函数同名不同参数表的函数是不能构成函数重载的,先上代码:
class A
{
public:
int a_data;
void a()
{
cout << "A" << endl;
}
};
class B
{
public:
int b_data;
void b()
{
cout << "B" << endl;
}
};
class C :public A, public B
{
public:
int c_data;
void a(int data)//重载A类中的a()函数
{
cout << "C" << endl;
}
};
int main()
{
C c;
c.a();
return 0;
}
编译后,编译器会报错
Error 1 error C2660: 'C::a' : function does not take 0 arguments e:\demo\继承\way\project1\project1\source.cpp 86 1 Project1
2 IntelliSense: too few arguments in function call e:\DEMO\继承\way\Project1\Project1\Source.cpp 86 6 Project1
错误表明:编译器并没有将c.a()看做C类继承自A类的a()函数,而是报错没有给a函数参数,即不构成函数重载,如果给c.a(1)一个参数,编译通过。输出:C
那么我们不给C类中定义同名函数呢
class A
{
public:
int a_data;
void a()
{
cout << "A" << endl;
}
};
class B
{
public:
int b_data;
void b()
{
cout << "B" << endl;
}
};
class C :public A, public B
{
public:
int c_data;
//void a(int data)
//{
// cout << "C" << endl;
//}
};
int main()
{
C c;
c.a();
return 0;
}
编译通过,运行输出:A
以上两个例子,完全可以说明,当我们在派生类中定义一个同名函数的时候,编译器是将同名函数隐藏了,不管参数表是否相同。即不会构成函数重载,直接为函数覆盖。
那么问题来了,为什么不会构成函数重载呢?
一定要注意,函数重载的条件是在同一个作用域中才会构成函数重载,而派生类和基类是两个类域,一定不会构成函数重载的
现在进入这篇文章的主题,派生类成员函数的解答,因为开篇我们讲的这个例子,我先从函数覆盖写起。
一、函数覆盖、函数隐藏、函数重载
先分别讲一下函数覆盖,隐藏和重载分别是什么:
1.成员函数被重载的特征
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
//virtual关键字在这里看不懂也可以,在下一篇文章中我会详细解答
覆盖是指派生类函数覆盖基类函数,特征是
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
当派生类对象调用子类中该同名函数时会自动调用子类中的覆盖版本,而不是父类中的被覆盖函数版本,这种机制就叫做覆盖。
派生类对象调用的是派生类