Разработка API-оболочки C для объектно-ориентированного кода C ++

Почему бы не добавить промежуточное ПО с чем-то вроде этого:

class RequestMiddleware(object):

    thread_local = threading.local()

    def process_request(self, request):
        RequestMiddleware.thread_local.current_user = request.user

и позже в вашем коде (особенно в сигнале в этом разделе):

thread_local = RequestMiddleware.thread_local
if hasattr(thread_local, 'current_user'):
    user = thread_local.current_user
else:
    user = None
74
задан theactiveactor 11 January 2010 в 23:47
поделиться

5 ответов

Я работал над продуктом электронной коммерции несколько лет назад, и мы сделали это путь вы описали. Но мы добавили еще один слой для обработки нескольких атрибутов на одном продукте (размер и цвет, как вы сказали). Мы отслеживали каждый атрибут отдельно, и у нас была таблица «SKU», в которой перечислялась каждая комбинация атрибутов, разрешенная для каждого продукта. Что-то вроде этого:

attr_id   attr_name  
1         Size  
2         Color  

sku_id    prod_id    attr_id    attr_val  
1         1          1          Small  
1         1          2          Blue  
2         1          1          Small  
2         1          2          Red  
3         1          1          Large  
3         1          2          Red  

Позже мы добавили отслеживание запасов и другие функции, и мы связали их с идентификаторами sku ID, чтобы мы могли отслеживать каждый по отдельности.

-121--3383584-

В этом примере не используются никакие условия и исключения.
(Есть некое скрытое состояние при коротком замыкании ИЛИ).
Использование рекурсии позволяет избежать петель.

public class OneToHundered {

  public static boolean exit() {
    System.exit(0);
    return true;
  }

  public static boolean printToHundered(int i) {
    boolean r;
    System.out.println(i);
    r = (i<100) || exit();
    printToHundered(i+1);
    return r;
  }

  public static void main(String[] args) {
    printToHundered(1);
  }
}
-121--1851134-

Это не слишком сложно сделать вручную, но будет зависеть от размера интерфейса. Случаи, когда я делал это, чтобы разрешить использование нашей библиотеки C++ из чистого кода C, и, таким образом, SWIG не был большой помощью. (Может быть, SWIG можно использовать для этого, но я не гуру SWIG и это казалось нетривиальным)

Все, что мы в итоге сделали:

  1. Каждый объект передается в C непрозрачной ручкой.
  2. Конструкторы и деструкторы заключены в чистые функции
  3. Членов функции являются чистыми функциями.
  4. Другие сборки отображаются на эквиваленты C, где это возможно.

Итак, такой класс, как этот (заголовок C++)

class MyClass
{
  public:
  explicit MyClass( std::string & s );
  ~MyClass();
  int doSomething( int j );
}

Будет сопоставляться с C-интерфейсом, таким как этот (заголовок C):

struct HMyClass; // An opaque type that we'll use as a handle
typedef struct HMyClass HMyClass;
HMyClass * myStruct_create( const char * s );
void myStruct_destroy( HMyClass * v );
int myStruct_doSomething( HMyClass * v, int i );

Реализация интерфейса будет выглядеть следующим образом (источник C++)

#include "MyClass.h"

extern "C" 
{
  HMyClass * myStruct_create( const char * s )
  {
    return reinterpret_cast<HMyClass*>( new MyClass( s ) );
  }
  void myStruct_destroy( HMyClass * v )
  {
    delete reinterpret_cast<MyClass*>(v);
  }
  int myStruct_doSomething( HMyClass * v, int i )
  {
    return reinterpret_cast<MyClass*>(v)->doSomething(i);
  }
}

Мы извлекаем наш непрозрачный дескриптор из исходного класса, чтобы избежать необходимости в литье, и (Это, кажется, не работает с моим текущим комплексом Мы должны сделать дескриптор структурой, так как C не поддерживает классы.

Это дает нам базовый интерфейс C. Если вам нужен более полный пример, показывающий один из способов интеграции обработки исключений, то вы можете попробовать мой код на github: https://gist.github.com/mikeando/5394166

Теперь интересная часть гарантирует, что вы правильно получите все необходимые библиотеки C++, связанные в большую библиотеку. Для gcc (или clang) это означает, что выполняется только заключительная стадия связи с использованием g++.

65
ответ дан 24 November 2019 в 11:42
поделиться

Виден ли iFrame при загрузке или показан позже? Элементы создаются в другом порядке, который является основой метода setTimeout. Пробовали ли вы время ожидания с высоким значением для установленного тайм-аута?

Попробуйте что-то вроде, по крайней мере, полсекунды, чтобы проверить... IE имеет тенденцию делать вещи в другом порядке, поэтому может потребоваться большое тайм-аут, чтобы заставить его не стрелять, пока рендеринг/краска не завершится:

$(function(){
  setTimeout(function() {
    var myIFrame = $("#iframeName");
    myIFrame.focus();
    myIFrame.contents().find('#inputName').focus();
    }, 500);
});
-121--4859869-

Если поле может быть определено как метка времени, можно использовать следующее:

 ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ОБ ОБНОВЛЕНИИ CURRENT_TIMESTAMP);
-121--3527913-

Я думаю, что вы можете получить некоторые идеи о направлении и/или, возможно, использовать непосредственно SWIG . Я думаю, что рассмотрение нескольких примеров, по крайней мере, даст вам представление о том, какие вещи следует учитывать при переносе одного API в другой. Упражнение может быть полезным.

SWIG - это средство разработки программного обеспечения, которое соединяет программы, написанные на C и C++, с различными высокоуровневыми языками программирования. SWIG используется с различными типами языков, включая общие языки сценариев, такие как Perl, PHP, Python, Tcl и Ruby. Список поддерживаемых языков также включает языки без сценариев, такие как C #, Common Lisp (CLISP, Allegro CL, CFFI, UFFI), Java, Lua, Modula-3, OCAML, Octave и R. Также несколько интерпретированных и скомпилированных реализаций схемы (Guile, MzScheme, Cheme, Chicken) SWIG чаще всего используется для создания высокоуровневых интерпретируемых или скомпилированных сред программирования, пользовательских интерфейсов и в качестве инструмента для тестирования и прототипирования программного обеспечения C/C + +. SWIG также может экспортировать свое дерево синтаксического анализа в виде XML и Lisp s-выражений. SWIG может свободно использоваться, распространяться и изменяться для коммерческого и некоммерческого использования.

6
ответ дан 24 November 2019 в 11:42
поделиться

Просто замените концепцию объекта с помощью void * (часто называют непрозрачным типом в C ориентированных библиотеках) и повторно используйте все, что вы знаете от C ++.

4
ответ дан 24 November 2019 в 11:42
поделиться

Я думаю, что ответ Майкл Андерсон находится на правильном пути, но мой подход будет другим. Вы должны беспокоиться об одном дополнительных делах: исключения. Исключения не являются частью C ABI, поэтому вы не можете позволить исключениям, когда-либо брошенным в течение кода C ++. Таким образом, ваш заголовок будет выглядеть так:

#ifdef __cplusplus
extern "C"
{
#endif
    void * myStruct_create( const char * s );
    void myStruct_destroy( void * v );
    int myStruct_doSomething( void * v, int i );
#ifdef __cplusplus
}
#endif

и файл вашей обертки .CPP будет выглядеть так:

void * myStruct_create( const char * s ) {
    MyStruct * ms = NULL;
    try { /* The constructor for std::string may throw */
        ms = new MyStruct(s);
    } catch (...) {}
    return static_cast<void*>( ms );
}

void myStruct_destroy( void * v ) {
    MyStruct * ms = static_cast<MyStruct*>(v);
    delete ms;
}

int myStruct_doSomething( void * v, int i ) {
    MyStruct * ms = static_cast<MyStruct*>(v);
    int ret_value = -1; /* Assuming that a negative value means error */
    try {
        ret_value = ms->doSomething(i);
    } catch (...) {}
    return ret_value;
}

еще лучше: если вы знаете, что все, что вам нужно как один экземпляр Mystruct, не рискуйте Работа с пустотыми указателями, передаваемыми на ваш API. Сделайте что-то вроде этого вместо этого:

static MyStruct * _ms = NULL;

int myStruct_create( const char * s ) {
    int ret_value = -1; /* error */
    try { /* The constructor for std::string may throw */
        _ms = new MyStruct(s);
        ret_value = 0; /* success */
    } catch (...) {}
    return ret_value;
}

void myStruct_destroy() {
    if (_ms != NULL) {
        delete _ms;
    }
}

int myStruct_doSomething( int i ) {
    int ret_value = -1; /* Assuming that a negative value means error */
    if (_ms != NULL) {
        try {
            ret_value = _ms->doSomething(i);
        } catch (...) {}
    }
    return ret_value;
}

Эта API многое безопаснее.

Но, как упомянутое Майкл, связывание может стать довольно сложно.

Надеюсь, это поможет

14
ответ дан 24 November 2019 в 11:42
поделиться

Нетрудно выставить код C ++ к C, просто используйте шаблон дизайна фасада

, я предполагаю, что ваш код C ++ встроен в библиотеку, все, что вам нужно сделать, это сделать один C модуль в вашей библиотеке C ++ в качестве фасада в вашей библиотеке вместе с чистым файлом заголовка C. Модуль C будет вызывать соответствующие функции C ++

, как только вы выполним, что ваши приложения и библиотека C будут иметь полный доступ к выставленному вами API C API.

, Например, вот образец фасадного модуля

#include <libInterface.h>
#include <objectedOrientedCppStuff.h>

int doObjectOrientedStuff(int *arg1, int arg2, char *arg3) {
      Object obj = ObjectFactory->makeCppObj(arg3); // doing object oriented stuff here
      obj->doStuff(arg2);
      return obj->doMoreStuff(arg1);
   }

, который вы затем выставляете эту функцию C в качестве API, и вы можете свободно использовать его, как C Lib без беспокойства в

// file name "libIntrface.h"
extern int doObjectOrientedStuff(int *, int, char*);

, очевидно, это надуманный пример, но это Самый простой способ выдержать библиотеку C ++ к C

10
ответ дан 24 November 2019 в 11:42
поделиться