202001300-01 C++17 多态再学习 override final 纯虚函数 虚函数带默认参数

一、前言:

  1. 用一句解释何为多态
  2. 虚函数
  3. 纯虚函数
  4. 派生类和基类调用的关系和方法

二、正文

2.1 何为多态(我的理解)

一个成员函数直到运行或者编译时才确定具体使用的实现类型

多态里面有三种形式:重载、重写、覆盖
重载:同一个类函数名相同但是参数不同
class A {
    virtual void test(double a);
    void test(int a);
    void testA();
}

重写:基类标注 virtual 子类有相同的函数名,相同参数
class B : private A {
    void test(double a) override;
}

覆盖:基类没有标注 virtual 子类有相同函数名,参数无关
class C : private A {
    void testA(int a);
}

2.2 虚函数

简单而言,虚函数就是基类成员函数前标注 virtual 的那部分 virtual viod get();

 

2.2.1 override 和 final

这两个函数声明需要放在一个函数最后面(比如 void get() const override;)

override 标识符作用

1 编译器会检查函数是否写错

2 提高函数的可读性

final 标识符作用

1 子类将不允许再重写该函数

class A {
private:
    virtual void getVal(){ 
        std::cout << "A:123" << std::endl;
    }
    virtual void getTest() final { //不允许子类重写
        std::cout << "A:223" << std::endl;
    }
};

class B : private A {
public:
    void getVal() override {//即便基类是私有类,子类依旧可以重写
        std::cout << "B:321" << std::endl;
    }
    void getTest() override; //这样无法通过编译
};

 

2.2.2 基类私有化虚函数

示例如 2.2.1 所示,其作用有二:

1 子类可以正常重定义该虚函数

2 避免外界调用该函数,保证封装的完整性

 

2.2.3 虚函数带默认参数

结论:存有子类的基类调用虚函数,默认参数取决于基类的默认值(具体看示例)

class A {
public:
    virtual void getVal(int a = 10) {
        std::cout << "A:" << a << std::endl;
    }
};
class B : public A {
    void getVal(int a = 123) override {
        std::cout << "B:" << a << std::endl;
    }
};
int main() {
    A* a = new B;
    a->getVal();
}
//output
B:10

2.2.4 dynamic_cast 应用场景

基类到子类且(基类至少带有一个虚函数),因为 dynamic_cast 是带有运行检查的,可以确保得到一个非虚的函数,错误返回 nullptr;

其他情况可以使用 static_cast

 

2.2.5 析构或构造函数调用 虚函数

这个时候由于是静态调用,默认会直接调用该虚函数在父类的实现

 

2.3 纯虚函数

特征一:virtual void test() = 0; 就是末尾 "=0“

特征二:不能被构建对象

特征三:常用于 C++ 声明接口

class A {
public:
    virtual int getVal() = 0;
};

class B : public A {
public:
    int getVal() override {
        std::cout<<"B:"<<222<<std::endl;
        return 100;
    }
};

class C : public A {
public:
    int getVal() override {
        std::cout << "C:"<<333<<std::endl;
        return 222;
    }
};

int main() {
    B b;
    C c; 
    std::vector<A*> aPtr {&b, &c}; 
    for (const auto& temp : aPtr) 
        temp->getVal(); 
}

//output
B:222
C:333

 

2.4 派生类与基类的之间调用

2.4.1 派生类对象的地址可以存在基类指针或引用中,反之不行

由于派生类继承了基类全部成员,因此不会出现基类调用的对象在派生类中不存在

class A {
    
};

class B : public A {

};

class C : public A {

};

int main() {
    A *a1 = new B;
    A *a2 = new C;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值