Я работаю над экспериментом по моделированию цифровой логики. (Логические ворота.)
У меня есть абстрактный базовый класс component
из которого класс andgate
наследует. Класс port
также наследует от component
, Учебный класс port
имеет члена; PORTSTATE state
,
PORTSTATE
является классом enum, со значениями, включающими HIGH
, LOW
, HIGH_IMPEDANCE
, UNDEFINED
и т. д. (Это просто справочная информация.)
Симуляция работает путем изменения состояния входного порта на некоторый логический вентиль. Ворота связаны (используя указатели) с классом Net
который в свою очередь имеет указатели на всю подключенную логику в этой сети. Это позволяет изменять все ворота ниже по потоку от одного, который изменил свое состояние, как требуется. Рассмотрим состояние логического элемента, изменяющегося из-за изменения на входе, при использовании сети, к которой подключен его выход, любые шлюзы, расположенные дальше по последовательности, могут быть соответствующим образом обновлены.
Мой вопрос о том, как этот процесс должен быть выполнен с использованием дружественных функций и бинарных операторов, таких как operator&
,
Рассмотрим вентиль And с 1 выходным портом и 2 входными портами. Порты являются членами класса, представляющего ворота, и к ним прикреплена некоторая информация, такая как их направление, а также их состояние.
Вызывается функция для вычисления выхода гейта из входов. Эта функция является функцией-членом класса gate. Например, у шлюза And есть версия этой функции.
Изначально я реализовал функцию следующим образом.
void Update()
{
this->output_port.SetState(this->input_port_a & this->input_port_b);
}
Важность в том, что operator&
вызывается с аргументами 2 входных вентилей; input_port_a
а также input_port_b
в качестве аргументов.
В классе порта я тогда реализовал этот оператор.
friend const port& operator&(const port& left, const port& right)
{
if((left.state == PORTSTATE::HIGH) && (right.state == PORTSTATE::HIGH))
{
return PORTSTATE::HIGH;
}
else if( // These are the 3 options for definitive low
((left.portstate == PORTSTATE::LOW) && (right.portstate == PORTSTATE::HIGH))
|| ((left.portstate == PORTSTATE::LOW) && (right.portstate == PORTSTATE::LOW))
|| ((left.portstate == PORTSTATE::HIGH) && (right.portstate == PORTSTATE::LOW))
)
{
return PORTSTATE::LOW;
}
else
{
return PORTSTATE::UNDEFINED; // Anything else is not defined
}
}
Но у меня есть серьезные проблемы с этим. Вы не можете «И» 2 порта вместе. Порт — это абстрактное понятие, метод отслеживания того, какой ток течет (или, что то же самое, какое напряжение подается) на какие входы или выходы. Более физическая интерпретация состоит в том, что порт представляет собой короткий отрезок провода, через который проходит некоторый ток. Ток либо «ВЫСОКИЙ», либо «НИЗКИЙ», но, конечно, нет способа «И» соединить эти 2 объекта. Я думаю, что большинство инженеров и физиков, вероятно, смотрят на этот кусок кода в ужасе из-за этого.
Таким образом, «очевидное» решение состоит в том, чтобы разместить operator&
внутри ворот А как дружественная функция.
Однако те, кто не спит, поймут, что это тоже плохая * идея, потому что тогда было бы возможно только &
2 экземпляра И ворот вместе, и это, конечно, не имеет смысла, и при этом он не вычисляет правильный результат! (Может ли это даже вычислить разумный результат? Маловероятно.)
*(совершенно неправильно)
Рассматривать;
andgate and_gate_1, and_gate_2;
// Setup the inputs, outputs, connections, networks
// When stepping through the simulation, we end up with something like this:
and_gate_1.Update();
// Which calls a function like this:
const andgate& operator&(const andgate& left, const andgate& right)
{
// How would you even implement this? It makes no sense...
}
Так что да, это проблема, и я не могу придумать решение. Хотя в некотором смысле это концептуально, идея использовать первый подход и иметь возможность «И» соединить два кусочка проволоки кажется серьезной ошибкой.
Единственное, о чем я могу думать, это обойтись без операторов и программировать все вручную внутри шлюзов And. Update()
функция … Но этот тип избегает хороших вещей в C ++, которые заключаются в том, что вы можете писать операторы для таких вещей.
Обратите внимание, что если бы не было такой вещи, как PORTSTATE
и если в замен bool
не было бы проблемы, так как 2 типа логики могут быть просто &
‘вместе Однако это изменит Update()
что-то вроде этого, что тоже не очень приятно. (Обратите внимание, что членский доступ открыт
void Update()
{
return (input_a.state) & (input)b.state); // input_* is of type port, state is a bool
}
Возможно, лучше защитить данные: (но, может быть, «выглядит» хуже из-за вызова функции?)
void Update()
{
return (input_a.state()) & (input)b.state()); // input_* is of type port
// state() is a member function returning a bool
}
Это также вводит проблему только двух существующих состояний. Нет ничего, что могло бы обрабатывать неопределенные состояния или состояния с высоким импедансом и т. Д.
Так что я застрял и вне идей.
Перегрузить operator&
для двоих PORTSTATE
, Устраняя проблему с UNDEFINED
это заставит вашу последнюю форму работать.
PORTSTATE operator&(const PORTSTATE& a, const PORTSTATE& b)
{
...
}
void Update()
{
return input_a.state() & input_b.state(); // input_* is of type port
// state() is a member function returning a bool
}
Для меня это самый правильный путь, потому что операция AND работает только с состояниями.
Вызов функции-члена не сбивает с толку и широко используется. Во-первых, это делает явным то, что порт имеет состояние, в котором вы находитесь (и это более логично). Во-вторых, это защищает state
поле от внешней модификации.