Как работают виртуальные функции в C # и Java? - PullRequest
19 голосов
/ 20 января 2009

Как работают виртуальные функции в C # и Java?

Использует ли он ту же концепцию vtable и vpointer, что и в C ++, или это что-то совершенно другое?

Ответы [ 6 ]

19 голосов
/ 18 июля 2013

Как работают виртуальные функции в Java?

Кодирующие интервьюеры любят этот вопрос. Да. Хотя в Java нет виртуального ключевого слова, в Java есть виртуальные функции, и вы можете их писать.

В объектно-ориентированном программировании виртуальная функция или виртуальный метод - это функция или метод, поведение которых может быть переопределено в классе наследования функцией с такой же сигнатурой. Эта концепция является очень важной частью полиморфизма в объектно-ориентированном программировании (ООП).

Чтобы задать архитектурный вопрос о конкретном языке, подобном этому, требуются отличные коммуникативные навыки и глубокое владение основными принципами компилятора Java, в частности интерфейсами, абстрактными классами и принципами наследования.

Направьте интервьюера на конкретный пример виртуальной функции.

Да, вы можете писать виртуальные функции на Java с интерфейсами.

Java методы интерфейса все "чисто виртуальные", потому что они предназначены для переопределения. Например:

interface Bicycle {         //the function applyBrakes() is virtual because
    void applyBrakes();     //functions in interfaces are designed to be 
}                           //overridden.

class ACMEBicycle implements Bicycle {
    public void applyBrakes(){               //Here we implementing applyBrakes()
       System.out.println("Brakes applied"); //function, proving it is virtual.
    }
}

Да, вы можете писать виртуальные функции на Java с абстрактными классами.

Java Абстрактные классы содержат неявно «виртуальные» методы, реализуемые расширяющими его классами. Например:

abstract class Dog {                   
    final void bark() {               //bark() is not virtual because it is 
        System.out.println("woof");   //final and if you tried to override it
    }                                 //you would get a compile time error.

    abstract void jump();             //jump() is a virtual function because it
}                                     //is part of an abstract class and isn't
                                      //final.  
class MyDog extends Dog{
    void jump(){
        System.out.println("boing");    //here jump() is being overridden, a 
    }                                   //demonstration that it is virtual.
}
public class Runner {
    public static void main(String[] args) {
        MyDog myDog = new MyDog();       //instantiating myDog
        myDog.jump();                    //calling the overridden function jump()
    }
}

Вы можете заставить функцию НЕ быть виртуальной в универсальном классе, сделав ее final

Например:

class myJavaFoobarClass {

    final boolean giveMeTrueFunction()   //this Java function is NOT virtual
    {                                    //because final keyword prevents this
        return true;                     //function from being modified in a
    }                                    //subclass.

    boolean isItRainingFunction()   //this Java function IS virtual because
    {                               //without the final keyword, the function
        return false;               //can be overridden in a subclass.
    }
}
10 голосов
/ 20 января 2009

По крайней мере, в Java нет виртуального ключевого слова.

Это просто разрешает самую производную версию любого метода, который вы вызываете ...

class A{
void sayhi(){ System.out.println("A");}
}
class B extends A{
void sayhi(){ System.out.println("B");}
}

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

Напечатает "B".

Вы можете создавать «чисто виртуальные» методы, объявив класс Abstract и оставив чисто виртуальные методы объявленными, но не реализованными. Или с помощью интерфейса / реализует вместо класса / расширяет. Интерфейс - это класс, где все методы чисто виртуальные. Это дает дополнительный бонус, заключающийся в том, что класс может реализовывать несколько интерфейсов, поскольку в отличие от C ++ класс Java может напрямую наследовать только один другой класс.

EDIT:


В ответ на ваш комментарий, Навин:

Если вы сказали A a = new A (); a.sayhi (); это напечатало бы "A".

Терминология Java является динамической. Вы можете думать об этом как о виртуальном, но это может сбить с толку некоторых разработчиков Java. те, кто не знает C ++, по крайней мере. В Java нет явных указателей, поэтому нам не нужно беспокоиться о виртуальных / не виртуальных. VTables не существует, вы просто возвращаете класс и его предков, пока не найдете реализацию метода, который вам нужен. Существует только одно наследование, поэтому вам не нужно беспокоиться о порядке конструктора (он всегда снизу вверх).

В C ++ вы получаете другое поведение, если у вас есть виртуальные методы и вы делаете что-то вроде

a->sayhi();

где a было A *, указывая на экземпляр B вместо

a.sayhi();

где a был объектом типа A, содержащим объект типа B

4 голосов
/ 28 апреля 2011

В Java виртуальная функция совершенно другая. В Java виртуальная функция означает функцию, которая может быть переопределена в ее подклассах. Так что все нестатические методы Java являются виртуальными функциями. Только финальная и приватная функция не наследуются, поэтому они не являются виртуальной функцией.

Таким образом, мы можем сказать, что все нестатические функции, которые не являются окончательными и частными, являются виртуальными функциями в Java.

2 голосов
/ 20 января 2009

Все языки, поддерживающие полиморфизм, используют vtables для разрешения вызовов методов для правильной функции. Так же и Java и .NET.

Они оба компилируются в некоторый промежуточный язык (IL для .NET и байт-код для Java), но vtable не виден на этом промежуточном языке. Поддерживается базовым движком (CLR для .NET)

0 голосов
/ 17 июня 2009

Чистые виртуальные функции в C ++. C # использует интерфейсы для той же цели, поэтому я бы посоветовал вам пойти по этому пути.

0 голосов
/ 20 января 2009

Я уверен, что Java не использует vtables, поскольку она способна поддерживать двоичную совместимость.

Для уточнения: vtable создается при компиляции производного / подкласса. Если изменяется макет базового / суперкласса, необходимо перекомпилировать vtable для d / s. В Java это не так. Вы можете изменить b / s без перекомпиляции d / s.

Хм. Вполне возможно, что vtable будет построен во время запуска. когда класс загружен. В этом случае Java и C ++ будут одинаковыми, но разными.

...