C++第08课 虚函数和多态 (一)

1.虚函数

+ 在类中用virtual 修饰的函数 叫做虚函数
+ 没有虚构造函数,但是存在虚析构函数
   虚函数对于类的类内存影响
    + 没有数据成员类是占用1个字节,普通函数对于类的内存是毫无影响
    + 所有虚函数都是用一个指针存储:虚函数指针
    + 通过虚函数表的理解去访问虚函数

class MM {
public:
    virtual void print1() {
        cout << "print1" << endl;
    }
    virtual void print2() {
        cout << "print2" << endl;
    }
};

int main()
{
    //通过虚函数表访问虚函数
    MM mm;
    int** p = (int**)&mm;
    void (*pfun1)() = (void(*)())p[0][0];                //print1
    pfun1();
    void (*pfun2)() = (void(*)())p[0][1];                //print2
    pfun2();

    typedef void(*pFun)();
    void (*pfun11)() = (pFun)((int**)(&mm))[0][0];        //print1
    pfun11();
    void (*pfun22)() = (pFun)((int**)(&mm))[0][1];        //print2
    pfun22();

    return 0;
}

2.纯虚函数和抽象类

+ 纯虚函数是一种特殊的虚函数,纯虚函数是没有函数体的,注意写法
+ 具有至少一个纯虚函数的类叫做抽象类
+ 抽象类不能构建对象
+ 抽象类可以构建对象指针
+ 抽象类产生一个子类,子类想要构建对象,必须要重写父类中的纯虚函数

class MM {
public:
    //纯虚函数
    virtual void print() = 0;
};
//只有在子类重写了父类的纯虚函数才能构建对象
class Girl :public MM{
public:
    void print()
    {
        cout << "Hello World!" << endl;
    }
};
int main()
{
    //不能构建对象
    MM* mm = nullptr;

    Girl g;
    g.print();
    return 0;
}

3.多态实现

+ 数据类型上多态:基类指针可以被父类和子类对象初始化
+ 函数调用上的多态:相同的函数调用导致的不同的行为(结果)

多态的必要条件:

+ 必须存在虚函数,子类中必须存在一样的函数
+ 必须存在不正常指针引用关系(指针赋值)
+ 必须是public继承

class MM {
public:
    virtual void print() {
        cout << "MM print" << endl;
    }
    void printMM() {
        cout << "print MM" << endl;
    }
};

class Girl :public MM{
public:
    void print() {
        cout << "Girl print" << endl;
    }
    void printMM() {
        cout << "print Girl" << endl;
    }
};

int main()
{
    //正常的赋值关系
    //MM mm;
    //mm.print();                //MM print
    //MM& mm1 = mm;
    //mm1.print();            //MM print
    //MM* mm2 = new MM;
    //mm2->print();            //MM print

    //Girl gg;
    //gg.print();                //Girl print
    //Girl& gg1 = gg;
    //gg1.print();            //Girl print
    //Girl* gg2 = new Girl;
    //gg2->print();            //Girl print

    //不正常的赋值关系
    MM* p = new Girl;        //父类指针用子类对象初始化,即子到父,称为上行转换
    p->print();                //Girl print 如果没有virtual调用的就是父类的
    p->printMM();            //print MM

    Girl g;
    MM& p1 = g;
    p1.print();                //Girl print
    p1.printMM();            //print MM


    Girl* pp = static_cast<Girl*>(new MM);    //子类指针用父类对象初始化,即父到子,称为下行转换
    pp->print();            //MM print
    pp->printMM();            //print Girl

    MM mm;
    Girl& pp2 = static_cast<Girl&>(mm);
    pp2.print();            //MM print
    pp2.printMM();            //print Girl

    return 0;
}

 

posted @ 2021-09-06 20:13  Creature_lurk  阅读(36)  评论(0编辑  收藏  举报