Подтвердить что ты не робот

Как перегрузка является временем компиляции, а переопределение - временем выполнения?

Люди

Я нашел много потоков для понимания полиморфизма (как время компиляции, так и время выполнения). Я был удивлен, увидев некоторые ссылки, где программисты утверждают, что перегрузка - это время выполнения, а переопределение - время компиляции.

Что я хочу знать отсюда:

  • Полиморфизм времени выполнения с примером REAL TIME и небольшим кодом и сценарий, который мы должны использовать.
  • Полиморфизм времени компиляции с примером REAL TIME и небольшим кодом и когда использовать.

Потому что я читал много теоретических определений, но я не удовлетворен пониманием этого.

Кроме того, я подумал, что, где я также чувствовал, перегрузка должна быть временем выполнения, потому что, скажем, у меня есть метод, который вычисляет Area, во время выполнения он решает, какой перегруженный метод вызывать на основе параметров, которые я передаю (скажем, если Я пропускаю только один параметр, он должен стрелять в квадрат, а если параметры равны 2, он должен срабатывать Rectangle).... Так не правда ли, я могу утверждать его время выполнения? Как его время выполнения? (Скорее всего, теоретически перегрузка - это время компиляции, но они даже не дают правильный пример реального времени... очень немногие утверждают, что он работает)....

Кроме того, я считаю, что переопределение - это время компиляции, потому что, когда вы пишете код и выполняете комплимент, вы гарантируете, что используете виртуальное ключевое слово, а также переопределяете этот метод в производном классе, который в противном случае дал бы вам ошибку времени компиляции. Таким образом, я чувствую его время компиляции, так же, как я видел в потоке..... Но большинство потоков утверждает свое время выполнения: D

Я запутался:( Этот вопрос является дополнительным к моим вопросам 1 и 2. Пожалуйста, помогите с примером в реальном времени.. поскольку я уже знаю теоретические определения....: (

Спасибо....

4b9b3361

Ответ 1

В случае перегрузки вы используете статический (компиляционный) полиморфизм, потому что компилятор знает точно, какой метод вы вызываете. Например:

public static class test
{
    static void Main(string[] args)
    {
        Foo();
        Foo("test");
    }

    public static void Foo()
    {
        Console.WriteLine("No message supplied");
    }

    public static void Foo(string message)
    {
        Console.WriteLine(message);
    }
}

В этом случае компилятор точно знает, какой метод Foo() мы вызываем, в зависимости от числа/типа параметров.

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

public static class MessagePrinter
{
    public static void PrintMessage(IMessage message)
    {
        Console.WriteLine(message.GetMessage());
    }
}

public interface IMessage
{
    public string GetMessage();
}

public class XMLMessage : IMessage
{
    public string GetMessage()
    {
        return "This is an XML Message";
    }
}

public class SOAPMessage : IMessage
{
    public string GetMessage()
    {
        return "This is a SOAP Message";
    }
}

Во время компиляции вы не знаете, передается ли вызывающая функция этой функции в XMLMessage, SOAPMessage или, возможно, в другом типе сообщений, определенных в другом месте. Когда функция PrintMessage() является вызовом, она определяет, какую версию GetMessage() использовать во время выполнения, в зависимости от типа передаваемого IMessage.

Ответ 2

Читайте: Полиморфизм (Руководство по программированию на С#)

Подобный ответ: Время компиляции и время полиморфизма

Хорошо, существуют два типа полиморфизма, как указано ниже:

  • Статический полиморфизм (раннее связывание)
  • Динамический полиморфизм (поздняя привязка)

Статический полиморфизм (раннее связывание):

Статический полиморфизм также известен как ранний связывание и полиморфизм времени компиляции. Перегрузка метода и перегрузка оператора являются примерами того же самого.

Он известен как раннее связывание, потому что компилятор знает о функциях с тем же именем, а также о том, какая перегруженная функция должна быть вызвана, известна во время компиляции.

Например:

public class Test
{
    public Test()
    {

    }

    public int add(int no1, int no2)
    {

    }

    public int add(int no1, int no2, int no3)

    {

    }
}

class Program
{
    static void Main(string[] args)
    {
        Test tst = new Test();
        int sum = tst.add(10, 20);

        // here in above statement compiler is aware at compile time that need to call function add(int no1, int no2), hence it is called early binding and it is fixed so called static binding.
    }
}

Динамический полиморфизм (поздняя привязка):

public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("Animal sound");
    }
}

public class Dog:Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Dog sound");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Animal an = new Dog();
        an.MakeSound();           
        Console.ReadLine();
    }
}

Как и в приведенном выше коде, как и любой другой вызов виртуального метода, будет скомпилирован в IL-код callvirt. Это означает, что фактический метод, который вызывается, определяется во время выполнения (если JIT не может оптимизировать какой-либо частный случай), но компилятор проверял, существует ли этот метод, он выбрал наиболее подходящую перегрузку (если таковой имеется) и имеет гарантию что указатель функции будет существовать в четко определенном месте в таблице vtable этого типа (хотя это деталь реализации). Процесс разрешения виртуального вызова чрезвычайно быстрый (вам нужно только разыменовать несколько указателей), поэтому это не имеет большого значения.

Ответ 3

public class Animal {
    public virtual void MakeSound()
    {
        Console.WriteLine("Animal sound");
    } }

public class Dog:Animal {
    public override void MakeSound()
    {
        Console.WriteLine("Dog sound");
    } }

class Program {
    static void Main(string[] args)
    {
        Animal an = new Dog();
        an.MakeSound();           
        Console.ReadLine();
    } }

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