是带有参数的非纯虚拟函数的不良做法

Are non-pure virtual functions with parameters bad practice?

本文关键字:函数 不良 虚拟 参数      更新时间:2023-10-16

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

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"param实现了派生函数,但没有任何警告。这些只是C++中常见的陷阱,还是我误解了虚拟函数?

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

virtual void OnlyImplementThisSometimes(int ) { }

在C++中,当试图重写虚拟函数时,错误地实现错误的方法签名是需要小心的。像C#这样的语言可以用override关键字来解决这个问题。

我们将宏_unused定义为:

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

然后将函数定义为:

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

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

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

或者默认实现可能引发异常

如果您提供了一个虚拟函数的默认实现,那么它应该是所有未覆盖该函数的派生类的正确实现。如果你不能提供一个正确的实现,那么我的建议是制作一个纯虚拟函数,让派生类来提供实现。不允许调用该方法的派生类可以引发异常,以确保该方法不会被错误使用。

除了简单地省略变量名之外,在许多编译器中,您可以告诉编译器,您知道它是未使用的,并通过执行来关闭

int func(int x)
{
   (void) x;
}

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

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

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

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

这是一种不错的做法,也是指定类中可选择实现的部分的常见习惯用法。

目前,我正在将其用于用户输入系统,因为对于该类的用户来说,实现每一个方法都是乏味的,即使他很可能无论如何都不会使用它。

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) {}
};

Btw,如果你知道你的基类,就永远不需要进行动态的up-转换,即从派生到基类。

Base *b = &d;

也可以,当你下投时,应该使用dynamic_cast<>,即从基础到衍生:

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

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

试试这个:

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

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

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

最简单的答案如下所示:

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

对变量的简单引用绝对不起任何作用,将删除所有警告(无论如何都是从VC++的最高级别)。