Программный интерфейс: различия между версиями
Nachinka (обсуждение | вклад) |
Nachinka (обсуждение | вклад) |
||
Строка 144: | Строка 144: | ||
<syntaxhighlight lang="pascal"> | <syntaxhighlight lang="pascal"> | ||
type | |||
ICalcFuncHandle = ^ICalculatorFunctions; | |||
ICalculatorHandle = ^ICalculator; | |||
ICalculatorFunctions = record | |||
Add: function(pThis: ICalculatorHandle; a, b:integer): integer;stdcall; | |||
end; | |||
ICalculator = record | |||
pFunc:ICalcFuncHandle; | |||
end; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=====Реализация сервера===== | =====Реализация сервера===== | ||
<syntaxhighlight lang=pascal> | <syntaxhighlight lang=pascal> | ||
function Add(pThis: ICalculatorHandle; a,b:integer):integer;stdcall; | |||
begin | |||
result:=a+b; | |||
end; | |||
function GetObject():ICalculatorHandle;stdcall; | |||
var Calc:ICalculatorHandle; | |||
begin | |||
Calc:=new(ICalculatorHandle); | |||
Calc^.pFunc^.Add := @Add; | |||
result:= Calc; | |||
end; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=====Реализация клиента===== | =====Реализация клиента===== | ||
<syntaxhighlight lang=pascal> | <syntaxhighlight lang=pascal> | ||
const | const | ||
{$ifdef win32} | {$ifdef win32} | ||
Строка 167: | Строка 186: | ||
{$endif} | {$endif} | ||
{$endif} | {$endif} | ||
function GetObject():ICalculatorHandle; stdcall; external serverlib; | function GetObject():ICalculatorHandle; stdcall; external serverlib; | ||
Строка 188: | Строка 195: | ||
writeln(pObject^.pFunc^.Add(pObject, 2,3)); | writeln(pObject^.pFunc^.Add(pObject, 2,3)); | ||
readln() | readln() | ||
end. | end. | ||
</syntaxhighlight> | </syntaxhighlight> |
Версия 18:58, 24 января 2016
Под программным интерфейсом, если не оговорено иное, понимается набор число виртуальных функций, вызываемых над скрытым указателем на объект, либо согласно спецификации thiscall, либо (для обеспечения межъязыковой совместимости) stdcall с первым скрытым параметром - указателем на объект.
Пусть интерфейс определен как
struct IFace
{
virtual void Method() = 0;
};
Такой интерфейс связан с объектом, обычно получаемым через компонент фабрику-класса
IClassFactory$ refFactory = get(); //Экземпляр порождающего класса, полученный откуда-то
IFace& inst = refFactory->CreateInstance(/*Аргументы*/);
либо через точку входа, имеющую связывание в стиле C
/*Импортируемая откуда-то функция, связывание C*/
extern "C" void* /*dllimport*/ GetObject(/*параметры*/);
struct IFace
{
virtual void Method() = 0;
};
int main(int argc, char** argv)
{
IFace* object_ptr = (struct IFace*) GetObject(/*аргументы*/);
object_ptr->Method();
return 0;
}
либо предоставляется как параметр какой-либо функции
void caller(IFace* object_ptr)
{
object_ptr->Method();
}
Межъязыковая совместимость интерфейсов
Язык C++
Определение интерфейса
struct ICalculator
{
virtual int __stdcall Add(int A, int B) = 0;
};
extern "C" void* __stdcall GetObject();
Реализация сервера
struct Implementation:ICalculator
{
virtual int __stdcall Add(int A, int B);
};
int __stdcall Implementation::Add(int A, int B)
{
return A + B;
}
extern "C" void* __stdcall GetObject()
{
static Implementation instance;
return &instance;
}
Реализация клиента
#include <iostream>
int main(int, char**)
{
ICalculator* pObject = (ICalculator*) GetObject();
std::cout << "Summ of 2 and 3 is " << pObject->Add(2, 3) << ".\n";
return 0;
}
Язык C
Определение интерфейса
В языке нет понятия классов с методами, поэтому интерфейс определяется как структура с указателем на список указателей на функции-реализации методов интерфейса. Указатель на объект класса, над которым вызывается метод, передается в каждую функцию-метод как первый параметр. В архитектуре x86 и языке C++ этот параметр обычно передается через регистр ecx (см. thiscall), поэтому методы реализуются согласно спецификации stdcall, требующей передачу всех параметров через стек. Для x64 данное требование не применимо, так как в этом случае для функций и методов используется единая (для платформы) конвенция вызовов.
struct ICalculator;
struct ICalculator_functionlist
{
int (__stdcall * Add)(struct ICalculator* pThis, int A, int B);
};
struct ICalculator
{
struct ICalculator_functionlist* pFunc;
};
void* __stdcall GetObject();
Реализация сервера
int __stdcall Add(struct ICalculator* pThis, int A, int B)
{
return A + B;
}
void* __stdcall GetObject()
{
static struct ICalculator_functionlist vtbl = {Add};
static struct ICalculator impl = {{&vtbl}};
return &impl;
}
Реализация клиента
#include <stdio.h>
int main(int argc, char** argv)
{
struct ICalculator* pInst = GetObject();
printf("Summ of 2 and 3 is %d.\n", pInst->pFunc->Add(pInst, 2, 3));
return 0;
}
Язык Free Pascal
Определение интерфейса
Free Pascal как и С++ - объектно-ориентированный. Но механизм вызова методов объектов отличается. Поэтому приходится взаимодействовать через указатель на список указателей на функции аналогично языку C.
type
ICalcFuncHandle = ^ICalculatorFunctions;
ICalculatorHandle = ^ICalculator;
ICalculatorFunctions = record
Add: function(pThis: ICalculatorHandle; a, b:integer): integer;stdcall;
end;
ICalculator = record
pFunc:ICalcFuncHandle;
end;
Реализация сервера
function Add(pThis: ICalculatorHandle; a,b:integer):integer;stdcall;
begin
result:=a+b;
end;
function GetObject():ICalculatorHandle;stdcall;
var Calc:ICalculatorHandle;
begin
Calc:=new(ICalculatorHandle);
Calc^.pFunc^.Add := @Add;
result:= Calc;
end;
Реализация клиента
const
{$ifdef win32}
serverlib = 'server.dll';
{$else}
{$ifdef darwin}
serverlib = 'server';
{$linklib server}
{$else}
serverlib = 'server.so';
{$endif}
{$endif}
function GetObject():ICalculatorHandle; stdcall; external serverlib;
var pObject:ICalculatorHandle;
begin
pObject:= GetObject();
write('Sum of 2 and 3 is ');
writeln(pObject^.pFunc^.Add(pObject, 2,3));
readln()
end.