C++ 多态

    这篇文章对多态做一个总结,同时对虚函数、纯虚函数、重载、覆盖、隐藏作相应的总结。

1.1 定义

    如果有几个相似而不完全相同的对象,有时人们要求在向他们发出同一消息时,他们的反应各不相同,分别执行不同的操作,这种情况就是多态现象。C++所谓的多态是指,由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应。在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。

2 虚函数

2.1 定义

    虚函数是一种在基类定义为virtual的函数,并在一个或多个派生类中重新定义的函数。

2.2 格式

class 类名{
    vitrual 函数声明
};

2.3 规则

  • 在基类中用virtual声明成员函数为虚函数。类外实现虚函数时,不必再加virtual;
  • 在派生类中重新定义此函数称为覆写,要求函数名,返回类型,函数参数个数及类型全部匹配。并根据派生类的需要重新定义函数体;
  • 当一个成员函数被声明为虚函数后,其派生类中完全相同的函数(显示的写出)也为虚函数。可以在其前面加上vitrual以示清晰;
  • 定义一个基类对象的指针,并使其指向子类的对象,通过该指针调用虚函数,此时调用的就是指针变量指向对象的同名函数;
  • 子类中覆写的函数,可以为任意访问类型,依子类需求决定;
  • 只有类中的成员函数才能声明为虚函数,因为虚函数仅适用于与有继承关系的类对象,所以普通函数(包括友元函数)不能声明为虚函数;
  • 静态成员函数不能是虚函数,因为静态成员函数不受限于某个对象;
  • 内联函数不能是虚函数,因为内联函数不能再运行中动态确定位置;
  • 构造函数不能是虚函数,析构函数可以是虚函数,而且通常声明为虚函数(析构函数比较特殊,因为派生类的析构函数跟基类的析构函数名称不一样,但是构成覆盖,这里编译器做了特殊处理);

有关虚函数表的介绍:虚函数表

3 纯虚函数

3.1 格式

class 类名{
    vitrual 函数声明=0;
};

3.2 规则

  • 含有纯虚函数的类,称为抽象基类,不可实例化。即不能创建对象,存在的意义就是被继承,提供族类的公共接口,java中称为interface。
  • 纯虚函数只有声明,没有实现,被“初始化”为0。
  • 如果一个类中声明了纯虚函数,而在派生类中没有对该函数定义,则该虚函数在派生类中仍然为纯虚函数,派生类仍然为纯虚基类。

4 多态

多态可以分为静多态和动多态,如下图所示。

                                         

                                                              图 1 多态

4.1 静多态

    静多态是在编译的时候就确定调用函数的类型,函数重载就是一个典型的静多态。

    函数重载的规则:(1)函数名相同;(2)参数的个数不同、参数的类型不同、参数的顺序不同,均可构成重载;(3)返回类型不同不可以构成重载;(4)相同的范围(在同一个类中)。

4.2 动多态

    在运行的时候才确定调用哪个函数,动态绑定。实质是子类重新定义了父类的虚函数,父类的指针根据赋给它的不同子类的指针,动态的调用属于子类的该函数,这样的函数调用在编译期间无法确定。这里需要引入一个概念:覆盖。覆盖是指派生类中重新定义父类中的函数,其函数名、参数列表、返回类型必须同父类中的相对应被覆盖的函数严格一致,只有函数体不同。

覆盖的规则:(1)函数名相同;(2)参数相同;(3)基类函数必须有virtual关键字;

上面已经提及重载和覆盖,接着说一下隐藏:隐藏是指派生类的函数屏蔽了与其同名的基类函数。

规则:(1)如果派生类的函数与基类的函数同名,但是参数不同,此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆);(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆);

加个图:

                                                         图2 重载、覆盖和重定义的区别

Reference :

C++中的多态(Polymorphism)是指在父类和子类之间的相互转换,以及在不同对象之间的相互转换。 C++中的多态性有两种:静态多态和动态多态。 1. 静态多态 静态多态是指在编译时就已经确定了函数的调用,也称为编译时多态C++中实现静态多态的方式主要有函数重载和运算符重载。 函数重载是指在同一作用域内定义多个同名函数,但它们的参数列表不同。编译器根据传递给函数的参数类型和数量来确定调用哪个函数。例如: ```c++ void print(int num) { std::cout << "This is an integer: " << num << std::endl; } void print(double num) { std::cout << "This is a double: " << num << std::endl; } int main() { int a = 10; double b = 3.14; print(a); // 调用第一个print函数 print(b); // 调用第二个print函数 } ``` 运算符重载是指对C++中的运算符进行重新定义,使其能够用于自定义的数据类型。例如: ```c++ class Complex { public: Complex(double real, double imag) : m_real(real), m_imag(imag) {} Complex operator+(const Complex& other) const { return Complex(m_real + other.m_real, m_imag + other.m_imag); } private: double m_real; double m_imag; }; int main() { Complex a(1.0, 2.0); Complex b(3.0, 4.0); Complex c = a + b; // 调用Complex类中重载的+运算符 } ``` 2. 动态多态 动态多态是指在运行时根据对象的实际类型来确定调用哪个函数,也称为运行时多态C++中实现动态多态的方式主要有虚函数和纯虚函数。 虚函数是在父类中定义的可以被子类重写的函数,使用virtual关键字声明。当一个对象的指针或引用指向一个子类对象时,调用虚函数时会根据实际的对象类型来确定调用哪个函数。例如: ```c++ class Shape { public: virtual void draw() { std::cout << "Drawing a shape." << std::endl; } }; class Circle : public Shape { public: void draw() override { std::cout << "Drawing a circle." << std::endl; } }; int main() { Shape* shape_ptr = new Circle(); shape_ptr->draw(); // 调用Circle类中重写的draw函数 } ``` 纯虚函数是在父类中定义的没有实现的虚函数,使用纯虚函数声明(如virtual void func() = 0;)。父类中包含纯虚函数的类称为抽象类,抽象类不能被实例化,只能作为基类来派生子类。子类必须实现父类的纯虚函数才能实例化。例如: ```c++ class Shape { public: virtual void draw() = 0; }; class Circle : public Shape { public: void draw() override { std::cout << "Drawing a circle." << std::endl; } }; int main() { Shape* shape_ptr = new Circle(); shape_ptr->draw(); // 调用Circle类中重写的draw函数 } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值