C # не вызывал функцию производного класса в полиморфизме, когда параметр pass [duplicate]

Ответы

Q: Что такое лямбда-выражение в C ++ 11?

A: Под капотом это объект автогенерированного класса с оператором перегрузки () Уст. Такой объект называется замыканием и создается компилятором. Эта концепция «закрытия» находится рядом с концепцией связывания с C ++ 11. Но lambdas обычно генерируют лучший код.

В: Когда я буду использовать один?

A: Определить «простую и малую логику» и спросить компилятор выполнить генерацию из предыдущего вопроса. Вы даете компилятору некоторые выражения, которые вы хотите быть внутри оператора ().

Q: Какой класс проблемы они решают, что было невозможно до их введения?

A: Это какой-то синтаксис сахара, как перегрузка операторов вместо функций для пользовательских операций add, subrtact ... Но он сохраняет больше строк ненужного кода, чтобы обернуть 1-3 строки реальной логики для некоторых классов и т. д.! Некоторые инженеры считают, что если число строк меньше, то вероятность ошибок в нем меньше (я тоже так думаю)

Пример использования

auto x = [=](int arg1){printf("%i", arg1); };
void(*f)(int) = x;
f(1);
x(1);

Дополнительные сведения о лямбдах, не затрагиваемые вопросом. Игнорируйте этот раздел, если вы не заинтересованы

1. Захваченные значения. Что вы можете захватить

1.1. Вы можете ссылаться на переменную со статической продолжительностью хранения в lambdas. Все они захвачены.

1.2. Вы можете использовать лямбда для значений захвата «по значению». В этом случае захваченные вары будут скопированы в объект функции (замыкание).

[captureVar1,captureVar2](int arg1){}

1.3. Вы можете захватить ссылку. & Амп; - в этом контексте означают ссылки, а не указатели.

   [&captureVar1,&captureVar2](int arg1){}

1.4. Он содержит обозначения для захвата всех нестатических варов по значению или по ссылке

  [=](int arg1){} // capture all not-static vars by value

  [&](int arg1){} // capture all not-static vars by reference

1.5. Он содержит обозначения для захвата всех нестатических варов по значению или путем ссылки и указания smth. Больше. Примеры: Захват всех нестатических варов по значению, но путем захвата ссылки Param2

[=,&Param2](int arg1){} 

Захват всех нестатических варов по ссылке, но с помощью захвата значения Param2

[&,Param2](int arg1){} 

2. Вывод типа возврата

2.1. Возвращаемый тип Lambda может быть выведен, если лямбда - это одно выражение. Или вы можете явно указать его.

[=](int arg1)->trailing_return_type{return trailing_return_type();}

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

3. Захваченные значения. Что вы не можете захватить

3.1. Вы можете захватывать только локальные вары, а не переменную-член объекта.

4. Свержения

4.1. lambda не является указателем на функцию и не является анонимной функцией, но может быть неявно преобразован в указатель на функцию.

p.s.

  1. Подробнее о лямбда-грамматической информации можно найти в рабочем проекте для языка программирования C ++ # 337, 2012-01-16, 5.1.2. Лямбда-выражения, стр.88
  2. В C ++ 14 добавлена ​​дополнительная функция, названная «захват init». Он позволяет выполнять произвольное объявление членов данных закрытия:
    auto toFloat = [](int value) { return float(value);};
    auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);};
    
151
задан Mateen Ulhaq 7 January 2016 в 21:51
поделиться

13 ответов

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

public class Base
{
    public virtual void DoIt()
    {
    }
}

public class Derived : Base
{
    public override void DoIt()
    {
    }
}

Base b = new Derived();
b.DoIt();                      // Calls Derived.DoIt

будет вызывать Derived.DoIt, если это переопределяет Base.DoIt.

]

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

public class Base
{
    public virtual void DoIt()
    {
    }
}

public class Derived : Base
{
    public new void DoIt()
    {
    }
}

Base b = new Derived();
Derived d = new Derived();

b.DoIt();                      // Calls Base.DoIt
d.DoIt();                      // Calls Derived.DoIt

Сначала вызовет Base.DoIt, затем Derived.DoIt. Они фактически представляют собой два совершенно разных метода, которые имеют одно и то же имя, а не производный метод, переопределяющий базовый метод.

Источник: Блог Microsoft

196
ответ дан bluish 16 August 2018 в 05:38
поделиться
  • 1
    This indicates for the compiler to use the last defined implementation of a method. как можно найти последнюю определенную реализацию метода? – AminM 5 March 2014 в 21:30
  • 2
    Начните с конкретного класса, проверьте, имеет ли он реализацию метода, представляющего интерес. Если да, то все готово. Если это не так, выполните один шаг вверх в иерархии наследования, то есть проверьте, имеет ли суперкласс класс, представляющий интерес. Продолжайте, пока не найдете интересующий вас метод. – csoltenborn 24 October 2014 в 09:16
  • 3
    Также обратите внимание, что вы можете использовать только метод override, когда базовый класс определяет метод как virtual. Слово virtual является базовым классом, говорящим «Привет», когда я вызываю этот метод, его можно было бы фактически заменить производной реализацией, поэтому я не знаю заранее, какую реализацию метода я нахожу во время выполнения , Таким образом, virtual означает заполнитель для метода. Это означает, что методы, которые не отмечены как virtual, нельзя переопределить. Но вы можете заменить любой не виртуальный метод в производном классе с модификатором new, доступным только на производном уровне. – Erik Bongers 20 May 2018 в 10:03

Разница между двумя случаями заключается в том, что в случае 1 базовый метод DoIt не становится переопределенным, просто скрытым. Это означает, что в зависимости от типа переменной зависит, какой метод будет вызван. Например:

BaseClass instance1 = new SubClass();
instance1.DoIt(); // Calls base class DoIt method

SubClass instance2 = new SubClass();
instance2.DoIt(); // Calls sub class DoIt method

Это может быть действительно запутанным и приводит к не ожидаемому поведению, и его следует избегать, если это возможно. Таким образом, предпочтительным способом будет случай 2.

3
ответ дан Christian Specht 16 August 2018 в 05:38
поделиться

В первом случае он вызовет метод DoIt () производного класса, потому что новое ключевое слово скрывает метод базового класса DoIt ().

Во втором случае он вызовет overriden DoIt ()

  public class A
{
    public virtual void DoIt()
    {
        Console.WriteLine("A::DoIt()");
    }
}

public class B : A
{
    new public void DoIt()
    {
        Console.WriteLine("B::DoIt()");
    }
}

public class C : A
{
    public override void DoIt()
    {
        Console.WriteLine("C::DoIt()");
    }
}

позволяет создать экземпляр этих классов

   A instanceA = new A();

    B instanceB = new B();
    C instanceC = new C();

    instanceA.DoIt(); //A::DoIt()
    instanceB.DoIt(); //B::DoIt()
    instanceC.DoIt(); //B::DoIt()

Все ожидается выше. Позвольте задать экземпляр B и instanceC в instanceA и вызвать метод DoIt () и проверить результат.

    instanceA = instanceB;
    instanceA.DoIt(); //A::DoIt() calls DoIt method in class A

    instanceA = instanceC;
    instanceA.DoIt();//C::DoIt() calls DoIt method in class C because it was overriden in class C
0
ответ дан cimey 16 August 2018 в 05:38
поделиться

Функциональная разница не будет отображаться в этих тестах:

BaseClass bc = new BaseClass();

bc.DoIt();

DerivedClass dc = new DerivedClass();

dc.ShowIt();

В этом примере, вызванная Doit является той, которую вы ожидаете назвать.

In чтобы увидеть разницу, которую вы должны сделать:

BaseClass obj = new DerivedClass();

obj.DoIt();

Вы увидите, если вы запустите этот тест, который в случае 1 (как вы его определили), DoIt() в BaseClass (в том случае, если вы определили его), вызывается DoIt() в DerivedClass.

0
ответ дан Ken Falk 16 August 2018 в 05:38
поделиться

В случае 1, если вы использовали метод DoIt () унаследованного класса, в то время как тип объявлен как базовый класс, вы увидите действие базового класса.

/* Results
Class1
Base1
Class2
Class2
*/
public abstract class Base1
{
    public void DoIt() { Console.WriteLine("Base1"); }
}
public  class Class1 : Base1 
{
    public new void DoIt() { Console.WriteLine("Class1"); }
}
public abstract class Base2
{
    public virtual void DoIt() { Console.WriteLine("Base2"); }
}
public class Class2 : Base2
{
    public override void DoIt() { Console.WriteLine("Class2"); }
}
static void Main(string[] args)
{
    var c1 = new Class1();
    c1.DoIt();
    ((Base1)c1).DoIt();

    var c2 = new Class2();
    c2.DoIt();
    ((Base2)c2).DoIt();
    Console.Read();
}
3
ответ дан Matthew Whited 16 August 2018 в 05:38
поделиться
  • 1
    Вы, гайка, показываете как недопустимый токен, когда я пытаюсь выполнить код – Learner 13 February 2013 в 12:54
  • 2
    Не могли бы вы отправить предупреждение или ошибку, которую вы получаете. Этот код работал нормально, когда я изначально разместил его. – Matthew Whited 13 February 2013 в 14:55
  • 3
    Все это должно быть вставлено в ваш класс точки входа (программа). Это было удалено, чтобы обеспечить лучшее форматирование на этом сайте. – Matthew Whited 13 February 2013 в 14:57
  • 4
    @MatthewWhited. Не кормите троллей – uriDium 22 May 2014 в 15:12

попробуйте выполнить: (case1)

((BaseClass)(new InheritedClass())).DoIt()

Edit: virtual + override разрешены во время выполнения (поэтому переопределение действительно отменяет виртуальные методы), а новые просто создают новый метод с тем же именем и скрывает старый, он разрешен во время компиляции -> ваш компилятор вызовет метод, который он видит '

7
ответ дан nothrow 16 August 2018 в 05:38
поделиться

Ниже приведена статья в vb.net, но я думаю, что объяснение новых переопределений vs очень легко понять.

https://www.codeproject.com/articles/17477/ the-dark-shadow of of-overrides

В какой-то момент статьи есть следующее предложение:

В общем, Shadows предполагает связанную с этим функцию с вызовом type, в то время как Overrides предполагает реализацию объекта.

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

1
ответ дан Samuel 16 August 2018 в 05:38
поделиться

Если в производном классе используется ключевое слово override, то оно переопределяет родительский метод.

Если ключевое слово new используется в производном классе, то выведите метод, скрытый родительским методом.

1
ответ дан Sangram Nandkhile 16 August 2018 в 05:38
поделиться

Мой способ иметь в виду оба ключевых слова, которые они противоположны друг другу.

override: ключевое слово virtual должно быть определено для переопределения метода. Метод, использующий ключевое слово override, независимо от ссылочного типа (ссылка на базовый класс или производный класс), если он создается с базовым классом, выполняется метод базового класса. В противном случае используется метод производного класса.

new: если ключевое слово используется методом, в отличие от ключевого слова override, тип ссылки важен. Если он создается с производным классом, а ссылочный тип - это базовый класс, выполняется метод базового класса. Если он создается с производным классом, а ссылочный тип - это производный класс, выполняется метод производного класса. А именно, это отличие от ключевого слова override. En passant, если вы забыли или опустите, чтобы добавить новое ключевое слово в метод, компилятор ведет себя по умолчанию при использовании ключевого слова new.

class A 
{
    public string Foo() 
    {
        return "A";
    }

    public virtual string Test()
    {
        return "base test";
    }
}

class B: A
{
    public new string Foo() 
    {
        return "B";
    }
}

class C: B 
{
    public string Foo() 
    {
        return "C";
    }

    public override string Test() {
        return "derived test";
    }
}

Вызов в основном:

A AClass = new B();
Console.WriteLine(AClass.Foo());
B BClass = new B();
Console.WriteLine(BClass.Foo());
B BClassWithC = new C();
Console.WriteLine(BClassWithC.Foo());

Console.WriteLine(AClass.Test());
Console.WriteLine(BClassWithC.Test());

Выход:

A
B
B
base test
derived test
2
ответ дан snr 16 August 2018 в 05:38
поделиться

virtual: указывает, что метод может быть переопределен переопределением функции inheritor

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

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

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

153
ответ дан Sнаđошƒаӽ 16 August 2018 в 05:38
поделиться
  • 1
    Почему при запуске метода, который скрывает базовый метод, опасно? Или вы подразумеваете, что кастинг вообще опасен? – Mark 7 November 2016 в 03:39
  • 2
    @Mark - вызывающий может не знать о реализации, что приводит к случайному неправильному использованию. – Jon B 7 November 2016 в 17:26

В первом случае вы скрываете определение в родительском классе. Это означает, что он будет вызываться только в том случае, если вы имеете дело с объектом как дочерний класс. Если вы примените класс к его родительскому типу, будет вызван метод parent. Во втором случае метод переопределяется и будет вызываться независимо от того, был ли объект включен в качестве дочернего или родительского класса.

14
ответ дан tvanfosson 16 August 2018 в 05:38
поделиться

Из всего этого новое - самое запутанное. Благодаря экспериментированию новое ключевое слово похоже на предоставление разработчикам возможности переопределить реализацию наследующего класса с реализацией базового класса, явно определяя тип. Это похоже на то, как думать наоборот.

В приведенном ниже примере результат вернет «Производный результат» до тех пор, пока тип явно не будет определен как тест BaseClass, только тогда будет возвращен «Базовый результат».

class Program
{
    static void Main(string[] args)
    {
        var test = new DerivedClass();
        var result = test.DoSomething();
    }
}

class BaseClass
{
    public virtual string DoSomething()
    {
        return "Base result";
    }
}

class DerivedClass : BaseClass
{
    public new string DoSomething()
    {
        return "Derived result";
    }
}
1
ответ дан usefulBee 16 August 2018 в 05:38
поделиться
  • 1
    Добавьте свой комментарий, если вы возражаете. Хит и бег настолько труслив. – usefulBee 22 August 2017 в 16:03

У меня был тот же вопрос, и это действительно запутанно, вы должны учитывать, что переопределение и новые ключевые слова работают только с объектами базового класса типа и значением производного класса. В этом случае вы увидите эффект переопределения и новый: Итак, если у вас есть class A и B, B наследуется от A, вы создаете экземпляр объекта следующим образом:

A a = new B();

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

https://msdn.microsoft.com/EN-US/library/ms173153%28v=VS.140,d=hv.2% 29.aspx е = 255 & амп;? MSPPError = -2147217396

0
ответ дан user 16 August 2018 в 05:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: