zoukankan      html  css  js  c++  java
  • C++学习22 多态的概念及前提条件

    在《C++基类和派生类的赋值》一节中讲到,基类的指针也可以指向派生类对象。请看下面的例子:

    #include <iostream>
    using namespace std;
    class People{
    protected:
        char *name;
    public:
        People(char *name):name(name){}
        void display(){ cout<<"People: "<<name<<endl;}
    };
    class Student: public People{
    public:
        Student(char *name):People(name){}
        void display(){ cout<<"Student: "<<name<<endl;}
    };
    int main(){
        People *p = new People("Xiao Ming");
        p->display();
        p = new Student("Li Lei");
        p->display();
        return 0;
    }

     运行结果:
    People: Xiao Ming
    People: Li Lei

    我们通常认为,如果指针指向了派生类对象,那么就应该使用派生类的成员变量和成员函数,这符合人们的思维习惯。

    但是本例的运行结果却告诉我们:当基类指针 p 指向派生类 Student 的对象时,虽然使用了 Student 的成员变量,但是却没有使用它的成员函数,造成输出结果不伦不类,不符合我们的预期。

    如果希望通过 p 指针访问 Student 类的成员函数,可以将该成员函数声明为虚函数,请看下面的代码:

    #include <iostream>
    using namespace std;
    class People{
    protected:
        char *name;
    public:
        People(char *name):name(name){}
        //加virtual关键字声明为虚函数
        virtual void display(){ cout<<"People: "<<name<<endl;}
    };
    class Student: public People{
    public:
        Student(char *name):People(name){}
        //加virtual关键字声明为虚函数
        virtual void display(){ cout<<"Student: "<<name<<endl;}
    };
    int main(){
        People *p = new People("Xiao Ming");
        p->display();
        p = new Student("Li Lei");
        p->display();
        return 0;
    }

    运行结果:
    People: Xiao Ming
    Student: Li Lei

    与上面的代码相比,这段代码仅仅是在 display() 函数声明前加了一个 virtual 关键字,将成员函数声明为了虚函数(Virtual Function)。这样,就可以通过 p 指针调用 Student 类的成员函数了,运行结果也证明了这一点。

    借助虚函数,基类指针既可以使用基类的成员函数,也可以使用派生类的成员函数,它有多种形态,或多种表现方式,这就是多态(Polymorphism)。

    上面的代码中,同样是p->display();这条语句,当 p 指向不同的对象时,它执行的操作是不一样的。同一条语句可以执行不同的操作,看起来有不同表现方式,这就是多态

    多态是面向对象的主要特征之一。在C++中,虚函数的唯一用处就是构成多态。

    C++提供多态的目的是:可以通过基类指针对所有派生类(包括直接派生和间接派生)的成员变量和成员函数进行“全方位”的访问,尤其是成员函数。如果没有多态,我们只能访问成员变量。

    构成多态的条件

    多态存在的三个条件:

    • 必须存在继承关系;
    • 继承关系中必须有同名的虚函数,并且它们是覆盖关系(重载不行)。
    • 存在基类的指针,通过该指针调用虚函数。

    注意:派生类中的虚函数必须覆盖(不是重载)基类中的虚函数,才能通过基类指针访问。请看下面的代码:

    #include <iostream>
    using namespace std;
    class Base{
    public:
        void a(){ cout<<"Base::a()"<<endl; }
        virtual void b(){ cout<<"Base::b()"<<endl; }
        virtual void c(){ cout<<"Base::c()"<<endl; }
    };
    class Derived: public Base{
    public:
        //覆盖基类普通成员函数,不构成多态
        void a(){ cout<<"Derived::a()"<<endl; }
        //覆盖基类虚函数,构成多态
        virtual void b(){ cout<<"Derived::b()"<<endl; }
        //重载基类虚函数,不构成多态
        virtual void c(int n){ cout<<"Derived::c()"<<endl; }
        //派生类新增函数
        int d(){ cout<<"Derived::d()"<<endl; }
    };
    int main(){
        Base *p = new Derived;
        p -> a();
        p -> b();
        p -> c(0);  //Compile Error
        p -> d();  //Compile Error
        return 0;
    }
  • 相关阅读:
    XX宝面试题——css部分
    XX宝面试题——JS部分
    Struts、JSTL标签库的基本使用方法
    JavaScript:学习笔记(10)——XMLHttpRequest对象
    SpringBoot学习笔记:单元测试
    SpringMVC:学习笔记(11)——依赖注入与@Autowired
    SpringBoot学习笔记:动态数据源切换
    Django:学习笔记(9)——视图
    Django RF:学习笔记(8)——快速开始
    CNN学习笔记:批标准化
  • 原文地址:https://www.cnblogs.com/Caden-liu8888/p/5813354.html
Copyright © 2011-2022 走看看