Оборачивание объекта C ++ в extern "C" - PullRequest
7 голосов
/ 27 мая 2011

рассмотрим простой пример класса:

class BankAccount {
public:
   BankAccount() { balance =0.0; };
  ~BankAccount() {};
   void deposit(double amount) {
      balance += amount;
   }
   private:
      double balance;
};

Теперь скажите, что я хочу обернуть это в extern "C", чтобы я мог вызывать его из разных языков программирования, таких как C # и Java. Я попробовал следующее, которое, казалось, работало:

// cbankAccount.h:
extern "C" unsigned long createBackAccount(); 
extern "C" void deposit(unsigned long bankAccount, double amount);
// cbankAccount.cpp
unsigned long createBackAccount() {
  BankAccount *b = new BankAccount();
  return (unsigned long) b;
}
void deposit(unsigned long bankAccount, double amount) {
  BankAccount *b = (BankAccount*) bankAccount;
  b->deposit(amount);
} 

Это портативный? Является ли тип unsigned "unsigned long" достаточно большим для указателя объекта? Есть ли другие проблемы с этим подходом?

Заранее благодарен за любые ответы!

Ответы [ 6 ]

10 голосов
/ 27 мая 2011

Да. Это плохо. Действительно плохо. unsigned long - просто нет. Верните правильно напечатанный BankAccount* - другие языки увидят его на другом конце как универсальный указатель (такой как System.IntPtr), и нет необходимости возвращать нетипизированный указатель, когда двоичный интерфейс все равно не вводит указатели.

extern "C" BankAccount* CreateBankAccount() {
    return new BankAccount;
}
extern "C" void deposit(BankAccount* account, double amount) {
    account->deposit(amount);
}
9 голосов
/ 27 мая 2011

Это в принципе выглядит хорошо с одной оговоркой. Попытка использовать целочисленный тип для хранения указателя не очень хорошая идея - гораздо лучше использовать void*, поскольку по определению это ширина указателя.


На самом деле, я думаю, что ответ @ DeadMG - более чистый подход, чем этот.

5 голосов
/ 27 мая 2011

Type-strong даже лучше, чем void *.

typedef struct BankAccountProxy *  BankAccountPtr;

BankAccountPtr createBackAccount() {
  BankAccount *b = new BankAccount();
  return (BankAccountPtr) b;
}
3 голосов
/ 27 мая 2011

Вероятно, это будет зависеть от платформы, если long достаточно велик (вероятно, не для x86-64), альтернативой является использование что-то вроде swig

3 голосов
/ 27 мая 2011

Это не переносимо, потому что unsigned long может быть недостаточно длинным для указателя. Не редкая платформа, где это происходит, - win64.

Лучше использовать ptrdiff_t или void*.

2 голосов
/ 27 мая 2011

Я бы использовал void * вместо unsigned long.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...