您的位置:首页 > 编程语言 > C语言/C++

c++ 编译时函数匹配和运行时类型识别

2013-04-03 10:28 218 查看
重载:在同一个作用域下面同名不同参的两个函数互为重载函数;
覆盖:父类的虚函数在子类中重写了,同名同参的父类虚函数被重写;
隐藏:父类中的某个函数名为fun(int,double)函数,子类中同名函数fun(xxx),无论参数是否相同,都将父类中的函数给覆盖了,虽然你会觉得很恶心,但是cxx大师本杰明在设计cxx的时候处于安全考虑:某些c++程序员可能根部不知道父类中有这么个名字的函数,在子类中写了个同名函数,在传参的时候传的不是那么准确,这个时候其实给父类的函数给他执行是一件很恐怖的事情,所以会出现后来cxx的隐藏。
先说下,编译时期的函数匹配的问题,比如一个对象Derived d;这么个对象,在编译的时候d.test();编译器会到d的类中给它找到同名test的函数,然后实参匹配形参,匹配度最高的为他的入口地址,如果找到两个匹配度相同的函数,则编译器报错;
eg:
class Base {
public:
virtual int test() {cout << "base" << endl;}
};
class Derived: public Base {
public:
int test(int i) {cout << "derived:int"<< endl;}
int test(double i) {cout << "derived:double" << endl;}
};
int main(){
Derived d;
d.test();
}
d.test();会使得编译器在子类中查找名字为test的,结果找到两个test(int i)和test(double),注意:这里是找不到Base中的test()函数的,理由上面解释的很清楚,本杰明大师在设计cxx的时候就明确不允许去基类中找同名函数使得某些程序员误以为程序是对的;所以这一句会引起cxx编译器的报错;
如果我们把Derived的定义改写为如下形式:
class Derived :public Base {
public:
int test(int i) {cout <<"derived:int" <<endl;}
int test(double i) {cout <<"derived:double" <<endl;}
using Base::test;
};
此时这种情况下,由于程序员告诉了编译器,我他妈的就是要到基类中找到匹配的函数,这个时候编译器会让你去,因为不存在误解;这个时候d.test();会找到三个匹配的函数,最后匹配度最高的当然是父类中的那个了,参数匹配;ok,编译通过,当然如果这里将父类中的test函数设置为private,编译器仍然会报错,因为你用using Base::test实际上是人以为父类中的test是pulic的,编译器这里报错是很合理的,他告诉你你的想法错了;

隐藏大概就上面这些,接下来讲解下万众瞩目的覆盖了;
覆盖,其实在每个地方都定义不一样,在这里的意思指的是子类中重定义父类中的虚函数;
首先,我们要弄明白为什么父类会设计虚函数,其实父类的设计者知道这个函数会被重定义;被重定义后,Base *b = new Derived();b的内存模型很简单,
其实,虚函数表是在编译期间生成的,为什么?因为每个类的虚函数表其实是一样的,在编译期间生成好了之后,到时候直接放到内存中就行了,每个类只需要一个虚函数表就够了,运行期间的每个对象只需要一个4字节的指针就可以指向虚函数表了,多省空间啊。也就是说,虚函数表示编译期间就画好了,换句话说,函数的覆盖其实也是在编译期间完成的,所谓的运行时类型识别,用下面的例子来解释吧:
Base *pb = new Derived();此时pb是一个Base指针,但是他指向的是一个derived对象,刚才不是说了么derived对象会有一个虚函数表指针,该指针指向类Derived的虚函数表,就是说在运行的时候pb会先找到derived对象,然后通过该对象找到相应的虚函数表,再找到虚函数表中响应函数的入口,最后调用了Derived类的函数;
对于下面这种情况,Base* pb = new Base();此时pb指向的是一个Base对象,最终找到的是Base类的虚函数表,然后Base的函数。这就达到了运行时类型识别;
所以虚函数表在编译期间生成的好处就是省空间啊;第一个是虚函数指针,指向一个虚函数表,虚函数表的第一个函数是test(),假设在Derived中test()函数被重定义了,这个时候编译器会让Derived的test()去覆盖Base的test(),然后假设Base中有第二个虚函数test2(),就会在虚函数表的Derived::test()之后的一个表格内,依次类推;
注意:父类的虚函数表会被子类先继承,然后覆盖;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: