9

我有一个带有可选虚函数的基类

class Base {
    virtual void OnlyImplementThisSometimes(int x) {}
};

当我编译这个时,我收到一个关于未使用的参数 x 的警告。还有其他一些我应该实现虚拟功能的方法吗?我已经像这样重写了它:

class Base {
    virtual void OnlyImplementThisSometimes(int x) 
    {
        x = 0;
    }
};

我还有一个问题,如果我不小心,我制作的子类可能会实现错误的功能,然后由于重载而我没有注意到:例如

class Derived : public Base {
    void OnlyImplementThisSometimes(int x, int y) { // some code }
};

Derived d;
Base *b = dynamic_cast<Base *>(&d);
b->OnlyImplementThisSometimes(x); // calls the method in the base class

之所以调用基类方法,是因为我使用“int y”参数实现了派生函数,但对此没有任何警告。这些只是 C++ 中的常见缺陷还是我误解了虚函数?

4

10 回答 10

22

忽略设计问题,您可以通过省略变量名称来绕过编译器警告未使用的变量,例如:

virtual void OnlyImplementThisSometimes(int ) { }

在尝试覆盖虚函数时错误地实现了错误的方法签名只是您在 C++ 中需要小心的事情。像 C# 这样的语言使用 'override' 关键字来解决这个问题。

于 2008-11-04T00:09:54.463 回答
11

我们将宏定义_unused为:

#define _unused(x) ((void)x)

然后将函数定义为:

virtual void OnlyImplementThisSometimes(int x) { _unused( x );}

这不仅使编译器不会抱怨,而且让任何维护代码的人都清楚你没有忘记 x —— 你故意忽略它。

于 2008-11-04T00:53:03.843 回答
6

为什么要在基类中定义它?如果基类不打算使用该方法,那么只需将其定义为派生类中的虚拟方法。

或者默认实现可能会抛出异常

于 2008-11-04T00:04:02.057 回答
4

如果您提供虚函数的默认实现,它应该是所有不覆盖该函数的派生类的正确实现。如果您无法提供正确的实现,那么我的建议是制作一个纯虚函数并将其留给派生类来提供实现。不允许调用方法的派生类可以抛出异常,以确保不被误用。

于 2008-11-04T00:04:38.390 回答
3

除了简单地省略变量名之外,在许多编译器中,您可以告诉编译器,您知道它是未使用的,并且通过这样做 SHUTUP

int func(int x)
{
   (void) x;
}
于 2008-11-04T00:14:39.523 回答
2

这在我的代码中有些常见。例如,我有专为单线程操作和多线程设计的类。有很多常见的套路和数据。我把所有这些都放在基类中(它也有几个纯虚拟的)。

我在基类中实现了两个空虚函数:Init() 和 Cleanup()。单线程派生类不隐含它们,但多线程派生类可以。

我有一个工厂函数创建适当的派生类,然后返回一个指针。客户端代码只知道基类类型,它调用 Init() 和 Cleanup()。这两种情况都是正确的。

当然,关于如何做到这一点,可能还有其他好的建议,但是这个习惯用法适用于我的很多代码。

于 2008-11-04T00:12:33.473 回答
2

这不是一个不好的做法,它是指定类中可选实现的部分的常见习惯用法。

目前我将它用于用户输入系统,因为该类的用户实现每一个方法都会很乏味,即使他很可能不会使用它。

class mouse_listener{
public:
    virtual ~mouse_listener() {}

    virtual void button_down(mouse_button a_Button) {}
    virtual void button_up(mouse_button a_Button) {}
    virtual void scroll_wheel(mouse_scroll a_Scroll) {}
    virtual void mouse_move_abs(math::point a_Position) {}
    virtual void mouse_move_rel(math::point a_Position) {}
};
于 2008-11-04T00:18:23.133 回答
2

顺便说一句,如果你知道你的基类,就永远不需要做动态向上转换,即从派生到基类。

Base *b = &d;

也可以,dynamic_cast<>应该在你向下转换时使用,即从基础到派生:

if((Derived *d = dynamic_cast<Derived *>(b)) != 0)
{
  // use d
}

(当然,在向下投射的情况下,static_cast<>通常也会起作用。)

于 2008-11-04T00:50:10.700 回答
-1

试试这个:

class Base {
    virtual void OnlyImplementThisSometimes(int x) = 0;
};

我已经有一段时间没有做过这样的事情了,但我相信这就是你声明虚函数的方式。

也正如其他人所说,变量名在这样的函数声明中是可选的。

于 2008-11-05T20:51:04.737 回答
-2

最简单的答案如下所示:

class Base {
    virtual void OnlyImplementThisSometimes(int x) { x;}
};

对绝对不执行任何操作的变量的简单引用将删除所有警告(无论如何来自最高级别的 VC++)。

于 2008-11-04T09:30:44.237 回答