我读了这么多博客,我理解如何在c ++中使用虚函数。但是,我仍然不明白为什么我们使用虚函数。你能给我一个真实世界的例子,这样我就可以更容易地看到虚函数的实际含义。
答案 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.
希望这有帮助。