C++多态

C++ 的三大特性,封装,继承,多态。封装可以使得代码模块化,继承可以扩展已存在的代码,而多态的目的则是为了接口重用。本篇博客主要介绍C++中多态的相关概念及使用方法。

概念

多态(Polymorphisn)

多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说:允许将子类类型的指针赋值给父类类型的指针(一个接口,多种方法)。
C++ 支持两种多态性:编译时多态性,运行时多态性。

a、编译时多态性(静态多态):通过重载函数实现
b、运行时多态性(动态多态):通过虚函数实现。

多态的作用

那么多态的作用是什么呢,封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。也就是说,不论传递过来的究竟是那个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。

多态的用法

运行时多态:

最常见的用法就是声明基类的指针,利用该指针指向任意一个子类对象,调用相应的虚函数,可以根据指向的子类的不同而实现不同的方法。如果没有使用虚函数的话,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。因为没有多态性,函数调用的地址将是一定的,而固定的地址将始终调用到同一个函数,这就无法实现一个接口,多种方法的目的了。

非运行时多态:

通过函数重载实现

简而言之:

有virtual才可能发生动态多态现象,无virtual调用就按原类型调用

令人迷惑的隐藏规则

隐藏是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

  • 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆,重载是在同一个类中,而隐藏涉及派生类与基类)。
  • 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆,覆盖有virtual关键字)。

C++虚函数

虚函数: 就是允许被其子类重新定义的成员函数,子类重新定义父类虚函数的做法,可实现成员函数的动态覆盖(Override)。

纯虚函数: 是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”

virtual void funtion()=0

抽象类: 包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能进行实例化。

纯虚函数的作用:

  1. 为了方便使用多态特性,我们常常需要在基类中定义虚拟函数。
  2. 在很多情况下,基类本身生成对象是不合情理的。例如,动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理。

为了解决上述问题,引入了纯虚函数的概念,将函数定义为纯虚函数(方法:virtual ReturnType Function()= 0;),则编译器要求在派生类中必须予以重写以实现多态性。同时含有纯虚拟函数的类称为抽象类,它不能生成对象。这样就很好地解决了上述两个问题。
示例代码:

#include<iostream>
using namespace std;
//基类对象
class Base
{
public:
    //有virtual关键字,运行时多态
    virtual void f(float x)
    {
        cout<<"Base::f(float)"<< x <<endl;
    }
    //无viratul关键字,不会发生运行时多态
    void g(float x)
    {
        cout<<"Base::g(float)"<< x <<endl;
    }
    void h(float x)
    {
        cout<<"Base::h(float)"<< x <<endl;
    }
};
class Derived : public Base
{
public:
    virtual void f(float x)
    {
        cout<<"Derived::f(float)"<< x <<endl;   //多态、覆盖
    }
    //子类与父类的函数同名,无virtual关键字,则为隐藏
    void g(int x)
    {
        cout<<"Derived::g(int)"<< x <<endl;     //隐藏
    }
    void h(float x)
    {
        cout<<"Derived::h(float)"<< x <<endl;   //隐藏
    }
};
int main(void)
{
    Derived d;  //子类
    Base *pb = &d;  //基类指针指向子类
    Derived *pd = &d;   //子类指针指向自己
    // Good : behavior depends solely on type of the object
    pb->f(3.14f);   // Derived::f(float) 3.14   调用子类,多态
    pd->f(3.14f);   // Derived::f(float) 3.14   调用子类
    // Bad : behavior depends on type of the pointer
    pb->g(3.14f);   // Base::g(float)  3.14 无多态,调用自己的
    pd->g(3.14f);   // Derived::g(int) 3    无多态,调用自己的
    // Bad : behavior depends on type of the pointer
    pb->h(3.14f);   // Base::h(float) 3.14  无多态,调用自己的
    pd->h(3.14f);   // Derived::h(float) 3.14   无多态,调用自己的
    return 0;
}

转载自http://huqunxing.site/2016/09/08/C++%20%E4%B8%89%E5%A4%A7%E7%89%B9%E6%80%A7%E4%B9%8B%E5%A4%9A%E6%80%81/

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函数 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值