简体   繁体   English

运行时多态性

[英]Runtime polymorphism

Suppose I have class A 假设我有A级

public class A
{
    public void method()
    {
        //do stuff
    }
}

Also another class B 还有另一个B类

public class B extends A
{
    public void method()
    {
        //do other stuff
    }
}

Now I have the following statements: 现在我有以下声明:

A a = new B();
a.method();

Is this an example of run time polymorphism? 这是运行时多态的一个例子吗? If yes, then is no binding is done for the reference a at compile time? 如果是,那么在编译时是否没有对引用a进行绑定?

The compiler will tell you that this can't work, because there's no relationship between A and B that will allow you to write A a = new B(); 编译器会告诉你这不起作用,因为A和B之间没有任何关系可以让你写A a = new B();

B either has to extend A or both have to implement a common interface with void method() in it. B必须扩展A或两者都必须在其中实现与void method()的通用接口。

You could have answered this very quickly by trying it with the compiler. 您可以通过编译器尝试快速回答这个问题。 Be an experimentalist - it's faster than forums. 成为一名实验主义者 - 它比论坛更快。

UPDATE: 更新:

It works, now that B extends A. The binding that you care about, dynamic binding, is done at runtime. 它工作,现在B扩展A.你关心的绑定,动态绑定,是在运行时完成的。 The static compile time type for the variable "a" is class A; 变量“a”的静态编译时类型是A类; at runtime it is dynamically bound to a reference of type B. Yes, I would consider this to be an example of polymorphism. 在运行时,它动态绑定到类型B的引用。是的,我认为这是多态的一个例子。

I was waiting to put my answer to another post, into a more correctly classified problem. 我等着把我的答案放到另一篇文章中,进入一个更正确的分类问题。 Your question fits the concept, I've tried to explain in detail. 你的问题符合这个概念,我试图详细解释。 but, since I don't know how link answers, I'll just copy/paste the complete script here .... Kindly go through it, you'll understand everything that there is to understand about your problem, you've asked 但是,由于我不知道链接的答案如何,我只需要复制/粘贴完整的脚本....请仔细阅读,你会理解有关你的问题的一切,你问过


let's say compiler has to resolve a call like this : * 假设编译器必须解决这样的调用:*

A a = new AA(); A =新AA(); // Assume AA to be some subclass of class A //假设AA是A类的某个子类
a->someFunc(); A-> someFunc(); // and we're invoking a method "someFunc()' on a //我们正在调用一个方法“someFunc()”

*. *。

Now, compiler will go over following steps methodically. 现在,编译器将有条不紊地执行以下步骤。

1.) Firstly, compiler knows the declared type of variable a, so it will check whether the declared type of object a ( lets call this, class A for time being ), have a method with the name someFunc() and that it must be public. 1.)首先,编译器知道变量a的声明类型,因此它将检查声明的对象类型a( lets call this, class A for time being ),有一个名为someFunc()的方法,并且它必须公开。 This method could either be declared in class A , or it could be a derived method from one of the base class(es) of class A, but it doesn't matter to compiler and it just checks for it's existence with it's access specifier being public . 这个方法既可以在class A声明,也可以是来自class A的基类之一的派生方法,但它与编译器无关,它只是通过它的访问说明符来检查它是否存在public

  • Needless to say any error in this step will invite a compiler error. 不用说,此步骤中的任何错误都会引发编译器错误。

2.) Secondly, once the method is validated to be a part of the class A, compiler has to resolve the call to the correct method, since many methods could be there with same name (thanks to function overloading). 2.)其次,一旦该方法被验证为A类的一部分,编译器必须解析对正确方法的调用,因为许多方法可能具有相同的名称(由于函数重载)。 This process of resolving correct method is called overloading resolution . 解决正确方法的过程称为overloading resolution Compiler achieves this by matching the signatures of the called method with all the overloaded methods that are part of the class. 编译器通过将被调用方法的签名与作为类的一部分的所有重载方法相匹配来实现此目的。 So, of all the someFunc() s only the correct someFunc() (matching the signatures with called method) will be found and considered further. 因此,在所有someFunc() s只能找到正确的someFunc()(使用被调用方法匹配签名)并进一步考虑。

3.) Now comes the difficult part, It may very well happen that someFunc() may have been overridden in one of the subclasses of the class A ( lets call this class AA and needless to say it is some subclass of A ), and that variable a (declared to be of type A) may actually be referring to an object of class AA, (this is permissible in C++ to enable polymorphism). 3.)现在遇到了困难的部分,很可能会发生someFunc()可能已被重写在A类的一个子类中( lets call this class AA and needless to say it is some subclass of A ),并且变量a(声明为类型A)实际上可能是指类AA的对象(这在C ++中是允许的,以启用多态)。 Now, if the someFunc() method is declared to be of type virtual , in base class (ie Class A) and someFunc() has been overriden by subclass(es) of A (either in AA or classes between A and AA), the correct version of someFunc() have to be found out by the compiler. 现在,如果someFunc()方法声明为virtual类型,则在基类(即A类)中,someFunc()已被A的子类覆盖(在AA或A和AA之间的类中),必须由编译器找到someFunc()的正确版本。

  • Now, imagine you're the compiler and you have this task of finding whether the class AA has this method. 现在,想象一下你是编译器,你有这个任务来查找AA类是否有这种方法。 Obviously, class AA will have this method since, it is a subclass of A and public access of A in class A has already been validated in Step 1 by the compiler !!! 显然,AA类将具有此方法,因为它是A的子类,并且A类中的A的公共访问已经在编译器的步骤1中得到验证! . But Alternatively, as mentioned in previous paragraph, someFunc() may be overriden by class AA (or any other class between A and AA), which is what compiler needs to catch. 但另外,如前一段所述,someFunc()可能被类AA(或A和AA之间的任何其他类)覆盖,这是编译器需要捕获的。 Therefore, you (since, your'e playing the compiler) could do a systematic check to find the bottom-most (lowest in the inheritance tree) overridden method someFunc() starting from class A and ending at class AA. 因此,您(因为,您正在玩​​编译器)可以进行系统检查以找到最重要的(继承树中最低的)重写方法someFunc()从类A开始并在类AA结束。 In this search, you'll look for same method signatures as was validated in overloading resolution. 在此搜索中,您将查找与重载分辨率中验证的方法签名相同的方法签名。 This method will be the method which will be invoked. 此方法将是将被调用的方法。

  • Now, you may be wondering, "What the heck", is this search done everytime ? 现在,您可能想知道,“这是什么”,这次搜索是什么时候完成的? ... Well, Not really. ......好吧,不是真的。 The compiler knows the overhead of finding this everytime, and as such, maintains a data-structure called Virtual Table for every class type. 编译器知道每次查找此内容的开销,因此,为每个类类型维护一个名为Virtual Table的数据结构。 Think of virtual table, as mapping from method signatures (which are publicly accessible) to the function pointers. 可以将虚拟表视为从方法签名(可公开访问)到函数指针的映射。 This virtual table is made by compiler during compilation process and is maintained in-memory during program execution. 此虚拟表由编译器在编译过程中生成,并在程序执行期间保留在内存中。 In our example, class A and class AA will both have their own virtual tables. 在我们的示例中,A类和AA类都有自己的虚拟表。 And when compiler has to be find someFunc() in class AA (since actual object pointed by variable a is of type AA), it will simply find the function pointer through the virtual table of Class AA. 当编译器必须在类AA中找到someFunc()时(因为变量a指向的实际对象是AA类型),它将简单地通过类AA的虚拟表找到函数指针。 This is as simple has hashing into the table and is a constant time operation. 这很简单,已经散列到表中并且是一个恒定的时间操作。

Regards 问候

AViD AVID

The code example you've given isn't legal, so I guess the answer is that it's not a kind of polymorphism. 你给出的代码示例是不合法的,所以我想答案是它不是一种多态。

You can't assign a class to a variable of an unrelated type like that. 您不能将类分配给不相关类型的变量。 I'm guessing that you might be intending for B to derive from A? 我猜你可能打算从A派生出来?

Is this an example of run time polymorphism? 这是运行时多态的一个例子吗?

As of the edit: yes that would be runtime polymorphism, since which method is actually executed depends on what is assigned to a . 在编辑时:是的,这将是运行时多态,因为实际执行哪个方法取决于分配给a

Edit: 编辑:

If method() would be static, then calling a.method() would always result in the version of A being called. 如果method()是静态的,那么调用a.method()总会导致调用A的版本。 However, you'd then just write A.method() and if you don't do that any decent IDE would warn you about that (because it might be misleading to call a static method on an instance). 但是,您只需编写A.method() ,如果不这样做,任何体面的IDE都会警告您(因为在实例上调用静态方法可能会产生误导)。

End Edit. 结束编辑。

Compile time polymorphism would be the overloading mechanism, ie the compiler decides whether to use someMethod(Number) or someMethod(Integer) depending on what it knows about the parameter that is passed (if you pass a Double or just a Number it would be the first one, if you pass an Integer it would be the second). 编译时多态将是重载机制,即编译器决定是否使用someMethod(Number)someMethod(Integer)具体取决于它对传递的参数的了解(如果传递Double或只是一个Number ,它将是第一个,如果你传递一个Integer ,它将是第二个)。

If yes, then is no binding is done for the reference a at compile time? 如果是,那么在编译时是否没有对引用a进行绑定?

What do you mean exactly? 你到底是什么意思? Note that the type of a will be A so you can assign everything that extends A at runtime. 需要注意的是类型aA扩展,所以你可以指定一切A在运行时。 The compiler will just complain if the assigned value is not an A (you might trick the compiler with a cast, but this is just evil and if this breaks your program, you have been warned ;) ) 如果指定的值不是A ,编译器会抱怨(你可能会使用强制转换欺骗编译器,但这只是邪恶的,如果这破坏了你的程序,你就会被警告;))

It should be 它应该是

public class B extends A { 公共等级B扩展A {
public void method() public void method()
{ {
//do other stuff //做其他的事
} } }}

If it were compiling, it would be the B::method() that would be called. 如果它正在编译,那么将调用B::method() (only if you changed your code to make the B class inherit the A class). (仅当您更改代码以使B类继承A类时)。

In this case your use your object like it was only an A, but if some methods are overidden in B, then these methods are called, instead of A's methods. 在这种情况下,你使用你的对象,就像它只是一个A,但如果在B中覆盖了一些方法,则调用这些方法,而不是A的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM