Члены виртуальной базы не видят переопределений? - PullRequest
5 голосов
/ 31 августа 2010

Я всегда думал, что base.Something было эквивалентно ((Parent)this).Something, но, очевидно, это не так. Я думал, что переопределение методов исключает возможность вызова оригинального виртуального метода.

Почему третий выход отличается?

void Main() {
    Child child = new Child();

    child.Method();             //output "Child here!"
    ((Parent)child).Method();   //output "Child here!"
    child.BaseMethod();         //output "Parent here!"
}

class Parent {
    public virtual void Method() { 
        Console.WriteLine("Parent here!"); 
    }
}

class Child : Parent {
    public override void Method() { 
        Console.WriteLine ("Child here!"); 
    }
    public void BaseMethod() { 
        base.Method(); 
    }
}

Ответы [ 6 ]

5 голосов
/ 31 августа 2010

Поскольку в BaseMethod вы явно вызываете метод в базовом классе, используя ключевое слово base. Существует разница между вызовами Method() и base.Method() в классе.

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

3 голосов
/ 31 августа 2010

C # Спецификация языка:

Во время компиляции базовый доступ выражения формы base.I и База [E] оцениваются точно так же, как если бы они были написаны ((B) это). Я и ((B) это) [E], где B является основанием класс класса или структуры, в которой конструкция происходит.

Когда базовый доступ ссылается на член виртуальной функции (метод, свойство, или индексатор), определение какого члена функции вызывать во время выполнения (§7.4.4) изменилось. Член функции, который вызывается определяется путем нахождения наиболее производная реализация (§10.6.3) члена функции по отношению к B (вместо по отношению к тип во время выполнения этого, как было бы обычный в неосновном доступе).

т.е. base.Something эквивалентно ((Parent) this) .Something, но только для не виртуальных членов, в противном случае семантика отличается.

3 голосов
/ 31 августа 2010

((Parent)this).foo для виртуального метода foo по-прежнему / всегда является вызовом виртуального метода. Целевой адрес будет найден в таблице виртуальных методов класса, что всегда даст вам самую лучшую реализацию для типа экземпляра объекта. Вы можете привести его к родительскому типу, сколько захотите, но это не изменит виртуальную таблицу, используемую для отправки вызова во время выполнения.

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

2 голосов
/ 31 августа 2010

Я полагаю, вы неправильно поняли base.Something(). base специально вызывает базовые классы (возможно) переопределенную реализацию метода или свойства. Из MSDN :

Базовое ключевое слово используется для доступа члены базового класса изнутри производный класс:

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

Обратите внимание, что ((Parent)this).Something() повлияет только на то, что вызывается, если вы используете new, чтобы скрыть метод вместо override виртуального.

1 голос
/ 31 августа 2010

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

В BaseMethod вы вызываете base.Method, который является способом получения доступа к родительской функции (если вам это нужно), но если у вас есть массивтип Shape, и в нем разные подклассы формы, вы хотите, чтобы метод .Draw () вызывал подкласс, а не метод суперкласса (по умолчанию).

0 голосов
/ 31 августа 2010

Это связано с пониманием полиморфизма.

http://en.wikipedia.org/wiki/Type_polymorphism

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...