一、函数的处理
对于不少的开发者来说,函数在开发过程中是一个必须深入掌握的知识点。函数,看起来不难,应用起来也不难。但想要把函数用到灵活自如却不是一个简单的事情。在C++编程中,函数的应用其实相当复杂,就一个函数指针便可以让开发者头疼无比,更不要提其它的用法了。
本文针对函数的升级用法进行一下分析说明,重点分析一下重载、重写、覆盖和隐藏这几个常见的用法,并对其功能、特点进行整体的对比,让大家能够有一个具体、形象的认知。
二、几个重要的函数概念
1、重载
Overloading,同一作用域内(如同一类或同一文件中)声明同名函数,但参数列表不同(参数的类型、数量或顺序),不过返回值的返回类型不同则不能认为是重载。重载的作用更倾向于同一类操作的功能,比如不同类型的值的加减这种功能。
重载的特点在于,首先必须在同一个作用域中;其次函数名必须完全相同;再次参数必须不同,这种不同体现在参数的数量、类型或顺序;最后,const与virtual以及返回值不影响重载。
2、重写
Overriding,子类重新定义父类的虚函数即virtual关键字声明的函数,从而实现运行时多态。编译器会在编译时会生成一个虚表,从而能动态的绑定具体的函数。在新的标准中,为了防止重写和隐藏的意外混淆,提供了override的关键字,当然也可以使用final禁止覆盖。它的主要作用在实现父子类相同接口的不同的具体实现,能够更好的扩展基类的行为,增加代码的灵活性和可重用性。
重写的特点在于,首先必须是在继承应用中并使用virtual标记;其次函数签名完全一致(命名、参数及const),这个要和重载区别开来;访问权限可不同。重写只能使用指针和引用来实现。
3、覆盖
一般来说,覆盖和重写的概念是同一个概念,但在有一些教学或其它特定的说明场景下,覆盖也可以特别指为隐藏。这个希望大家能够引起注意。这里把覆盖单独拿出来,也是这个意思。
4、隐藏
Hiding,其实就是父子类中,具有同名的函数(签名并不完全一致),那么子类对象访问此函数时,只能访问子类中的函数,这就相当于隐藏了父类中的函数。一般来说,隐藏作用更倾向于某种特定的情况下,比如故意想隔离父类中的函数。否则正常情况下,开发者都会写不同的函数名字来实现功能。
需要提醒的是,即使有virtual关键字,如果函数签名不是完全一致,也会引起隐藏。
三、对比分析
下面对重写等进行对比分析:
四、例程
根据前面的分析,看一下相关的例程:
//重载 1
class Demo {
public:
int add(int a, int b) { ... }
double add(double a, double b) { ... }
int add(int a, int b, int c) { ... }
};
//重载 2
int add(int a, int b) { ...}
double add(double a, double b) { ... }
int add(int a, int b, int c) { ... }
//重写/覆盖
class Base {
public:
virtual int add(int a, int b) { ... }
};
class Demo:public Base {
public:
int add(int a, int b) override { ... }
};
//隐藏
class Base {
public:
virtual int add(int a) { ... }//签名不一致
int sub(){...}
};
class Demo:public Base {
public:
int add(int a, int b) { ... }//签名不一致
int sub(int a){...}
};
代码非常简单,一看就明白了。
五、总结
基础知识是一种相对乏味的知识,在学习它们的时候往往觉得这些东西用处不大,不如写一个更有实践意义的小功能小界面什么的。但正如一些修仙小说中的,这种基础知识往往在中后期的升级中起到了不可估量的作用。在编程中,也是如此,当开发者的技术水平到达中级想到再上一层时,基础知识的匮乏就成为了瓶颈,这时候只能回头恶补了。
人往往是经历过后 才会重视,也就是常说的“人教人教不会,事教人一教就会”。