Вопрос про классы в C++

Тема в разделе "WASM.ZEN", создана пользователем Pasha 111, 22 фев 2005.

  1. Pasha 111

    Pasha 111 New Member

    Публикаций:
    0
    Регистрация:
    10 авг 2003
    Сообщения:
    19
    Есть класс CTEST:


    Код (Text):
    1.  
    2. class COBJECT
    3. {
    4. public:
    5.     virtual ~COBJECT(){};
    6. };
    7.  
    8. class CTEST: public COBJECT
    9. {
    10. public:
    11.     virtual void func()
    12.     {
    13.         ...........
    14.     }
    15. };
    16.  




    Есть функции:


    Код (Text):
    1.  
    2. extern "C" __declspec(dllexport) void NewObj(CTEST **ppNewObj)
    3. {
    4.     *ppNewObj = new CTEST;
    5. }
    6.  
    7. extern "C" __declspec(dllexport) void DeleteObj(CTEST *pObj)
    8. {
    9.     if(pObj) delete pObj;
    10. }
    11.  




    Всё это компилируется в библиотеку (dll).



    В другой программе (exe):


    Код (Text):
    1.  
    2. #pragma comment(lib, "Test.lib")
    3.  
    4. class COBJECT
    5. {
    6. public:
    7.     virtual ~COBJECT();
    8. };
    9.  
    10. class CTEST: public COBJECT
    11. {
    12. public:
    13.     virtual void func();
    14. };
    15.  
    16. extern "C" __declspec(dllimport) void NewObj(CTEST **ppNewObj);
    17. extern "C" __declspec(dllimport) void DeleteObj(CTEST *pObj);
    18.  






    Далее тут идёт ошибка:


    Код (Text):
    1.  
    2. class CMYTEST: public CTEST
    3. {
    4. public:
    5.     int SomeValue;
    6. }
    7.  
    8. ..............
    9.  
    10. void main()
    11. {
    12.     CMYTEST *a = NULL;
    13.     NewObj((CTEST **)&a);
    14.     a->SomeValue = 5; // <-- ошибка
    15. }
    16.  




    Т.е. получается, что при вызове функции new() в dll-ке, выделяется память под базовый класс, а под SomeValue не выделяется, поэтому при записи a->SomeValue = 5 может возникнуть ошибка типа "память не может быть write" :)

    Что можно сделать?





    Я тут подумал, а что, если сделать так (в DLL):


    Код (Text):
    1.  
    2. extern "C" __declspec(dllexport) void NewObj(CTEST **ppNewObj)
    3. {
    4.     // Если память уже выделена в exe, то
    5.     if(*ppNewObj)
    6.     {
    7.         // Создаём объект
    8.         CTEST obj;
    9.         // Копируем его поля (чтобы и указатель на таблицу виртуальных
    10.         // функций скопировался)
    11.         memcpy(*ppNewObj, &obj, sizeof(obj);
    12.         // Выходим
    13.         return;
    14.     }
    15.     *ppNewObj = new CTEST;
    16. }
    17.  




    В exe-шнике:


    Код (Text):
    1.  
    2. template <class DATA_TYPE>
    3. DATA_TYPE *New(DATA_TYPE **Data)
    4. {
    5.   *Data = (DATA_TYPE *)new BYTE[sizeof(DATA_TYPE)];
    6.   return *Data;
    7. }
    8.  
    9. class CMYTEST: public CTEST
    10. {
    11. public:
    12.     int SomeValue;
    13. }
    14.  
    15. ..............
    16.  
    17. void main()
    18. {
    19.     CMYTEST *a = NULL;
    20.     New(&a);
    21.     NewObj((CTEST **)&a);
    22.     a->SomeValue = 5; // <-- ошибки быть не должно
    23.     DeleteObj(a);
    24. }
    25.  




    Но потом понял, что всё равно это неправильно, т.к. возникает ошибка при удалении: delete (в dll-ке) думает, что удаляется класс, а на самом деле удаляется массив байтов, а из-за скрытой передачи параметров, расположенных до хранящегося в указателе адреса, вознивает ошибка. Т.е. мне ужно начать удалять массив байтов, но тогда не будет вызываться деструктор.

    Что делать?? Помогите!
     
  2. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Pasha 111

    Т.е. получается, что при вызове функции new() в dll-ке, выделяется память под базовый класс, а под SomeValue не выделяется

    Так и должно быть.

    А если у потомка три базовых класса, то они должны знать друг о друге, т.е. конструктор любого из них резервировать память под каждого родителя и потомка?

    А если потомок является продуктом иерархии классов?

    Как только тебе в голову могло придти, что класс-родитель может знать о классах-потомках.



    Копируем его поля (чтобы и указатель на таблицу виртуальных функций скопировался)

    Ты бы еще про указатель на таблицу не виртуальных методов вспомнил.



    Итого: Так на С++ программы не пишут.
     
  3. Pasha 111

    Pasha 111 New Member

    Публикаций:
    0
    Регистрация:
    10 авг 2003
    Сообщения:
    19
    q_q

    Ну дык а что делать-то????

    У меня есть класс CDIALOG, CBUTTON, CEDIT и т.д. Я хочу сделать класс CDIALOG1:
    Код (Text):
    1.  
    2. class CDIALOG1: public CDIALOG
    3. {
    4. public:
    5.     CBUTTON *Button1;
    6.     CBUTTON *Button2;
    7.     CBUTTON *Button3;
    8.     CEDIT *Edit1;
    9.     CEDIT *Edit2;
    10. } *Dialog1;
    11.  




    Но не могу из-за описанной выше проблемы :dntknw:(
     
  4. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Pasha 111

    что делать-то?

    Прочитай букварь по С++.



    не могу из-за описанной выше проблемы

    Не можешь, потому что четкого представления о С++ не имеешь.
     
  5. Pasha 111

    Pasha 111 New Member

    Публикаций:
    0
    Регистрация:
    10 авг 2003
    Сообщения:
    19
    q_q



    Если ты так считаешь - пускай, но помочь-то ведь сам не можешь. Других обс#рать все могут...
     
  6. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Pasha 111



    Лучше переформулируй вопрос. Скажи в двух словах, чего надо сделать, а не вываливай свой код.
     
  7. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.552
    Адрес:
    Russia
    ОФФТОП

    volodya

    да и за ругательства предупреждения надо давать ( правила форума видимо он не читал )



    Ведь даже в топе Тиро против Джоеля .. там нет не единого ругательства .. все культурно общались ..

    Pasha 111

    Используй COM подход ..
     
  8. Pasha 111

    Pasha 111 New Member

    Публикаций:
    0
    Регистрация:
    10 авг 2003
    Сообщения:
    19
    volodya

    Мне нужно, чтобы в DLL-ке был класс, были функции по созданию и удалению, а в exe-шнике можно было бы делать наследование от этого класса.



    TermoSINteZ



    Что ты имеешь ввиду?
     
  9. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Pasha 111

    помочь-то ведь сам не можешь

    Написать за тебя код?

    Рассказать тебе, что необходимо написать конструктор для CDIALOG1 и обеспечить в нем вызов конструктора CDIALOG и конструкторов CBUTTON'ов и CEDIT'ов и то же самое проделать в деструкторе?



    Мне нужно, чтобы в DLL-ке был класс

    Без dll'ки ты можешь создать требуемую иерархию?



    Других обс#рать все могут

    Не суди по себе.
     
  10. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.552
    Адрес:
    Russia
    q_q

    необходимо написать конструктор для CDIALOG1 и обеспечить в нем вызов конструктора CDIALOG и конструкторов CBUTTON'ов и CEDIT'ов и то же самое проделать в деструкторе?



    Это я и хотел сказать ...

    Если ты хочешь чтоб это все вызывалось и ДЛЛ.. то помоему будет глупо в нее вставлять описание классов .. но функции экспортировать все же можешь
     
  11. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Pasha 111



    Ты сам понимаешь, что делаешь ? Что это за опус ?
    Код (Text):
    1.     CMYTEST *a = NULL;
    2.     NewObj((CTEST **)&a);
    Если тебе нужен экземпляр класса CMYTEST, то и New должен вызываться для CMYTEST, а не для предка CTEST. А у тебя же создается именно CTEST, в котором никакого поля SomeValue просто нет.



    С С++ я не в ладах, но в паскале для подобных случаев существует тип class-reference, т.е. ссылка на класс (точнее на тип класса). Если процедура должна создавать объекты разных типов, то ей дополнительно передается ссылка на создаваемый класс и она создает объект именно того класса, какой нужен. ИМХО нечто подобное должно быть и в С++.



    PS знатокам С++: иногда проще дать подсказку и закрыть тему, чем разводить дискуссии, переходящие в "ругательства"
     
  12. Pasha 111

    Pasha 111 New Member

    Публикаций:
    0
    Регистрация:
    10 авг 2003
    Сообщения:
    19
    q_q



    Понимаешь в чём дело, конструктор класса CDIALOG1 всё равно не вызывается: если я создаю объект через "new BYTE[sizeof(CDIALOG1)]", то сам понимаешь, а если писать "new CDIALOG1", то будет ошибка при компиляции, т.к. оператор new захочет положить в создаваемый объект таблицу виртуальных функций, но он их не знает, т.к. они в dll-ке лежат, поэтому будет куча ошибок unresolved external simbol...





    Да. Если всё в одном ехе, то всё работает. А при разносе функций получается то, что я написал выше.



    TermoSINteZ



    Опять не понял (не тупой) :) Ты имеешь ввиду экспортировать функции классов отдельно как самостоятельные функции, а потом самому заполнить все указатели на функции в объекте класса?



    leo



    Я это всё ПРЕКРАСНО понимаю! ПОЧЕМУ у меня не получается я понял ещё до того, как пост создал, а вот как исправить - не знаю.
     
  13. vinnie_pooh

    vinnie_pooh New Member

    Публикаций:
    0
    Регистрация:
    30 июн 2004
    Сообщения:
    98
    leo





    Ну дык и чего постить?



    Pasha 111



    По поводу экспортирования классов, посмотри аттач, может оно.





    [​IMG] 2139391200__Cpp.rar
     
  14. Pasha 111

    Pasha 111 New Member

    Публикаций:
    0
    Регистрация:
    10 авг 2003
    Сообщения:
    19
    vinnie_pooh



    ОНО!!! Спасибо огромное!! Хоть кто-то помог!

    Ещё раз спасибо!