#oop #system-verilog
#ооп #system-verilog
Вопрос:
Этот вопрос может быть применим ко всем / большинству объектно-ориентированных языков программирования, но меня беспокоит только сторона SystemVerilog. Я думал, что понял полиморфизм, пока на днях не поговорил с коллегой, и это пришло, и я понял, что я не знаю, как это можно сделать. Ниже приведены два класса, которые следует рассмотреть для целей этого обсуждения —
class four_wheeler;
virtual function void vehicle_type();
$display("Four-wheeler");
endfunction:vehicle_type
virtual task colour();
$display("Many colours");
endtask:colour
endclass:four_wheeler
class jaguar extends four_wheeler;
function void vehicle_type();
$display("Jaguar");
endfunction:vehicle_type
task colour();
$display("Black");
endtask:colour
endclass:jaguar
program sv_prog;
initial begin
four_wheeler four_wheeler_h;
jaguar jaguar_h;
four_wheeler_h = new();
jaguar_h = new();
four_wheeler_h = jaguar_h;
four_wheeler_h.vehicle_type();
end
endprogram: sv_prog
Я хочу получить доступ к vehicle_type()
функции в базовом классе four_wheeler, используя ее собственный объект. Я могу сделать это, four_wheeler_h.vehicle_type()
перед four_wheeler_h = jaguar_h
копированием. Обычная работа ООП! Но могу ли я сделать это после копирования дескриптора?
Я могу использовать super
ключевое слово в методе jaguar class vehicle_type()
:
function void vehicle_type();
super.vehicle_type();
$display("Jaguar");
endfunction:vehicle_type
и получить результат:
Four-wheeler
Jaguar
Но меня больше интересует выполнение этого из самого программного блока без необходимости изменять функцию в классе jaguar. Есть ли какой-либо способ, которым я могу этого добиться? Возможно использование super
из самого программного блока.
Комментарии:
1. Я думаю, вам нужно описать реальный вариант использования того, чего вы пытаетесь достичь. Для вашего примера, зачем беспокоиться о том, чтобы сделать vehicle_type виртуальным методом?
2. На самом деле это гипотетический вопрос для понимания возможностей / ограничений языка.
3. Может быть вариант использования, когда я хочу получить доступ к методу базового класса и методу производного класса — оба, используя только объект базового класса, в этом случае мне нужно сделать метод базового класса виртуальным, но тогда я потеряю доступ к этому методу, если мне придется, в какой-то момент позже, получить к нему доступ. Итак, мой вопрос и к вам: могу ли я каким-то образом ‘отменить’ передачу дескриптора производного класса переменной базового класса и получить доступ к методу базового класса после первого обращения к методу производного класса (для которого я передал дескриптор производного класса переменной базового класса)?
Ответ №1:
Я боюсь, что в отличие от c , вы очень ограничены в способах выполнения этого (например, в java). Итак, все языки разные.
Аналогично java, SystemVerilog предоставляет вам ключевое слово ‘super’, которое вы можете использовать в членах класса. Вам нужно будет создать определенную функцию-член класса для доступа к его элементам базового (супер) класса в области видимости, отличной от класса:
class jaguar extends four_wheeler;
...
function super_vehicle_type();
super.vehicle_type();
endfunction
endclass:jaguar
теперь вы можете использовать
jaguar_h.super_vehicle_type();
вы также можете использовать идентификатор области видимости класса в функции для доступа к любому из базовых классов.
function super_vehicle_type();
four_wheeler::vehicle_type();
endfunction
В приведенном выше случае вы можете использовать любой из базовых классов (вместо four_wheeler) в качестве области видимости класса.
Комментарии:
1. Спасибо за ваш ответ. Из этого я понимаю, что это невозможно сделать в SystemVerilog, непосредственно из программного блока, без необходимости изменять производный класс. Таким образом, это также должно означать, что нет способа ‘отменить’ передачу дескриптора производного класса переменной базового класса, потому что, если бы мы могли это сделать, мы могли бы достичь того, к чему мы стремимся здесь. (?)
2. Нет, такого способа не существует. Все переменные, указывающие на объекты класса в SV, являются ссылками (такими же, как в java). Ссылки A всегда ссылаются на объекты, созданные
new
оператором. Итак, даже если вы присвоите ссылку производного класса ссылке базового класса, она все равно будет указывать на производный класс. Единственный способ обойти это — создать другой объект базового класса и скопировать базовые значения из производного. что-то вродеfour_wheeler fw_h = new(jaguar)
. Но вам нужно предоставить соответствующий конструктор дляfour_wheeler
.3. Спасибо, Серж. Через некоторое время я поэкспериментирую с обходным путем.
Ответ №2:
Простой ответ — нет, виртуальные методы работают не так. Полиморфизм определяет его таким образом, что вы не должны знать, что имеете дело с переопределенным объектом класса. Это все равно, что спросить, объявили ли вы элемент как local
или protected
, есть ли какой-либо способ получить доступ к этому элементу извне класса. Ответ на это также нет. Но … есть способы, которыми вы можете контролировать доступ к этим переменным-членам и методам, если вы предоставляете дополнительные методы доступа в базовом классе.
class base;
local int base_variable;
virtual function void do_this;
endfunction
function int get_base_variable;
return base_variable;
endfunction
function void base_to_this;
base::do_this();
endfunction
endless
Комментарии:
1. Спасибо, dave_59. И эта аналогия с инкапсуляцией — хороший способ объяснить реальную причину существования полиморфизма.