2014-01-24 103 views
2

我试图了解何时/何地应该写一个'虚拟'关键字,以便给定类的任何后代启用多态行为,因为我无法在别处找到有关此问题的特定信息。何时在派生类中实际需要“虚拟”属性?

对于我所尝试过的,在基类中使用虚函数会自动使该函数对于任何后代都是虚拟的。然而,互联网上的许多片段经常在后代中将这些功能再次虚拟化。

struct A { 
    virtual void foo1() { std::cout << "[A] foo1.\n"; } 
    virtual void foo2() { std::cout << "[A] foo2.\n"; } 
}; 
struct B : public A { 
    virtual void foo1() { std::cout << "[B] foo1.\n"; } 
      void foo2() { std::cout << "[B] foo2.\n"; } 
}; 

用g ++编译这段代码我得到foo1和foo2都有多态行为。另外,即使我再次从B中派生出来并创建一个C类,并且在没有virtual关键字的情况下再次实现foo2,foo2仍然使用v表。

在派生类中仅使用virtual关键字仅用于清晰和自我记录,还是存在其他一些我不知道的效果?

+1

派生类中的虚拟只是提供信息 –

+1

拥抱C++ 11 * override *关键字。它修复了由这种行为引发的许多令人讨厌的维护错误。 –

回答

4

For what I've tried, having virtual on a function in the base class automatically makes that function virtual for any descendants.

这是真的,孩子自动继承virtual内斯父方法。

作为一个约定,人们在子类中重申virtual只是为了明确表明孩子打算覆盖虚拟方法(尽管我们在C++ 11中有override)。

+0

C++ 11中的最佳实践是什么?在子类中使用虚拟和覆盖,或者只是覆盖? – Svalorzen

+2

只需使用'override'。编译器会告诉你,如果你搞砸了;-) – bstamour

-1

除非您打算将其派生,否则没有特别的理由说明为什么子类应该在成员上拥有virtual关键字。

决定是否让您的班级成员为虚拟只取决于您打算如何派生您的班级。如果您不打算派生您的班级,那么

有关更完整的说明,请考虑以下代码。如果我现在打算推导出B,或者使B成为可重用的代码片段,那么我可能会使代码中断,阻止访问A的成员。

#include <iostream> 

class A 
{ 
public: 
    virtual void foo1() 
    { 
    std::cout<<"A.foo1"<<std::endl; 
    } 
    void foo2() 
    { 
    std::cout<<"A.foo2"<<std::endl; 
    } 
}; 

class B : public A 
{ 
public: 
    void foo1() 
    { 
    std::cout<<"B.foo1"<<std::endl; 
    } 
    void foo2() 
    { 
    std::cout<<"B.foo2"<<std::endl; 
    } 
}; 


int main() 
{ 
    A* a = new A(); 
    a->foo1(); 
    a->foo2(); 
    B* b = new B(); 
    b->foo1(); 
    b->foo2(); 
    delete a; 
    a=b; 
    a->foo1(); 
    a->foo2(); 
} 

产生的输出:

A.foo1 
A.foo2 
B.foo1 
B.foo2 
B.foo1 
A.foo2 
+0

你在这里显示的行为是由A函数上是否存在虚拟引起的。无论您是否在B功能上指定虚拟,都不会产生任何影响。 –

0

注意要点:

  1. 被声明虚拟动态绑定的任何方法(运行时间)。 任何其他方法都是静态绑定的(编译时)。

  2. 任何曾经声明为虚拟的方法,对于下面的所有继承级别都是虚拟的,无论它是否在下面的类中声明为虚拟。即假设层次是这样的:Man-> Indian-> Tamilian。

如果do_work()是一个虚拟的方法,那么它仍然即使Tamilian虚拟的,即使它被声明为只在人的虚拟。

virtual关键字是如何工作的?

将do_work()声明为虚拟只是表示:调用哪个do_work()将仅在运行时确定。

想我做的,

Man *man; 
man = new Indian(); 
man->do_work(); // Indian's do work is only called. 

如果虚拟未使用,同样是静态确定或由编译器静态绑定,这取决于对象调用。因此,如果人的对象调用do_work(),人的do_work()被调用,即使它指向一个印度OBJECT

令我惊讶,我发现纯虚函数也可以有一个身体!我认为他们不能。但事实是,他们可以。这意味着可以调用一个抽象类的纯虚函数!两位非常出色的作家是Bjarne Stroustrup和Stan Lippman ....因为他们写了这个语言。

相关问题