2008-11-03 88 views
9

我有一个基类带有可选的虚拟函数带有参数错误练习的非纯虚函数?

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++常见的陷阱,还是我误解了虚函数?

回答

22

忽略的设计问题,你可以省略变量名绕开有关未使用的变量的编译器警告,例如:

virtual void OnlyImplementThisSometimes(int) { } 

试图重写虚函数时误执行了错误的方法签名只是你需要在C++中小心一些。像C#这样的语言通过'override'关键字解决了这个问题。

+1

执行此操作的另一种方法(相同效果)是将内联变量名注释掉,例如:int/* x * /。如果变量名称是描述性的(它应该是),这将有助于读者。 – Nick 2008-11-04 02:32:35

+0

@尼克:我坚信强类型安全,类型描述的目的(并防止争论混乱)。如果你(大多数)这样的代码,参数名称并不重要。 – 2011-12-12 14:00:10

+0

可以编辑最后一段以反映C++中的“override”关键字。 – Rotem 2016-05-29 08:03:57

6

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

或默认的实现可能抛出一个异常

4

如果你提供了一个虚函数的默认实现,这应该是所有派生类不重写功能的正确实施。如果你不能提供正确的实现,那么我的建议是制作一个纯虚拟函数,并将其留给派生类来提供实现。不允许调用方法的派生类可以抛出异常,以确保它不会被错误地使用。

+0

如果你能想到一个通常是正确的实现,但并不总是如此,那么你可以提供一个纯虚函数的实现,并且在正常情况下派生类只是调用它。 – 2008-11-04 13:06:51

2

这在我的代码中有点常见。例如,我有专为单线程操作和多线程设计的类。有很多常见的例程和数据。我把所有这些都放在基类中(它也有一些纯虚拟的)。我在基类中实现了两个空虚拟函数:Init()和Cleanup()。单线程派生类不会提示它们,但多线程派生类可以。

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

当然,如何做到这一点可能还有其他好的建议,但是这个习语很适合我的代码。

+0

我相信,在派生类中重写一个纯虚函数,并使其不做任何事情会导致代码更清晰和更容易使用,而不是在基类中执行此操作,而不是在派生类中重写。误用的可能性较小,因为该课程的用户必须仔细考虑。 – foraidt 2008-11-04 00:43:54

3

除了简单地省略了变量名,在许多编译器,你可以告诉编译器,你都知道,它是由这样

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

严格来说,这并不会告诉编译器它没有被使用和SHUTUP。它使用它。 – 2008-11-04 13:08:41

2

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

目前我正在使用它作为用户输入系统,因为对于该类的用户来说,实现每一种方法都是很乏味的,即使它很可能也不会使用它。

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

顺便说一句,如果你知道你的基类,从未有任何需要做动态 -casts,即来源于基地。

Base *b = &d; 

会做一样好,dynamic_cast<>应该改为使用时,你得到的向下转换,即从基地:

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

(当然在向下转换的情况下,static_cast<>将平时工作也一样)

+0

我至少可以考虑一个需要动态强制转换的情况:如果您从模板参数派生,并且需要根据基本类型调用特定的函数。在我的情况是这样的:if(fixture * f = dynamic_cast (this)){f-> set_up();} – 2008-11-04 03:44:54

11

我们定义一个宏_unused为:

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

然后定义功能:

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

这不仅能保持从抱怨编译器,但这样的确明显,任何人都保持你还没有忘记X代码 - 你是故意忽略它。

-2

最简单的答案是如下图所示:

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

一个简单的参考,其(在最高水平从VC++反正)绝对没有将删除所有警告变量。

-1

试试这个:

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

这已经有一段时间,因为我已经做了类似的东西,但我相信这是你如何声明一个虚函数。

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