2012-01-03 93 views
1

从Java的角度来看,我惊讶地发现只能覆盖具有virtual关键字的基本方法。 在Java中,您使用final关键字来声明方法不能被覆盖。C++中的重写规则

我曾在我的脑海的想法,你很少想禁止压倒一切,从而使他人可以扩展你的类他们如何认为合适的。

在C++

所以,如果你觉得有人会从你的类中的一些阶段继承想(也许几年后有人认为它是一个很酷的想法),你让所有的方法虚拟?

还是有希望为C++中,我不知道禁止一些这方面的关键原因是什么?

借鉴这是试验我每种语言做的:

的Java

public class Base { 

    void doSomething(){ 
    System.out.println("Doing the base thing"); 
    } 
    } 
    public class Derived extends Base { 

    void doSomething(){ 
    System.out.println("Doing the derived thing"); 
    } 

    public static void main(String... argv){ 
     Base object = new Derived(); 
     object.doSomething(); 
    } 
    } 

C++

class Base 
    { 
    public: 
     Base(void); 
     ~Base(void); 
     virtual void doSomething(); 
    }; 

    void Base::doSomething(){ 
     std::cout << "I'm doing the base thing\n" << std::endl; 
    } 

    class Derived : 
     public Base 
    { 
    public: 
     Derived(void); 
     ~Derived(void); 
     void doSomething(); 
    }; 

    void Derived::doSomething(){ 
     std::cout << "I'm doing the dervied thing" << std::endl; 
    } 


    int main(void){ 

     Base * object = new Derived; 

     object->doSomething(); 
     return 0; 

    } 
+0

的可能重复的[当在C++标记的功能作为虚拟?](http://stackoverflow.com/questions/8298041/when-to-mark-a-function-in-c-as-a-虚拟) – 2012-01-03 10:35:59

回答

1

duffymo和Als正朝着正确的方向引导你。我只是想在一件事情上,你说要评论:

所以在C++中,如果你觉得有人可能要在某些阶段从你的类继承 (也许几年后有人认为它是一个很酷的想法)做 你让你的所有方法变得虚拟?

从软件工程的角度来看:如果你没有立即使用继承并且没有使用接口,那么我不建议你声明你的方法是虚拟的。

虚拟方法拿出一个曾经如此轻微性能下降。对于非关键代码路径,性能影响可能可以忽略不计。但是对于被调用很多的类方法,它可以加起来。编译器不能做太多内联和直接链接。相反,被调用的虚拟方法必须在运行时在v表数组中查找。

当有人对我的编码团队开始了与设计谈话时,我的“未来验证”反模式警报响起“有人可能想在某个时候后...”那是。设计可扩展性是一回事,但“未来的特征”应该推迟到那个时候。

再说 - 这家伙年以后谁认为这是一个很酷的想法 - 让他自己转换类方法是虚拟的一个。无论如何,你将会进入更大的项目。 :)

+0

注意的虚方法对性能的影响仅仅是对C真正++或者有实际上不同的覆盖方式(甚至那么可以乐观地内联等) – Voo 2012-01-03 21:18:05

1

是,在C++中一个类的方法只能是overidden,如果它在基类中标记为virtual

如果你的类是继承做你的类方法是指为基地提供不同的行为和导出然后标记方法virtual

良好阅读:

When to mark a function in C++ as a virtual?

1

是的,你必须让所有的方法是虚拟的。

的Java采取的立场是一切都是公平的游戏默认覆盖,并禁止其所需的操作。 C++和C#采取相反的观点。

0

您可以覆盖在基类的方法,即使没有virtual

就拿这个小程序,例如:

#include <iostream> 

struct A 
{ 
    void m() 
     { std::cout << "A\n"; } 

    virtual void n() 
     { std::cout << "A\n"; } 
}; 

struct B : public A 
{ 
    void m() 
     { std::cout << "B\n"; } 

    virtual void n() 
     { std::cout << "B\n"; } 
}; 

int main() 
{ 
    A a; 
    a.m(); 
    a.n(); 

    B b; 
    b.m(); 
    b.n(); 

    A &c = b; 
    c.m(); 
    c.n(); 
} 

从程序的输出是:

 
A 
A 
B 
B 
A 
B 

正如你所看到的,B::m覆盖在A同样的方法方法。但是,这只适用于使用B的确切实例。在第三种情况下,如果使用对基类的引用,则需要virtual才能使其工作。

+4

'虚拟'关键字对于'overidding'是必需的,或者你得到的是'函数隐藏'。在派生结构'B'中的方法'm()'隐藏了Base结构'A'方法,而'B'中的方法'n()'覆盖了Base结构方法。 – 2012-01-03 10:41:10

+0

你在B中对m()所做的操作称为重载(这也会导致基类版本被隐藏),而不是重写。在C++中,函数必须被明确声明为虚拟的才能覆盖它。 – 2012-01-03 21:02:34

0

程序员从那里虚拟函数是默认语言来趋​​向于惊讶的是C++有默认值的反向选择,即非虚拟是默认值。但是请注意,一个[具体]虚函数的合同是一个困难得多文档和测试,因为它实际上涉及到两个不同的合同:

  1. 的所有重载函数的契约,即什么样的功能概念上做
  2. 的具体功能恰好做

仅文档化的,这些人会不会真正减少,因为另一半是不明确的,在所有的什么合同。这也意味着你不能从特定的实现中浏览实际的合同(假设你处于非常不典型的情况下,文档由源提供)。

+1

为什么把一切都虚拟或一般继承的一个例子可能不真的是一个好主意,经常看看所有那些从Java中'HashMap'继承而来的人并不像他们认为的那样。 – Voo 2012-01-03 21:19:14