学了一阵子感觉这个东西特别绕,记录下自己的理解,当然如果理解错了!请各位指出来,感激!
c++中的虚函数:
同一个类型的指针(基类指针),指向不同类型的对象(派生类),调用同一函数(虚函数),实现不同的功能(函数实现)
虚函数都存储在一个表中,相同类型的虚函数(同一个基类派生出来的),这些函数在续表中的映射地址是相同的,函数地址当然不同(当派生类中的虚函数被重载)。
而虚函数的地址也是可以被输出显示的:显示规则如下:此段代码以及解释转载自:chick here
#include <iostream> #include <stdio.h> using namespace std; class Base { public: virtual void f() { cout << "Base::f" << endl; } virtual void g() { cout << "Base::g" << endl; } void h() { cout << "Base::h" << endl; } }; class hehe:public Base{ virtual void haha(){ cout << "rnrn" << endl; } void f(){ cout << "haha" << endl; } }; typedef void(*Fun)(void); //函数指针 int main() { Base b; hehe c; // 这里指针操作比较混乱,在此稍微解析下: // *****printf("虚表地址:%p\n", *(int *)&b); 解析*****: // 1.&b代表对象b的起始地址 // 2.(int *)&b 强转成int *类型,为了后面取b对象的前四个字节,前四个字节是虚表指针 // 3.*(int *)&b 取前四个字节,即vptr虚表地址 // // *****printf("第一个虚函数地址:%p\n", *(int *)*(int *)&b);*****: // 根据上面的解析我们知道*(int *)&b是vptr,即虚表指针.并且虚表是存放虚函数指针的 // 所以虚表中每个元素(虚函数指针)在32位编译器下是4个字节,因此(int *)*(int *)&b // 这样强转后为了后面的取四个字节.所以*(int *)*(int *)&b就是虚表的第一个元素. // 即f()的地址. // 那么接下来的取第二个虚函数地址也就依次类推. 始终记着vptr指向的是一块内存, // 这块内存存放着虚函数地址,这块内存就是我们所说的虚表. // printf("虚表地址:%p\n", *(int *)&b); printf("第一个虚函数地址:%p\n", *(int *)*(int *)&b); printf("第二个虚函数地址:%p\n", *((int *)*(int *)(&b) + 1)); printf("第一个虚函数地址:%p\n", *(int *)*(int *)&c); printf("第二个虚函数地址:%p\n", *((int *)*(int *)(&c) + 1)); //Fun pfun = (Fun)*((int *)*(int *)(&b)); /itural f(); //printf("f():%p\n", pfun); //pfun(); //pfun = (Fun)(*((int *)*(int *)(&b) + 1)); /itural g(); //printf("g():%p\n", pfun); //pfun(); }举个例子,异质单链表的简单构成: 同一链表中,存储不同类型的信息(1.学生类的信息 2。老师类的信息)
先定义person类,构造print 的虚函数,之后派生出 学生和老师类,在链表中,指针的类型为person(基类),而输出时候,便可以调用虚函数来实现输出不同的结果。
代码例子如下:
#include <iostream> #include <stdio.h> using namespace std; class List; class person { friend class List; public: person(int _age, char *s) { age=_age; name=s; Next=NULL; } virtual ~person() {}; virtual void print() { cout<<" name is "<<name<<endl; cout<<" age is "<<age<<endl; } protected: int age; char *name; person* Next; }; class teacher:public person { public: teacher(int _age,char *s,int _title):person(_age,s) { title=_title; } void print() { person::print(); cout<<" title is "<<title<<endl; } protected: int title; }; class student:public person { public: student(int _age,char *s,int _number):person(_age,s) { number=_number; } virtual void print() { person::print(); cout<<" number is "<<number<<endl; } void sp() { cout<<"gggg"<<endl; } protected: int number; }; class List { private: person * head; int siz; public: List() { head=NULL;siz=0; } void Insert(person *p) { person *tmp=head; if(head==NULL) { head=p; } else { while(tmp->Next!=NULL) { tmp=tmp->Next; } tmp->Next=p; } siz++; } void show() { person *tmp=head; if(head==NULL) { cout<<"No one"<<endl; return ; } while(tmp!=NULL) { tmp->print(); tmp=tmp->Next; } } }; int main(void) { List root; char a[20]="abc"; char b[20]="def"; teacher prof1( 40,a ,2); student prof2( 50,b, 4); root.Insert(&prof1 ); //把prof1插入到personList中 root.Insert(&prof2 ); //把prof2插入到personList中 root.show(); //输出personList各结点的数据域值 }