在基类使用虚拟机时,在类层次结构中使用虚拟

时间:2014-10-22 15:20:07

标签: c++ polymorphism

我不理解Stroustrup的 A Tour of C ++ ,第43和44页的继承示例。我复制了一个表明我困惑的最小例子:

#include <iostream>

class Shape {
public:
    virtual void draw() const = 0;
    virtual ~Shape() {};
};

class Circle : public Shape {
public:
    Circle(int p, int rr) : x{p}, r{rr} {}
    void draw() const { std::cout << "In Circle::draw()" << std::endl; }
private:
    int x;
    int r;
};

class Smiley : public Circle {
public:
    Smiley(int p, int r): Circle{p,r}, mouth(nullptr) {}
    ~Smiley() { delete mouth; }
    void draw() const { std::cout << "In Smiley::draw()" << std::endl; }

private:
    Shape* mouth;
};

int
main(int argc, char *argv[])
{
    Circle *smiley;
    smiley = new Smiley(3, 4);
    smiley->draw();

    Circle *circle;
    circle = new Circle(3, 4);
    circle->draw();

    return 0;
}

令我困惑的是Circle :: draw不是虚拟的。我看到了,并认为这一定是一个错字。由于虚拟表示要查看定义的派生类,因此我不认为Smiley的绘制将从基本Circle引用中以多态方式调用。但是,我运行代码并获得以下输出:

In Smiley::draw()
In Circle::draw()

请帮忙。这怎么可能?当Circle :: draw不是虚拟时,Smiley :: draw是如何从Circle *指针调用的?当heirarchy的基类是虚拟的(Shape :: draw)时,是否没有必要为更多派生类的函数(例如Smiley :: draw)声明派生类函数virtual(例如Circle :: draw)?

2 个答案:

答案 0 :(得分:11)

Circle::draw实际上是虚拟的!这是因为Shape::draw是虚拟的。从基类覆盖虚函数时,该函数自动为虚函数,不需要关键字。我想提供虚拟关键字,以明确它是一个虚拟功能,但它是可选的。

在C ++ 11中,您可以标记重写的函数override,以确保它们实际上覆盖了虚函数。这可以防止错误。

void draw() const override

答案 1 :(得分:2)

我认为答案是即使没有指定,绘制仍然是虚拟的,只要第一次绘制声明(在类层次结构的顶部)被声明为虚拟。