c ++中虚函数的概念?

时间:2012-06-20 18:49:55

标签: c++ algorithm oop function

我读了这么多博客,我理解如何在c ++中使用虚函数。但是,我仍然不明白为什么我们使用虚函数。你能给我一个真实世界的例子,这样我就可以更容易地看到虚函数的实际含义。

7 个答案:

答案 0 :(得分:2)

值得一提的是,继承(关键字virtual是其基础)不应仅用于代码重用的目的,请使用委托。

当我们有一个类使用一个名为connection()的方法说BroadbandConnection时,委托就会出现。然后你的经理说我们想要添加加密,所以你创建了一个类BroadbandConnectionWithEncryption。你的本能可能是使用继承,然后使新的类BroadbandConnectionWithEncryption从BroadbandConnection派生。

对此的缺点是初始类的创建者没有为继承设计它,因此您需要更改其定义以使方法connection()为虚拟,以便您可以在派生类中覆盖其行为。这并不总是理想的。更好的想法是在此处使用委托来进行代码重用。

class BroadBandConnection
{
public:
    void Connection (string password)
    {
        //connection code.
    }
};

class BroadBandConnectionWithEndcryption
{
public:
    void Connection (string password)
    {
        mbroadbandconnection.Connection(password);
        //now do some stuff to zero the memory or
        //do some encryption stuff
    }

private:
    BroadBandConnection mbroadbandconnection;
};

关键字virtual用于多态。顾名思义,它是一个对象具有多个表单的能力。这种决定将在设计界面或类时进行。

class IShape
{
    virtual void Draw () = 0; 
};

class Square
{
    void Draw()
    {
        //draw square on screen 
    }
};

class Circle
{
    void Draw()
    {
        //draw circle on screen
    }
};

我使用= 0创建了Draw()纯虚拟。我可以将其留下并添加一些默认实现。对于没有合理默认实现的接口,纯虚拟有意义。

这让我做的是将一个Shape对象传递给各种方法,他们不需要关心我刚才给出的东西。他们所知道的是,我必须提供一些支持形状自我绘制能力的东西。

IShape* circle = new Circle ();
IShape* square = new Square ();

void SomeMethod (IShape* someShape)
{
   someShape->Draw(); //This will call the correct functionality of draw
}

将来随着人们开始考虑新的形状,他们可以从IShape派生出来,只要他们为Draw实现一些功能。他们可以将此对象传递给SomeMethod。

答案 1 :(得分:1)

首先,this

现在,一个真实的例子。我有一个带有三个选项卡的GUI程序。每个选项卡都是一个类的对象,它派生自一个公共基础TabBase。它有一个虚函数OnActivate()。激活选项卡后,调度程序会在当前选项卡上调用它。有一些常见的操作,并且有一些特定于此选项卡的操作。这是通过虚函数实现的。

好处是控制器不需要知道它是什么类型的选项卡。它存储一组TabBase指针,并且只调用它们上的OnActivate()。虚拟函数的神奇之处在于确保调用正确的覆盖。

class TabBase
{
    virtual void OnActivate()
    {
    //Do something...
    }
};

class SearchTab: public TabBase
{
    void OnActivate() //An override
    {
        TabBase::OnActivate(); //Still need the basic setup
        //And then set up the things that are specific to the search tab
    }
}

答案 2 :(得分:0)

我们有一个基类(动物)有方法,可以用它的孩子(比如说)来实现。当我们将此方法声明为虚拟时,我们可以对该方法进行处理,并将根据其子项的定义来实现。如果您使用儿童的重载方法,则不必使用虚拟,但是当您使用父方法时,您必须使用虚拟方法。

例如,如果你有一个动物的载体,每个动物都是不同的。你将方法(比如)声明为虚拟,并从动物类中调用它,它将从相应的子类中调用。

如果我错了,请纠正我,这就是我理解的方式。

答案 3 :(得分:0)

他们实际上在Wiki

上举了一个例子

http://en.wikipedia.org/wiki/Virtual_function

使用动物。动物是超级类,所有动物都吃(超类虚函数)。每只动物的食物可能与所有其他动物的食物不同(超越虚拟功能)。我有一个任意动物的清单,当我打电话给吃功能时,他们会表现出不同的饮食习惯。

答案 4 :(得分:0)

如果您熟悉Java,那应该很容易。在Java中,ALL类方法实际上是虚拟的。如果在派生类中覆盖它,并通过基类引用调用它,则将调用覆盖,而不是基础。

这不是C ++中的默认行为。如果希望函数以这种方式运行,则必须在基类中将其声明为虚拟。很容易。

Java充满了虚拟功能。它只是没有明确的关键字。

答案 5 :(得分:0)

虚拟功能的目的是实现dynamic dispatch

你说你熟悉Java,所以对于现实世界中虚拟函数的使用,想一想你在公共场所使用interface或使用@Override的Java中的任何地方受保护的方法。

答案 6 :(得分:0)

使用虚拟功能的决定很简单。您只需要知道何时要覆盖基本方法。以下面的代码为例:

  class animal
 {
   public:
 void sound()
 {
  cout << "nothing";
 }
};
class bird : public animal
{
 public:
void sound()
{
cout << "tweet";
}

};

在这种情况下,我想要覆盖bird()。但是如果我没有呢?这将是会发生的事情:

animal * a = new bird;
a->sound();
 **Output**
nothing

屏幕不会说什么,因为无论出于什么意图和目的,C ++只会看到一只动物。但是,如果您将其声明为virtual,则它知道在类层次中搜索最低的方法。再试一次:

 class animal{
   public:
    virtual void sound(){cout<<"nothing";}
  };
 class bird : public animal
 {
    public:
   void sound()
    {
      cout << "tweet";
    }
  };
   animal * a = new bird;
  a->sound();
 **Output**
   tweet.

希望这有帮助。