c++多态

 多态的概念

多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会 产生出不同的状态

多态的条件:

1虚函数重写

2父类的指针或者引用去调用虚函数

虚函数重写

父子继承关系中两个虚函数,三同(函数名,参数,返回)

virtual只修饰成员函数

斜变

三同有个例外:斜变->返回值可以不同,必须是父子类的指针或者引用

virtual的语法

基类有虚函数,派生类的函数可以不加virtual

new的情况下才需要析构函数虚函数重写

防止内存泄漏

final

1.修饰虚函数,不能让虚函数重写

2.修饰类,不能被继承

 

override

修饰派生类的虚函数,检查是否完成重写

抽象类

纯虚函数(=0)无法实例化出对象,可以定义出指针,见接的检测出是否重写了。在现实中人不需要实例化,但是人是抽象的,没有具体的对象,如果派生类是职业,比如是医生、护士、程序员等那么就可以实例化了。

接口继承和实现继承

普通函数的继承是一种实现继承,派生类继承了基类函数,可以使用函数,继承的是函数的实
现。虚函数的继承是一种接口继承,派生类继承的是基类虚函数的接口,目的是为了重写,达成
多态,继承的是接口。所以如果不实现多态,不要把函数定义成虚函数。

多态的原理

虚函数表

只要有虚函数就会多一个虚函数表指针_vfptr,叫做虚函数表指针,简称虚表。虚函数在os中存在代码段,虚函数表中只存虚函数的地址。虚函数和普通函数一样,都是存在代码段,同时把虚函数的地址存了一份到虚函数表。

虚函数重写(虚函数覆盖)

派生类的虚表需要生成一张新的虚表,那么就需要重写,覆盖成新的虚函数,如果不需要重写的那么就拷贝相同的地址。

虚表的调用

因为虚函数的必要条件是调用父类的指针或者引用,所以父子类各自都有自己的虚表,父类的虚函数要调用父类的虚表,子类的虚函数要调用子类的虚表,如果不是引用或者指针,那么传值的时候就会子类对象的虚函数值传给父类,就会造成传值覆盖,如果传的是引用或者指针,那么就会进行切割,子调用子的,父调用父的。

补充

1.父子类即使虚表内容一样,那么虚表的地址也不一样

2.不同的类用不同的虚表,同一个类用同一张虚表。

虚函数和虚函数表的地址

虚函数的地址

虚函数和普通函数一样,都是存在代码段,同时把虚函数地址存了一份到虚函数表中,他们是存储在代码段(常量区)  

虚函数的地址一定放进虚函数的表,而语法规定取虚函数地址一定要加&和类域:: 

虚函数表的地址

打印虚函数表

vfptr是一个指针,里面存储了虚函数表的地址,也就是函数指针数组的地址

定义一个函数指针,该函数指针是为了方便后续取函数指针地址用

typedef void(*VFPTR) ();

这里我们取对象地址,由于是在64位处理器的情况,所以要将强转成long long取前8个字节,再强转成用函数指针

 VFPTR* vTableb1 = (VFPTR*)(*(long long*)&d);

 那么我们就可以打印出来虚函数表

class Base1 {
public:
    virtual void func1() {cout << "Base1::func1" << endl;}
    virtual void func2() {cout << "Base1::func2" << endl;}
    virtual void func3() {cout << "Base1::func3" << endl;}
private:
    int b1;
};
class Base2 {
public:
    virtual void func1() {cout << "Base2::func1" << endl;}
    virtual void func2() {cout << "Base2::func2" << endl;}
private:
    int b2;
};
class Derive : public Base1, public Base2 {
public:
    virtual void func1() {cout << "Derive::func1" << endl;}
    virtual void func3() {cout << "Derive::func3" << endl;}
private:
    int d1;
};
typedef void(*VFPTR) ();
void PrintVTable(VFPTR vTable[])
{
    cout << " 虚表地址>" << vTable << endl;
    for (int i = 0; vTable[i] != NULL; ++i)
    {
        printf(" 第%d个虚函数地址 :0X%x,->", i, vTable[i]);
        VFPTR f = vTable[i];
        f();
    }
    cout << endl;
}
int main()
{
    Base1 d;
    VFPTR* vTableb1 = (VFPTR*)(*(long long*)&d);
    PrintVTable(vTableb1);
//    VFPTR* vTableb2 = (VFPTR*)(*(long long *)((char*)&d+sizeof(Base1)));
//    PrintVTable(vTableb2);
    return 0;
}

多继承的虚表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值