使用覆盖函数继承

时间:2016-02-16 14:20:52

标签: c++

我正在查看一些C ++示例代码,它有效地具有以下内容:

class Foo : public mynamespace::Bar
{
public:

    Foo()
    {
        // Do some stuff
    }

    void Delta() override
    {
        // Do some stuff

        Bar::Delta();
    }
};

我无法理解为什么行Bar::Delta();存在。鉴于类Foo继承了类Bar,那么当调用Foo::Delta()时,这会覆盖Bar::Delta()中存在的任何内容,因此该行是多余的。

或者我误解了整个继承的事情?也许override不会覆盖所有内容?

5 个答案:

答案 0 :(得分:3)

Bar::Delta();

是一个函数调用。这不是它的样子吗?

它正在调用Delta的基类版本 - 通过明确地将其Bar::Delta - 添加到以及Foo版本所做的任何额外内容。

  

也许覆盖不会覆盖所有内容?

override关键字只是要求编译器验证你是否真的覆盖了虚函数 - 否则,很容易意外地编写一个不会覆盖任何东西的新函数(例如,因为参数类型稍微有点不同的,或者一个版本是const限定的,或者您更改了基类并忘记更新派生类,或者......)。

这里 覆盖虚拟功能。这并不会阻止现有的基类实现,正如您所见,您仍然可以调用它。

你可以(并且应该)自己测试你对此类事物的直觉。考虑下面的简单测试代码。你认为它会做什么?

现在实际运行它。你是对的吗?如果没有,哪一部分意外?

#include <iostream>
using namespace std;

struct Bar {
    virtual void Delta() {
        cout << "Bar::Delta\n";
    }
};

struct Foo : public Bar {
    void Delta() override
    {
        cout << "Foo::Delta\n";
        Bar::Delta();
    }
};

int main()
{
    cout << "b.Delta()\n";
    Bar b;
    b.Delta();

    cout << "f.Delta()\n";
    Foo f;
    f.Delta();

    cout << "pb->Delta()\n";
    Bar *pb = &b;
    pb->Delta();

    cout << "pb->Delta()\n";
    pb = &f;
    pb->Delta();
}

答案 1 :(得分:3)

这是一种常见的模式。实际上,调用重写成员函数的::语法专门针对这种情况。

基类中的成员函数执行某些计算或操作是非常常见的,这些计算或操作可以独立于派生类完成,并让派生类执行特定于派生的事情。

这是一个虚构的例子:

class Stock {
protected:
    double totalDividend;
    double baseDividend;
    double adjustmentFactor;
public:
    Stock(double d, double a)
    : baseDividend(d), totalDividend(d), adjustmentFactor(a) {
    }
    virtual void double ComputeDividend() {
        return totalDividend * adjustmentFactor;
    }
};

class SpecialStock {
private:
    double specialDividend;
public:
    SpecialStock(double d, double sd, double a)
    : Stock(d, a), specialDividend(sd) {
    }
    virtual void double ComputeDividend() override {
        // Do some preparations
        totalDividend = baseDividend + specialDividend;
        // Call the overridden function from the base class
        return Stock::ComputeDividend();
    }
};

答案 2 :(得分:1)

  

也许覆盖不会覆盖所有内容?

当覆盖一个被覆盖的函数是虚拟的并且实际上被覆盖的函数时,覆盖说明符可用于进行编译时检查。

  

为什么行Bar :: Delta();存在

此行调用基本Delta函数,即使您已覆盖它,也可能会执行一些有用的任务。

一个简单的例子:

class Base
{
public:
    virtual ~Base() {}
    virtual void Foo()
    {
        // run tasks that are common to all derived types
    }
};

class Derived : public Base
{
public:
    void Foo() override
    {
        Base::Foo(); // we have to call this explicitly
        // run tasks specific to the derived type
    }
};

答案 3 :(得分:1)

您似乎误解了overridec++的含义。对于你的情况,你不应该为此烦恼。这就像一个普通的虚拟功能。 override关键字只是一种安全机制,可确保基类具有匹配功能。除了语义编译时检查之外,它不会改变任何内容。

防止典型的不匹配有点有用,例如const与非const版本等。

虚方法机制不会替换原始成员函数。它仍然存在于Derived对象中。会发生什么情况是引入了间接级别,因此对base.foo()的调用使用函数指针来调用正确的实现,在您的情况下为Derived::Foo()。但是Base::Foo()仍然存在,这是“访问”它的语法。您可以通过在virtual方法上搜索材料来查找其工作原理。

答案 4 :(得分:1)

foo中的Delta是一种虚拟方法,可以做一些事情&#34;然后调用基类的Delta实现。

覆盖不会覆盖任何内容,将该方法声明为虚拟方式。 override只是让编译器在父类没有Delta方法的情况下抛出语法错误。

相关问题