Я нахожусь в середине моего задания, и я столкнулся с этим вопросом:
Предполагая, что иногда мы хотим статического связывания, вы предпочитаете метод по методу
подход C ++ и C # или подход «переменные за переменными» в Ada 95? Почему?
Я искал в Интернете и учебник, но я не мог найти, что означает метод «метод за методом» в C ++ или метод «переменная за переменной» в Ada. Может кто-нибудь сказать мне значение этих терминов и что лучше из этих двух подходов.
Заранее спасибо!
Давайте сначала посмотрим на пример, C ++:
class Base {
public:
void a();
virtual void b();
};
class Derived : public Base {
public:
void a();
virtual void b();
};
Base* base = new Base();
Derived* derived = new Derived();
Base* upcastedDerived = new Derived();
base->a(); // calls Base::a()
base->b(); // calls Base::b()
derived->a(); // calls Derived::a()
derived->b(); // calls Derived::b()
upcastedDerived->a(); // calls Base::a()
upcastedDerived->b(); // calls Derived::b()
Называя методы base
а также derived
дает очевидные результаты. На upcastedDerived
Призыв к a()
связан во время компиляции (статическое связывание), поэтому он связан с Base::a()
потому что переменная имеет тип Base*
, Призыв к b()
однако связан во время выполнения, потому что метод объявлен virtual
, Потому что объект на самом деле класса Derived
, Derived::b()
вызывается.
Как вы видите, в C ++ от объявления метода зависит, связан ли вызов метода статически или динамически. Обратите внимание, что ключевое слово virtual
в производном классе необязателен — метод автоматически является виртуальным, поскольку базовый метод, который он переопределяет, является виртуальным.
Теперь давайте сделаем что-то похожее с Ada:
procedure Dispatching is
type Base is tagged null record;
procedure A (Object : in out Base);
type Derived is new Base with null record;
overriding procedure A (Object : in out Derived);
Base_Var : Base;
Derived_Var : Derived;
Upcasted_Var : Base'Class := Derived_Var;
begin
A (Base_Var); -- calls first A() procedure
A (Derived_Var); -- calls second A() procedure
A (Upcasted_Var); -- calls second A() procedure
end Derived;
Первое, что нужно отметить: у Ады нет ключевого слова, похожего на virtual
, Все методы могут быть связаны статически или динамически. Как видите, это зависит от типа переменной объекта: Base_Var
а также Derived_Var
оба имеют конкретный тип, и поэтому вызывается процедура этого типа. Upcasted_Var
с другой стороны, имеет тип класса (это не имеет эквивалента в C ++). Поэтому третий призыв к A()
связан динамически.
Подводя итог: в C ++ (и C #) есть способ аннотировать метод независимо от того, должен ли он отправляться или нет. У Ады есть способ аннотировать переменную объекта, независимо от того, должны ли вызовы ее функций отправляться или нет. Чтобы контролировать, является ли вызов диспетчеризируемым или нет, вы можете привести переменную к общеклассовому типу в Ada (вы не должны приводить к конкретному типу, чтобы предотвратить диспетчеризацию, потому что, если у вас уже есть общеклассный тип, вы не можете будь уверен, сможешь ли ты это разыграть).
Вы можете видеть это так: в C ++ любой указатель на класс является общеклассовым. В Аде любая примитивная подпрограмма тегового типа является виртуальной. Для полноты, вот как вы можете предотвратить диспетчеризацию на основе переменной в C ++:
upcastedDerived.Base::b();
Я не буду обсуждать, какой из них является лучше подход, потому что это в первую очередь основано на мнении.
Других решений пока нет …