C++中虚函数

学了一阵子感觉这个东西特别绕,记录下自己的理解,当然如果理解错了!请各位指出来,感激!

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各结点的数据域值
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值