Я могу Переопределить с производными типами?

Я помещаю превосходный ответ JLBorges на аналогичный вопрос дословно из cplusplus.com, так как это наиболее краткое объяснение, которое я прочитал по этому вопросу.

] В шаблоне, который мы пишем, есть два типа имен, которые можно использовать - зависимые имена и не зависимые имена. Зависимое имя - это имя, которое зависит от параметра шаблона; неизменяемое имя имеет то же значение, независимо от параметров шаблона.

Например:

template< typename T > void foo( T& x, std::string str, int count )
{
    // these names are looked up during the second phase
    // when foo is instantiated and the type T is known
    x.size(); // dependant name (non-type)
    T::instance_count ; // dependant name (non-type)
    typename T::iterator i ; // dependant name (type)

    // during the first phase, 
    // T::instance_count is treated as a non-type (this is the default)
    // the typename keyword specifies that T::iterator is to be treated as a type.

    // these names are looked up during the first phase
    std::string::size_type s ; // non-dependant name (type)
    std::string::npos ; // non-dependant name (non-type)
    str.empty() ; // non-dependant name (non-type)
    count ; // non-dependant name (non-type)
}

То, что зависит от зависимого имени, может быть чем-то другим для каждого конкретного экземпляра шаблона. Как следствие, шаблоны C ++ подвержены «двухфазному поиску имен». Когда шаблон сначала анализируется (до того, как выполняется какое-либо создание), компилятор просматривает не зависящие имена. Когда происходит конкретное создание шаблона, параметры шаблона известны к тому времени, и компилятор ищет зависимые имена.

На первом этапе анализатор должен знать, является ли зависимое имя именем типа или имени не-типа. По умолчанию зависимым именем считается имя не-типа.

Использовать ключевое слово typename только в объявлениях шаблонов и определениях, приведенных ниже.

blockquote>

у вас есть квалифицированное имя, которое относится к типу и зависит от параметра шаблона.

39
задан Luis Filipe 22 February 2016 в 17:59
поделиться

8 ответов

Это не возможно ни на каком языке.NET из-за проблем безопасности типов. На безопасных с точки зрения типов языках необходимо обеспечить ковариантность для возвращаемых значений и контравариантность для параметров. Возьмите этот код:

class B {
    S Get();
    Set(S);
}
class D : B {
    T Get();
    Set(T);
}

Для эти Get методы, ковариантность означает, что T должен или быть S или тип, полученный от S. Иначе, если бы у Вас была ссылка на объект типа D, сохраненного в переменной, введенной B, когда Вы звонили B.Get(), то Вы не получили бы объект, представимый как S назад - повреждение системы типов.

Для эти Set методы, контравариантность означает, что T должен или быть S или тип, который S происходит из. Иначе, если у Вас была ссылка на объект типа D, сохраненного в переменной, введенной B, когда Вы звонили B.Set(X), где X имел тип S, но не типа T, D::Set(T) получит объект типа, который это не ожидало.

В C#, там сознательное решение состояло в том, чтобы запретить изменение типа при перегрузке свойств, даже когда у них есть только одна из пары метода get/метода set, потому что это иначе имело бы очень непоследовательное поведение (, "Вы имеете в виду, я могу изменить тип на том с методом get, но не один и с методом get и с методом set? Почему нет?!?" - Анонимный Альтернативный Новичок Вселенной).

25
ответ дан Neuron 27 November 2019 в 02:21
поделиться

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

public class Father
{
    public Father SomePropertyName
    {
        get {
            return SomePropertyImpl();
        }
    }
    protected virtual Father SomePropertyImpl()
    {
        // base-class version
    }
}

public class Child : Father
{
    public new Child SomePropertyName
    {
        get
        { // since we know our local SomePropertyImpl actually returns a Child
            return (Child)SomePropertyImpl();
        }
    }
    protected override Father SomePropertyImpl()
    {
        // do something different, might return a Child
        // but typed as Father for the return
    }
}
42
ответ дан Marc Gravell 27 November 2019 в 02:21
поделиться

Нет, но можно использовать дженерики в 2 и выше:

public class MyClass<T> where T: Person
{
    public virtual T SomePropertyName
    {
        get
        {
            return  ...;
        }
    }
}

Тогда Родительский элемент и Ребенок являются универсальными версиями того же класса

11
ответ дан Keith 27 November 2019 в 02:21
поделиться

От Википедия :

На языке программирования C#, поддержке и ковариантности типа возврата и контравариантности параметра для делегатов был добавлен в версии 2.0 языка. Ни ковариантность, ни контравариантность не поддерживаются для переопределения метода.

Это ничего явно не говорит о ковариантности свойств все же.

7
ответ дан dalle 27 November 2019 в 02:21
поделиться

Можно создать единый интерфейс для родительского элемента и ребенка и возвратить тип того интерфейса.

2
ответ дан VVS 27 November 2019 в 02:21
поделиться

Нет. C# не поддерживает эту идею (это называют "ковариантностью типа возврата"). Можно однако сделать это:

public class FatherProp
{
}

public class ChildProp: FatherProp
{
}


public class Father
{
    public virtual FatherProp SomePropertyName
    {
        get
        {
            return new FatherProp();
        }
    }
}


public class Child : Father
{
    public override FatherProp SomePropertyName
    {
        get
        {
            // override to return a derived type instead
            return new ChildProp();
        }
    }
}

т.е. использование контракт, определенный базовым классом, но возвратом производный тип. Я сделал более подробный образец для высказывания этого более ясного мнения - возвращающий "это" снова ничего не изменил бы.

Это возможно (но грязно) протестировать возвращенный объект, поскольку это - фактический тип (т.е., "если someObject является ChildProp"), но лучше назвать виртуальный метод на нем, который делает правильную вещь для ее типа.

базовый класс виртуальный метод (в этом случае, виртуальное свойство) не только имеют реализацию, но также и определяют контракт: то, что дочерний класс может предоставить различную реализацию SomePropertyName, если это выполняет этот контракт (т.е. SomePropertyName возвращает объект типа "FatherProp"). Возврат объекта типа "ChildProp", полученный из "FatherProp", выполняет этот контракт. Но Вы не можете изменить контракт в "Ребенке" - этот контракт относится ко всем классам, убывавшим от "Родительского элемента".

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

1
ответ дан Anthony 27 November 2019 в 02:21
поделиться

номер C# не поддерживает эту идею (это называют "ковариантностью типа возврата").

Из Википедии:

На языке программирования C#, поддержке и ковариантности типа возврата и контравариантности параметра для делегатов был добавлен в версии 2.0 языка. Ни ковариантность, ни контравариантность не поддерживаются для переопределения метода.

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

лучшие решения состояли бы в том, чтобы использовать дженерики:

public class MyClass<T> where T: Person
{
   public virtual T SomePropertyNameA
   {        
      get { return  ...; }    
   }
}//Then the Father and Child are generic versions of the same class
1
ответ дан Micah 27 November 2019 в 02:21
поделиться

Это является самым близким, я мог приехать (до сих пор):

    public sealed class JustFather : Father<JustFather> {}

    public class Father<T> where T : Father<T>
    { public virtual T SomePropertyName
        { get { return (T) this; }
        }
    }

    public class Child : Father<Child>
    { public override Child SomePropertyName
        { get { return  this; }
        }
    }

Без JustFather класс, Вы не могли инстанцировать Father<T>, если это не был некоторый другой производный тип.

1
ответ дан Mark Cidade 27 November 2019 в 02:21
поделиться
Другие вопросы по тегам:

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