友元函数必须在类中进行声明而在类外定义,声明时须在函数返回类型前面加上关键字friend。友元函数虽不是类的成员函数,但它可以访问类中的私有和保护类型数据成员。
虚函数在重新定义时参数的个数和类型必须和基类中的虚函数完全匹配,这一点和函数重载完全不同。
函数的重载是指C++允许多个同名的函数存在,但同名的各个函数的形参必须有区别:形参的个数不同,或者形参的个数相同,但参数类型有所不同。
覆盖(Override)是指派生类中存在重新定义的函数,其函数名、参数列、返回值类型必须同父类中的相对应被覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体 (花括号中的部分)不同,当派生类对象调用子类中该同名函数时会自动调用子类中的覆盖版本,而不是父类中的被覆盖函数版本,这种机制就叫做覆盖。
下面我们从成员函数的角度来讲述重载和覆盖的区别。
成员函数被重载的特征有:
- 相同的范围(在同一个类中);2) 函数名字相同;3) 参数不同;4) virtual关键字可有可无。
覆盖的特征有: - 不同的范围(分别位于派生类与基类);2) 函数名字相同;3) 参数相同;4) 基类函数必须有virtual关键字。
隐藏是指派生类的函数屏蔽了与其同名的基类函数,规则如下: - 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。2) 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
#include<stdio.h>
#include<stdlib.h>
class A
{
public:
A()
{
printf("%s", "A");
}
virtual void fun()
{
printf("%s", "funA");
}
void g(float x)
{
printf("%s","A::G");
}
void h(float x)
{
printf("%s", "A::H");
}
virtual void show()
{
printf("%s","showA");
}
void rose(int a)
{
printf("%s", "roseA");
}
};
class B:public A
{
public:
B()
{
printf("%s","B");
}
//B::fun()覆盖A:fun()
virtual void fun()
{
printf("%s","funB");
}
//函数B::g(int)隐藏了A::g(float)
void g(int x)
{
printf("%s","B::G");
}
//函数B::h(float)隐藏了A::h(float),而不是覆盖。
void h(float x)
{
printf("%s", "B::H");
}
/*显式地调用自己类中的 "由A类继承过来的show()函数" ,
像这种直接显式指出某个类的某个函数时,
编译器处理方式是这样的: 首先在自己类中找有没有A::show(),
如果找到,调用.不在继续在A类中找,
如果找不到,则在显式指出的那个类中(即A类)调用那个函数.
这里当然是在B类中可以找到A::show() ,因为基类中指出了这个函数是virtual函数. */
virtual void show()
{
A::show();
}
void rose(int a,int b)
{
printf("%s","roseB");
}
};
int main()
{
A *a = new B();//输出AB
B *b = new B();//输出AB
a->fun();//输出funB
b->fun();//输出funB
a->g(4.0);//输出A::G
b->g(4.0);//输出B::G
a->h(3.14); //输出A::H
b->h(3.14);//输出B::H
a->show();//输出showA
b->show();//输出showA
b->A::show();//输出showA
a->rose(3);//roseA
//a->rose(3,4);//error
//b->rose(3);//error
b->rose(3,4);//roseB
getchar();
}