具有参数的非纯虚函数是不是很难实践?

时间:2008-11-03 23:56:22

标签: c++ polymorphism

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

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

当我编译它时,我得到一个关于未使用的param 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 ++中常见的陷阱还是我误解了虚函数?

10 个答案:

答案 0 :(得分:22)

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

virtual void OnlyImplementThisSometimes(int ) { }

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

答案 1 :(得分:11)

我们将宏_unused定义为:

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

然后将函数定义为:

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

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

答案 2 :(得分:6)

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

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

答案 3 :(得分:4)

如果提供虚函数的默认实现,则对于不覆盖该函数的所有派生类,它应该是正确的实现。如果你不能提供正确的实现,那么我的建议是创建一个纯虚函数,并将其留给派生类来提供实现。不允许调用该方法的派生类可以抛出异常,以确保不会错误地使用它。

答案 4 :(得分:3)

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

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

答案 5 :(得分:2)

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

我在基类中实现了两个空虚函数:Init()和Cleanup()。单线程派生类不会实现它们,但是多线程派生类会这样做。

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

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

答案 6 :(得分: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) {}
};

答案 7 :(得分:2)

顺便说一下,如果你知道你的基类,那么从来没有必要做动态 up -casts,即从派生到基础。

Base *b = &d;

同样会这样做,dynamic_cast<>应该在您向下投射时使用,即从基础到派生:

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

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

答案 8 :(得分:-1)

试试这个:

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

我已经做了类似的事情已经有一段时间了,但我相信这就是你宣布虚拟功能的方式。

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

答案 9 :(得分:-2)

最简单的答案如下所示:

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

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