C++自学篇 虚函数

前言:

笔者以前只学过C语言,没有学过C++,在新项目中用到C++做开发,因此需要快速学习C++。
注:
1.编译环境:g++.exe (x86_64-posix-seh-rev3, Built by MinGW-W64 project) 11.2.0
2.virtual关键字主要用于基类申明虚函数,override关键字主要用于衍生类申明重写函数。在项目中,只要基类使用virtual关键字申明了虚函数,其衍生类如果想改变此成员函数的实现,则必定会出现override关键字申明重写函数。
3.本篇使用的BaseClass代表基类,使用的DerivedClass代表衍生类。

1.虚函数的继承与virtual的使用

下述程序用于研究基类及其衍生类是否使用virtual关键字,对编译/运行造成的影响。

#include <iostream>

class BaseClass
{
public:
    void run_1(void) {
        printf("%s: BaseClass\r\n", __func__);
    }

    virtual void run_2(void) {
        printf("%s: BaseClass\r\n", __func__);
    }

    void run_3(void) {
        printf("%s: BaseClass\r\n", __func__);
    }

    virtual void run_4(void) {
        printf("%s: BaseClass\r\n", __func__);
    }
};

class DerivedClass : public BaseClass
{
public:
    void run_1(void) {
        printf("%s: DerivedClass\r\n", __func__);
    } 

    void run_2(void) {
        printf("%s: DerivedClass\r\n", __func__);
    }

    virtual void run_3(void) {
        printf("%s: DerivedClass\r\n", __func__);
    }

    virtual void run_4(void) {
        printf("%s: DerivedClass\r\n", __func__);
    }
};

int main(int argc, char *argv[])
{
    // Example_1: 基类指针 创建基类
    printf("BaseClass Pointer, New BaseClass:\r\n");
    BaseClass *baseLivingExample_1 = new BaseClass();
    baseLivingExample_1->run_1();   // BaseClass
    baseLivingExample_1->run_2();   // BaseClass
    baseLivingExample_1->run_3();   // BaseClass
    baseLivingExample_1->run_4();   // BaseClass
    delete baseLivingExample_1;

    // Example_2: 基类指针 创建衍生类
    printf("BaseClass Pointer, New DerivedClass:\r\n");
    BaseClass *baseLivingExample_2 = new DerivedClass();
    baseLivingExample_2->run_1();   // BaseClass
    baseLivingExample_2->run_2();   // DerivedClass
    baseLivingExample_2->run_3();   // BaseClass
    baseLivingExample_2->run_4();   // DerivedClass
    delete baseLivingExample_2;

    // Example_3: 衍生类指针 创建基类(编译错误)
    // printf("DerivedClass Pointer, New BaseClass:\r\n");
    // DerivedClass *derivedLivingExample_3 = new BaseClass();
    // derivedLivingExample_3->run_1();
    // derivedLivingExample_3->run_2();
    // derivedLivingExample_3->run_3();
    // derivedLivingExample_3->run_4();
    // delete derivedLivingExample_3;

    // Example_4: 衍生类指针 创建衍生类
    printf("DerivedClass Pointer, New DerivedClass:\r\n");
    DerivedClass *derivedLivingExample_4 = new DerivedClass();
    derivedLivingExample_4->run_1();    // DerivedClass
    derivedLivingExample_4->run_2();    // DerivedClass
    derivedLivingExample_4->run_3();    // DerivedClass
    derivedLivingExample_4->run_4();    // DerivedClass
    delete derivedLivingExample_4;

    return 0;
}

总结:
1.基类指针可以接收基类实体,衍生类指针可以接收衍生类实体
2.基类指针可以接收衍生类实体,衍生类指针不可以基类实体
3.基类的成员函数没有加“virtual”前缀,如果基类和衍生类的成员函数命名一致,则衍生类实体默认使用基类的成员函数
4.基类的成员函数有加“virtual”前缀,如果基类和衍生类的成员函数命名一致,则衍生类实体默认使用衍生类的成员函数

2.虚函数的继承与override的使用

下述程序用于研究衍生类是否使用override关键字,对编译/运行造成的影响。

#include <iostream>

class BaseClass
{
public:
    virtual void run_1(void);
    virtual void run_2(void);
    void run_3(void);
    void run_4(void);
};

class DerivedClass : public BaseClass
{
public:
    void run_1(void) override;
    virtual void run_2(void) override;
    // void run_3(void) override;           // 编译报错
    // virtual void run_4(void) override;   // 编译报错
    // void run_5(void) override;           // 编译报错
    // virtual void run_6(void) override;   // 编译报错
};

void BaseClass::run_1(void)
{
    printf("%s: BaseClass\r\n", __func__);
}

void BaseClass::run_2(void)
{
    printf("%s: BaseClass\r\n", __func__);
}

void DerivedClass::run_1(void)
{
    printf("%s: DerivedClass\r\n", __func__);
}

void DerivedClass::run_2(void)
{
    printf("%s: DerivedClass\r\n", __func__);
}

int main(int argc, char *argv[])
{
    // Example_1: 基类指针 创建基类
    printf("BaseClass Pointer, New BaseClass:\r\n");
    BaseClass *baseLivingExample_1 = new BaseClass();
    baseLivingExample_1->run_1();   // BaseClass
    baseLivingExample_1->run_2();   // BaseClass
    delete baseLivingExample_1;

    // Example_2: 基类指针 创建衍生类
    printf("BaseClass Pointer, New DerivedClass:\r\n");
    BaseClass *baseLivingExample_2 = new DerivedClass();
    baseLivingExample_2->run_1();   // DerivedClass
    baseLivingExample_2->run_2();   // DerivedClass
    delete baseLivingExample_2;

    // Example_3: 衍生类指针 创建基类(编译错误)
    // printf("DerivedClass Pointer, New BaseClass:\r\n");
    // DerivedClass *derivedLivingExample_3 = new BaseClass();
    // derivedLivingExample_3->run_1();
    // derivedLivingExample_3->run_2();
    // delete derivedLivingExample_3;

    // Example_4: 衍生类指针 创建衍生类
    printf("DerivedClass Pointer, New DerivedClass:\r\n");
    DerivedClass *derivedLivingExample_4 = new DerivedClass();
    derivedLivingExample_4->run_1();    // DerivedClass
    derivedLivingExample_4->run_2();    // DerivedClass
    delete derivedLivingExample_4;

    return 0;
}

总结:
1.基类指针可以接收基类实体,衍生类指针可以接收衍生类实体
2.基类指针可以接收衍生类实体,衍生类指针不可以基类实体
3.衍生类使用“override”,对应的基类相同命名成员函数必须带有“virtual”的前缀
4.衍生类使用“override”,其基类必须有相同命名成员函数

3.使用基类指针接收的衍生类实体

下述程序用于研究基类指针接收的衍生类实体调用各个类的成员函数,对编译/运行造成的影响。

#include <iostream>

class BaseClass
{
public:
    virtual void run();
    virtual void show(void) {
        printf("%s: BaseClass\r\n", __func__);
    }
};

class DerivedClass_1 : public BaseClass
{
public:
    void run(void);
    void show(void) override;
    void show_1(void) {
        printf("%s: DerivedClass_1\r\n", __func__);
    }
};

class DerivedClass_2 : public BaseClass
{
public:
    void run(void) override;
    void show(void) override;
    void show_2(void) {
        printf("%s: DerivedClass_2\r\n", __func__);
    }
};

class DerivedClass_3 : public BaseClass
{
public:
    virtual void run(void);
    void show(void) override;
    void show_3(void) {
        printf("%s: DerivedClass_3\r\n", __func__);
    }
};

class DerivedClass_4 : public BaseClass
{
public:
    virtual void run(void) override;
    void show(void) override;
    void show_4(void) {
        printf("%s: DerivedClass_4\r\n", __func__);
    }
};

void BaseClass::run(void)
{
    printf("%s: BaseClass\r\n", __func__);
}

void DerivedClass_1::run(void)
{
    printf("%s: DerivedClass_1\r\n", __func__);
}

void DerivedClass_1::show(void)
{
    show_1();
}

void DerivedClass_2::run(void)
{
    printf("%s: DerivedClass_2\r\n", __func__);
}

void DerivedClass_2::show(void)
{
    show_2();
}

void DerivedClass_3::run(void)
{
    printf("%s: DerivedClass_3\r\n", __func__);
}

void DerivedClass_3::show(void)
{
    show_3();
}

void DerivedClass_4::run(void)
{
    printf("%s: DerivedClass_4\r\n", __func__);
}

void DerivedClass_4::show(void)
{
    show_4();
}

int main(int argc, char *argv[])
{
    BaseClass *baseLivingExample[] = {
        new BaseClass,
        new DerivedClass_1,
        new DerivedClass_2,
        new DerivedClass_3,
        new DerivedClass_4,
    };

    for (int i = 0; i < sizeof(baseLivingExample) / sizeof(baseLivingExample[0]); i++) {
        baseLivingExample[i]->run();
    }

    baseLivingExample[0]->show();
    // baseLivingExample[1]->show_1(); // 编译报错
    // baseLivingExample[2]->show_2(); // 编译报错
    // baseLivingExample[3]->show_3(); // 编译报错
    // baseLivingExample[4]->show_4(); // 编译报错
    baseLivingExample[1]->show();
    baseLivingExample[2]->show();
    baseLivingExample[3]->show();
    baseLivingExample[4]->show();

    for (int i = 0; i < sizeof(baseLivingExample) / sizeof(baseLivingExample[0]); i++) {
        delete baseLivingExample[i];
    }

    return 0;

总结:
1.基类指针可以接收基类实体,基类指针可以接收衍生类实体
2.基类指针接收的衍生类实体,不允许访问衍生类特有的成员函数
3.基类想要访问衍生类特有的成员函数,需要用虚函数,在衍生类中实现虚函数去调用对应的成员函数
4.在实际项目中,可以用基类的指针数组统一管理各个衍生类的实体

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值