Virtual
 
Декларация метода virtual (виртуального)

Синтаксис

Type typename Extends base_typename
End Type

Описание

Virtual методы — это методы, которые могут быть переопределены в типах данных, производных от типа, в котором они были объявлены, позволяющие полиморфизм. В отличие от Abstract методов, virtual методы должны иметь реализацию метода, которая используется, когда virtual не переопределяется.

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

При вызове виртуальных методов, компилятор должен сделать поиск виртуальных таблиц, чтобы выяснить, какой метод должен быть вызван для данного объекта. Это требует дополнительных скрытых полей указателей для виртуальных таблиц, которые будут добавлены в верхней части каждого типа с виртуальными методами. Этот скрытый vptr обеспечивается встроенным Object типа. Из-за этого, виртуальные методы могут быть объявлены только в типе, который является прямым или косвенным Extends Object.

Constructors(конструкторы) не могут быть виртуальными, поскольку они создают объекты, в то время как виртуальные методы требуют уже существующий объект с определенным типом. Тип конструктора вызывает определение во время компиляции из кода.
Кроме того, при вызове виртуального метода в конструкторе, используется только локальная версия метода. Это потому, что vptr еще не создана для конструктора производного типа, а только конструктор локального типа.

Destructors могут быть виртуальными при удалении объекта, манипулируя через указатель на базовый тип, так что разрушение начинается на самом производном типе и ведет свой путь вниз к базовому типу. Чтобы сделать это, может понадобится добавление виртуальных деструкторов с пустым телом в любом месте, где явное разрушение еще не требуется.
С другой стороны, при вызове виртуального (или абстрактного) метода внутри деструктора (виртуального или нет), производный метод фактически используется, потому что vptr и его виртуальные таблицы еще там. Но это не является надежным, потому что дочерний деструктор, возможно, уже вызывается, и происходящий вызываемый метод может обращаться к разрушенным элементам.

Для методов-элементов с Virtual в своей декларации, Virtual также может быть указан на соответствующие тела методов, для улучшения читабельности кода.

Примечание: В многоуровневом наследовании, одноименный метод (тот же идентификатор и сигнатура) может быть объявлен  Abstract, Virtual или обычным (без спецификатора) на каждом уровне иерархии наследования. Когда есть смешивание спецификаторов, обычный порядок abstract -> virtual -> normal, сверху вниз в иерархии наследования.
Контроль доступа (Public/Protected/Private) из переопределенного метода не учитывается внутренним процессом полиморфизма, а учитывается только для первоначального вызова во время компиляции.
Производный статический метод не может переопределить базовый виртуальный/абстрактный метод, но может затенить любой базовый метод (включая виртуальный/абстрактный)

Пример

Type Hello extends object
    Declare virtual Sub hi( )
End Type

Type HelloEnglish extends Hello
    Declare Sub hi( )
End Type

Type HelloFrench extends Hello
    Declare Sub hi( )
End Type

Type HelloGerman extends Hello
    Declare Sub hi( )
End Type


Sub Hello.hi( )
    Print "hi!"
End Sub

Sub HelloEnglish.hi( )
    Print "hello!"
End Sub

Sub HelloFrench.hi( )
    Print "Salut!"
End Sub

Sub HelloGerman.hi( )
    Print "Hallo!"
End Sub


    Randomize( Timer( ) )

    Dim As Hello Ptr h

    For i As Integer = 0 To 9
        Select Case( Int( Rnd( ) * 4 ) + 1 )
        Case 1
            h = New HelloEnglish
        Case 2
            h = New HelloFrench
        Case 3
            h = New HelloGerman
        Case Else
            h = New Hello
        End Select

        h->hi( )
        Delete h
    Next

Различия диалектов

  • Доступно только в диалекте -lang fb.

Отличия от QB

  • Новое в FreeBASIC

См. также