C++面向对象 多态&虚函数的一个例子

C++面向对象 多态&虚函数的一个例子

在给人讲题时使用的,对Runoob C++ 多态的扩展。1

例子

先看基类和继承类的定义:基类Shape提供了方法area()display_area()用来求图形面积和显示图形面积,子类RectangleCircle分别重写了这两个方法,按照长方形和圆形的性质重新定义。

class Shape{
    public:
        double area(){
            return 0;
        }
        void display_area(){
            cout << "Shape Area = " << area() << endl;
        }
};

class Rectangle : public Shape{
    private:
        int width;
        int length;
    public:
        Rectangle(int a, int b){
            width = a;
            length = b;
        }
        double area(){
            return width * length;
        }
        void display_area(){
            cout << "Rectangle Area = " << area() << endl;
        }
};

class Circle : public Shape{
    private:
        int rad;
    public:
        Circle(int a){
            rad = a;
        }
        double area(){
            return 3.14 * rad * rad;
        }
        void display_area(){
            cout << "Circle Area = " << area() << endl;
        }
};

继承

简单继承,不涉及多态的主函数:分别实例化RectangleCircle对象,调用函数输出其面积。

int main(){
    Rectangle r1(3, 4);
    Circle c1(5);
    // point to rectangle
    Rectangle* r_ptr = &r1;
    r_ptr->display_area();
    // point to circle
    Circle* c_ptr = &c1;
    c_ptr->display_area();
}

输出结果:

Rectangle Area = 12
Circle Area = 78.5

静态多态&缺陷

主函数通过一个Shape指针分别指向实例化的RectangleCircle对象,实现多态。这里没用到virtual.

int main(){
    Rectangle r1(3, 4);
    Circle c1(5);
    Shape* s_ptr;
    // point to rectangle
    s_ptr = &r1;
    s_ptr->display_area();
    // point to circle
    s_ptr = &c1;
    s_ptr->display_area();
}

执行程序输出:

Shape Area = 0
Shape Area = 0

导致错误输出的原因是早绑定,并不太懂,可以参考2。总之,编译时因为s_ptrShape*类型,所以默认调用Shape :: display_area()Shape :: area(),而这并不是我们想要的。

动态多态

Shape :: area()声明为虚函数:

class Shape{
    public:
        virtual double area(){
            return 0;
        }
        void display_area(){
            cout << "Shape Area = " << area() << endl;
        }
};

重新执行上一节的主函数,结果为:

Shape Area = 12
Shape Area = 78.5

解析:第一次s_ptr->display_area()时,因为早绑定,首先执行Shape :: display_area();在display_area()函数体调用area()时,因为area()声明为虚函数,所以优先寻找子类的area()实现,所以此处的area()执行的是Rectangle :: area()。第二次同理。(上面说的“执行”指的是编译时绑定)

Shape :: display_area()声明为虚函数:

class Shape{
    public:
        double area(){
            return 0;
        }
        virtual void display_area(){
            cout << "Shape Area = " << area() << endl;
        }
};

重新执行上一节的主函数,结果为:

Rectangle Area = 12
Circle Area = 78.5

是想要的结果。

解析:第一次s_ptr->display_area()时,因为display_area()声明为虚函数,所以首先执行Rectangle :: display_area(),进而执行Rectangle :: area(),跟Shape :: area()没有关系。第二次同理。(上面说的“执行”指的是编译时绑定)

两个都虚?同理分析。

纯虚函数

在正常应用中,我们通常不希望程序调用Shape :: area(),并输出Shape Area = 0的结果。因此,Shape :: area()就不该有定义,且尝试调用Shape :: area()的行为应该报错。纯虚函数就是为这种情况服务的:把Shape :: area()定义为“没有”,只能从子类找area()的定义。

class Shape{
    public:
        virtual double area() = 0;
        virtual void display_area() = 0;
};

纯虚函数要求:

  • 子类必须重写(重新按照接口要求实现)父类中定义的纯虚函数。如果不这么做会报错:cannot declare variable ‘r1’ to be of abstract type ‘Shape’ because the following virtual functions are pure within ‘Shape’: virtual void area() = 0;
  • 包含纯虚函数的父类不能被实例化,报和上面一样的错。

这里的细节我还没搞清楚,比如为什么会报这个错。这不重要。

含有纯虚函数的基类的使用方法:定义一个基类类型的指针,指向派生类,调用派生类中已经重写过的方法。

注意:基类定义纯虚函数和基类无定义,子类新定义的区别在于,前者是“定义为没有”,后者是“没有定义”。

参考


  1. Runoob C++ 多态 ↩︎

  2. 早绑定和晚绑定 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值