对于直到运行时才创建的方法的虚方法?

时间:2011-11-23 17:42:25

标签: c++ methods runtime virtual

我在理解C ++中虚方法的目的时遇到了一些麻烦。如果方法不是在编译时创建的,那么方法是否必须是虚拟的?例如,如果你必须在运行时选择一个农场动物,那么所有动物的方法都需要是虚拟的,因为在用户选择一个之前你不知道它是否会被创建。如果我错了,请纠正我。

5 个答案:

答案 0 :(得分:7)

不,那是完全错误的。如果需要根据对象的类型选择方法并且在编译时不知道类型,则方法必须是虚拟的。如果您的代码如下所示:

Animal *x;
if(y==2)
{
    x = new Animal();
    x->DoSomething();
}

编译器在运行时知道x的类型是'Animal'。所以它知道要调用哪个版本的“DoSomething”。但看看这段代码:

Animal *x;
if(y==1) x=new Zebra();
else if (y==2) x=GetSomeAnimal();
else x=new Giraffe();
x->DoSomething();

这里,x的类型在编译时是未知的。它可以是斑马,它可以是长颈鹿,也可以是GetSomeAnimal函数返回的任何类型的动物。无法知道DoSomething的来电是否应该完全调用Zebra::DoSomethingGiraffe::DoSomething或其他内容。所以Animal::DoSomething需要是虚拟的。

只是为了表明它与将要创建的内容无关,请考虑一下:

void MyFunction(Animal &x)
{
    x.DoSomething();
}

void MyOtherFunction(int x)
{
   Giraffe g;
   Zebra z;
   if(x==2) MyFunction(g);
      else MyFunction(f);
}

这里非常清楚,将创建一个Giraffe和一个Zebra。但如果Animal::DoSomething不是虚拟的,那么MyFunction会在长颈鹿上调用Animal::DoSomething而不是Giraffe::DoSomething,而在Zebra上调用Zebra::DoSomething。 (当然,如果那是你想要的,请不要将该方法设为虚拟。)

答案 1 :(得分:0)

了解虚拟方法here的用途。我还建议您查看"Object Oriented Programming in ANSI C"本书。

答案 2 :(得分:0)

嗯,virtual是C ++中内置的支持OOD's多态的东西(特别是run-time or dynamic)。

当你想要相同类型的不同对象(Animal)表现不同时(getProduceName()返回“pork”或“beef”或“egg”或...)取决于上下文(是否{ {1}}实际上是AnimalPigCow或......)您制作的行为/功能Chicken

通常好的OOD会有良好的接口/实现分离。在C ++中,这是使用继承和virtual类/方法实现的。

所以实际上,当您abstract多态/ getProduceName()时,实际上是在尝试从不同的实现中提取接口(virtual)(Animal或{{1} }或Pig或...)来保护您的客户端代码不同的实现。这样,如果您必须支持新的实现,只要它符合接口Cow,您就不必更改客户端代码。

回答这个问题: 如果方法在编译时没有创建,那么方法是否必须是虚拟的?

方法是否为虚拟方法并不取决于创建对象的时间(编译/运行时)。这取决于您希望如何设计应用程序。创建函数Chicken可帮助您从不同的实现中提取接口。如果某个函数(Animal)在所有实现类(virtual)中具有相同的实现,则不需要将其设置为虚拟。

PS:恕我直言多态性是一个好的OOD的副产品,你不设计你的类来实现“运行时多态性”,然后在你有一个好的OO设计时展示运行时多态性。

答案 3 :(得分:0)

虚拟功能的一个重要目的是允许旧代码调用新代码

考虑一下。函数将Car对象作为参数。假设它执行的操作包括test_drive(),refuel(),calculate_ability(),getStoppingDistance()等。所有这些方法都取决于您传入的汽车类型。

但每年都有新车出现。现在,在现实世界中,我们只需导入一个包含构成所有汽车的属性的XML文件。但是假设为了争论我们必须静态地做到这一点:每次我们发现新车时,我们都必须重建我们的整个计划。如果我们的计划很庞大,那将非常不方便。在某种程度上,我们调用相同的函数,但在某种程度上我们不是 - 因为对象的类型不同。我们为什么要重新编译?

虚拟功能救援!当汽车制造商发布新车时,他们会同时发布一个头文件,声明新类型(继承自具有虚函数的公共基类)和一个库(定义特定方法的目标文件)。因此,我们只需重新链接到这个新库,而不是重新编译我们的应用程序。因此,旧代码(我们的应用程序)能够调用新代码(汽车附带的新库)。

答案 4 :(得分:0)

假设你有这段代码:

Animal * a = new Pig();

指针a具有Animal静态类型Pig动态类型

现在让我们说我们正在打电话

a->MakeASound();

如果MakeASound是虚拟的,则调用动态类型MakeASound方法(Pig)。

如果不是,则调用静态类型MakeASoundAnimal),无论Pig是否覆盖MakeASound方法。