Функции C ++ __declspec (dllexport) не могут получить доступ к переменным экземпляра - PullRequest
0 голосов
/ 09 февраля 2012

Я пытаюсь защитить некоторый код C ++ путем экспорта в виде DLL (в Windows / VS 2010).

В приведенном ниже примере в конструкторе суперкласса установлено значение var, а отладчик показывает, чтоопределенно установлен на ссылку что-то .

. Тест создается в коде, который использует DLL, в которой содержится класс теста.

Но когда go вызывается изэкземпляр теста (вызывается из DLL, но вызывающий метод вызывается потребителем DLL) var - нулевой указатель (его значение равно 0).

Это упрощение, так как мне не разрешеночтобы поделиться реальным кодом.

//Headers

class Base {
  public:
    __declspec(dllexport) Base();      
  private:
    Foo* var;
};

class Test : Base {
public:
  __declspec(dllexport) Test();
  __declspec(dllexport) void go();
private:
};

//Body

Base::Base() {
  var = new Foo();
}

Test::Test() : Base() {
}

void Test::go() {
  var->do_something();
}

В коде-потребителе заголовок

class Base {
public:
  __declspec(dllimport) Base();
}; 

class Test {
public:
  __declspec(dllimport) Test();
  __declspec(dllimport) void go();
};

Реальный код намного сложнее, но я был бы признателен, если кто-нибудь может сказать мнесуществуют ли известные ограничения для переменных экземпляра с помощью dllexport, или более вероятно, что я вызываю метод для нулевого указателя для Test, или, возможно, это проблема dllexport и наследования.Этот код работал до того, как я разделил потребительский код и DLL-код был в том же проекте, он сломался только после его разделения: функции dllexporting / dllimporting, которые я хочу представить во втором наборе заголовков, используемых потребителем.

Ответы [ 3 ]

1 голос
/ 09 февраля 2012

Когда вы передаете значение Test по значению из одного места в другое в «коде потребления», вы будете вызывать нарезку , поскольку клиентский код не знает о переменной и вычисляет неверный размер для класса Test.

Чтобы решить эту проблему, вы должны также объявить переменную в клиентском коде, или, в качестве альтернативы, вы можете предоставить статическую фабричную функцию некоторого вида и разрешить только клиентскому коду передавать указатели на Test с, чтобы избежать нарезки .

0 голосов
/ 09 февраля 2012

Есть ли причина не использовать:

#ifdef IN_FOO_PROJECT
# define fooEXPORT __declspec(dllexport)
#else
# define fooEXPORT __declspec(dllimport)
#endif

class fooEXPORT exportClass
{
public:
  void function( void );
  Foo * var;
}

Если вы хотите скрыть свой класс (или часть вашего класса), вы можете использовать его в качестве частного члена:

#ifdef IN_FOO_PROJECT
# define fooEXPORT __declspec(dllexport)
#else
# define fooEXPORT __declspec(dllimport)
#endif

class classToHide;

class fooEXPORT exportClass
{
public:
  void function( void );
  classToHide * var;
}

А в Cpp:

#include "exportClass.h"
#include "classToHide.h"

void exportClass::function( void )
{
  var->function();
}
0 голосов
/ 09 февраля 2012

Если вы удалите переменную экземпляра из кода, предоставленного клиенту, только ваш собственный код будет знать реальный размер вашего объекта и сможет его создать. От всей моей головы у вас есть два способа сделать это:

  1. Предоставить статическую функцию createTest, которая создает экземпляр вашего класса (фабричный метод). Самое приятное, что можно сделать здесь, это предоставить чистый интерфейс (без переменной экземпляра).

  2. Если вы хотите скрыть только определенную часть своего класса, вы можете использовать идиому pimpl ( статья в Википедии ).

...