2

我有一个派生类,我希望其中一个函数在基类中覆盖其版本,但具有不同的签名。简单的例子:

#include "stdio.h"

bool use_foo = false;

class Foo {
public:
    virtual int func(double x) { printf ("%f in Foo!\n", x); }
};

class Bar : public Foo {
public:
    int func(short x) { printf ("%d in Bar!\n", x); }
};

int main () {
    Foo* A;
    if (use_foo) 
        A = new Foo;
    else 
        A = new Bar;

    A->func(2);
    return 0;
}

即使 A 被分配为派生类,上面的代码也会调用基类副本:

> g++ test.cpp -o test -O3 && ./test
2.000000 in Foo!

因为(据我的理解)参数可以转换为匹配基类签名,并且派生类不会因为这种差异而覆盖它(但在这种情况下它不会隐藏它吗?)。如果我将基类函数也更改为具有short参数,则派生类确实设法覆盖它。

有没有一种简单的方法来说服调用基于指针使用正确的函数?我可以像这样添加另一个函数:

class Bar : public Foo {
public:
    int func2(short x) { printf ("%d in Bar!\n", x); }
    int func(double x) { func2(x); }
};

但是我会一直转换参数(short->double->short),这个函数对性能至关重要。有没有更好的办法?

4

2 回答 2

4

这些函数签名不相同:

virtual int func(double x) {...} // base class
int func(short x) {...} // derived class

一个使用double参数,另一个使用short. 要发生覆盖,必须满足几个条件。基函数和派生函数的相同参数类型是其中之一。Bellow 是 Scott Meyers 的“Modern Effective C++”一书中关于所有要求的摘录:

• 基类函数必须是虚拟的。

• 基函数名和派生函数名必须相同(析构函数除外)。

• 基函数和派生函数的参数类型必须相同。

• 基函数和派生函数的常量必须相同。

• 基函数和派生函数的返回类型和异常规范必须兼容。

或者,使签名相同并在派生函数体内执行转换:

int func(double x) override {
    short temp = static_cast<short>(x);
    // ...
}
于 2018-03-24T13:42:42.557 回答
1

无论如何,这有什么意义?使用虚函数的原因是调用者只需要知道基类,因此只需要知道基类签名。

换句话说,具有 aFoo&或 aFoo*或 a的代码无论如何std::unique_ptr<Foo>只知道double函数的版本。double它会在调用时传递 a func,因为它还应该做什么?

也许您真正想做的是将函数的子类实现转换doubleshort. 这是一个示例,它也摆脱了对printf类型安全的 C++ 流的支持:

class Bar : public Foo {
public:
    int func(double x) { std::cout << static_cast<short>(x) << " in Bar!\n"; }
};

请注意,从 C++11 开始,我们鼓励您使用override来标记覆盖函数。

此功能对性能至关重要。

  1. 对性能至关重要的功能是否应该是虚拟的?
  2. 你真的过速度吗?是否有明显的延迟?还是计算机太快了?
于 2018-03-24T13:50:12.157 回答