Программный интерфейс: различия между версиями

Материал из CAMaaS preliminary wiki
Перейти к навигации Перейти к поиску
(Новая страница: «Под программным интерфейсом, если не оговорено иное, понимаетс…»)
 
Строка 44: Строка 44:
</syntaxhighlight>
</syntaxhighlight>


===Примеры вызовов на разных языках, отличных от C++===
===Межъязыковая совместимость интерфейсов===


Для интерфейса <tt>IFace</tt>, определенного как
====Язык C++====


=====Определение интерфейса=====
<syntaxhighlight lang=cpp>
<syntaxhighlight lang=cpp>
struct ICalculator
struct ICalculator
{
{
   virtual int __stdcall Add(int A, int B) = 0;
   virtual int __stdcall Add(int A, int B) = 0;
  //Спецификатор stdcall может отличаться для разных языков и компиляторов одного языка. В MSVC и GCC __stdcall задан.
};
};
extern "C" void* __stdcall GetObject();
</syntaxhighlight>
</syntaxhighlight>


Клиент на C.
=====Реализация сервера=====
 
<syntaxhighlight lang=cpp>
struct Implementation:ICalculator
{
  virtual int __stdcall Add(int A, int B);
};
 
int __stdcall Implementation::Add(int A, int B)
{
  return A + B;
}


<syntaxhighlight lang=c>
extern "C" void* __stdcall GetObject()
/*Определение интерфейса на C, в котором нет понятия классов с методами:**/
{
struct ICalculator; /*Объявление*/
  static Implementation instance;
  return &instance;
}
</syntaxhighlight>
 
=====Реализация клиента=====
<syntaxhighlight lang=cpp>
#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;
}
</syntaxhighlight>
 
====Язык C====
 
=====Определение интерфейса=====
 
В языке нет понятия классов с методами, поэтому интерфейс определяется как структура с указателем на список указателей на функции-реализации методов интерфейса. Указатель на объект класса, над которым вызывается метод, передается в каждую функцию-метод как первый параметр. В архитектуре x86 и языке C++ этот параметр обычно передается через регистр <tt>ecx</tt> (см. [https://en.wikipedia.org/wiki/X86_calling_conventions#thiscall thiscall]), поэтому методы реализуются согласно спецификации stdcall, требующей передачу всех параметров через стек. Для x64 данное требование не применимо, так как в этом случае для функций и методов используется единая (для платформы) [https://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions конвенция вызовов].
 
<syntaxhighlight lang="c">
struct ICalculator;


struct ICalculator_functionlist
struct ICalculator_functionlist
{
{
   int (__stdcall * Add)(struct IFace* pThis, int A, int B);
   int (__stdcall * Add)(struct ICalculator* pThis, int A, int B);
};
};


Строка 72: Строка 109:
};
};


int main(int argc, char** argv);
void* __stdcall GetObject();
</syntaxhighlight>
 
=====Реализация сервера=====
<syntaxhighlight lang=c>
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;
}
</syntaxhighlight>
 
=====Реализация клиента=====
<syntaxhighlight lang=c>
#include <stdio.h>
 
int main(int argc, char** argv)
{
{
  /*Получение экземпляра через точку входа*/
struct ICalculator* pInst = GetObject();
  struct ICalculator* pInst = (struct ICalculator*) GetObject(/*аргументы*/);
printf("Summ of 2 and 3 is %d.\n", pInst->pFunc->Add(pInst, 2, 3));
  /*Вызов*/
return 0;
  printf("%d", pInst->pFunc(pInst, 1, 2));
  return 0;
}
}
</syntaxhighlight>
</syntaxhighlight>

Версия 18:05, 23 января 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;
}