C++ 中函数的一些概念

来源:互联网 发布:js bind 用法 编辑:程序博客网 时间:2024/06/06 07:32

梳理一些C++中函数的一些概念,比如隐藏,想说清隐藏,就肯定要提到重载,覆盖。

先说重载的一些特征:

1),在相同的范围内,也即是要在同一个类中,成员函数之间的重载。

2),函数名字相同,但是参数不同。

3),virtual关键字可以有,可以没有,

从以上特征看出,重载函数的区分是根据参数的不同,编译器会根据参数为每个重载函数产生不同的内部标识符。比如函数:

void func(int x, int y);

void func(char ch);

将产生像_func_int_int, _func_char之类的内部标识符。

重载是C++中的概念,重载函数也是c++中才有的,那么假如有一个C函数的声明是:

void func(int x, int y);

在C++中要调用这个相同的已经编译好的C函数,怎么做?

这时要使用一个连接交换制定符号 extern "C", 来解决。C中的函数被编译后在库中的标识符是_func,跟C++中编译后的名字不同。

用extern "C" 就是告诉C++编译器,函数func是一个C连接,应该在库中找名字_func,而不是找_func_int_int 。


在说覆盖的一些特征:

覆盖是指派生类函数覆盖基类函数。

1)在不同的范围内,一个在基类,一个在派生类中。

2)函数的名字相同,参数也相同。

3)基类函数必须有virutal关键字。


区分了重载和覆盖,再来看下隐藏的概念:

隐藏,是指派生类的函数屏蔽了与其同名的基类函数。

1)如果派生类中函数与基类的函数同名,参数也相同,只要基类函数没有virtual关键字,那么基类的函数就被隐藏了,如果基类函数有virtual关键字,就是覆盖了。

2)如果派生类的函数与基类的函数同名,但是参数不同,那么基类的函数就被隐藏了,这里不是重载,因为重载是在同一个类中。


那么隐藏和覆盖的区别在哪?以例子说明:

#include <iostream>#include <stdlib.h>using namespace std;class BaseClass{public:virtual void funcOverride(float num){cout << "BaseClass::funcOverride(float),,," << num << endl;}void funcHide(float num){cout << "BaseClass::funcHide(float),,," << num << endl;}void funcHideOrOverride(float num){cout << "BaseClass::funcHideOrOverride(float),,," << num << endl;}};class DerivedClass : public BaseClass{public:void funcOverride(float num){cout << "DerivedClass::funcOverride(float),,," << num << endl;}void funcHide(int num){cout << "DerivedClass::funcHide(float),,," << num << endl;}void funcHideOrOverride(float num){cout << "DerivedClass::funcHideOrOverride(float),,," << num << endl;}};int main(int argc, char *argv[]){DerivedClass dC; BaseClass *pBC = &dC;pBC->funcOverride(1.99f); //覆盖dC.funcOverride(1.99f); //覆盖pBC->funcHide(1.99f); //隐藏dC.funcHide(1.99f); //隐藏pBC->funcHideOrOverride(1.99f); //隐藏dC.funcHideOrOverride(1.99f); //隐藏return 0;}

运行结果:

DerivedClass::funcOverride(float),,,1.99
DerivedClass::funcOverride(float),,,1.99

BaseClass::funcHide(float),,,1.99
DerivedClass::funcHide(float),,,1

BaseClass::funcHideOrOverride(float),,,1.99
DerivedClass::funcHideOrOverride(float),,,1.99

先说对 funcOverride 方法的调用,继承类覆盖了基类的方法,所以用基类指针对象pBC调用时,执行了继承类的方法,这也就是C++中的动态绑定,c++中的函数调用默认不使用动态绑定,如果要触发动态绑定,必须要满足两个条件:一、只有指定为虚函数的成员函数才能进行动态绑定, 成员函数默认是非虚函数,非虚函数是不进行动态绑定的。二、必须通过基类类型的引用和指针进行函数调用。对比这两条,pBC->funcOverride(1.99f); 这句调用都满足,所以它是动态绑定,是多态性的表现。

将基类类型的指针或引用绑定到派生类对象对基对象没有影响,对象本身不会改变,仍为派生类对象。对象的实际类型可能不同于该对象引用或指针的静态类型,只是c++中动态绑定的关键。

所谓静态类型 static type,就是在编译时可知的引用类型或指针类型。

动态类型 dynamic type ,是指 指针或引用所绑定的对象的类型,这是仅在运行时可知的。

然后说 funcHide,funcHideOrOverride 这两个函数调用,按理说 pBC 这个基类指针绑定到了派生类对象,应该调用的是派生类的成员函数,但是却调用了基类的成员函数。原因是:如果函数是非虚函数,则无论实际对象是什么类型,都执行基类类型所定义的函数,只有调用虚函数时,才会根据实际绑定的对象类型,调用其定义的函数版本。

以上是覆盖,多态性的一些性质。

下面来说下隐藏,感觉跟多态、覆盖没什么关系,它是指基本的函数不可见了,本来继承类以public的方式继承了基类,那么基类的public的方法和属性,继承类都是可以直接使用的,但是如果继承类隐藏了基类的一个函数,即使这个函数在基类是public的,继承类也无法调用到,看下面的代码:

class FartherClass{public:void funcHide(char *num){cout << "FartherClass::funcHide(char),,," << num << endl;}void funcInherit(char *num){cout << "FartherClass::funcInherit(char),,," << num << endl;}};

这里添加了一个新的基类:FartherClass,

class DerivedClass : public BaseClass, public FartherClass{public:void funcOverride(float num){cout << "DerivedClass::funcOverride(float),,," << num << endl;}void funcHide(int num){cout << "DerivedClass::funcHide(int),,," << num << endl;}void funcHideOrOverride(float num){cout << "DerivedClass::funcHideOrOverride(float),,," << num << endl;}};

派生类DerivedClass是public的方式继承了FartherClass,根据前面的描述,funcHide函数隐藏了FartherClass的funcHide函数,所以派生类DerivedClass可以调用FartherClassx的funcInherit函数,但是无法调用到FartherClass的funcHide函数的,

int main(int argc, char *argv[]){DerivedClass dC; BaseClass *pBC = &dC;char str[]="ABC";        dC.funcInherit(str);dC.funcHide(str);return 0;}

这里的dC.funcHide(str);会报编译错误,invalid conversion from ‘char*’ to ‘int’ [-fpermissive]   dC.funcHide(str); 因为隐藏了父类funcHide(char *num)函数,实际调用的是自身的funcHide(int num)函数,参数由char* 到int无法转换,所以编译报错。

在这里,可能你真的是想调用基类的以字符指针为参数的函数,只是写错了参数,这时候隐藏规则给了你很好的提示,还有C++是多继承的,当有多个基类时,有时候可能搞不清楚那些基类定义了跟子类同名的函数,有了隐藏规则,调用时就会及时发现问题。


原创粉丝点击