![]() |
|
![]() ![]() ![]() |
|
Mishail |
|
|||
Новичок Профиль Группа: Участник Сообщений: 20 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
Друзья!
Возможно, вопрос излишне прост и корнями уходит в изучение среды VC++, но ни в одном из "учебников" а-ля "VC для чайников" ответа, увы, я так и не нашел ![]() Суть, собствнно, заключается в следующем: в процессе изучения VC++ (MFC) и написания кода, последний (код) постепенно "прибавил" в размере. И, как следствие, работать с кодом стало сложнее. Вот тут то и пришла мысль переместить некоторые функции в отдельный (ые) модуль (которй, кстати, очень удобно было бы потом использовать и в других проектах) - так я поступал в VB. Однако, просто добавить файл и вызвать объявленную в нем функцию (как в VB) не получилось ![]() А теперь вопрос: как правильно создавать/подключать, объявлять подобные модули в VC++ (6.0) и использовать функиции? Например: есть проект test в testDlg.cpp есть функция:
как правильно "перенести" эту функцию в отдельный, например MyFunc.cpp, файл и потом вызывать ее из testDlg.cpp? Может есть мануал какой по этому поводу? Буду очень признателен. С уважением, Михаил. |
|||
|
||||
maxim1000 |
|
||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 1 Всего: 110 |
чтобы функция была доступна в проекте, нужно добавить в него файл, в котором она реализована
т.е. делается файл MyFunc.cpp с содержанием
каждый файл компилируется отдельно (хотя есть разные отступления от этого для оптимизации, но на организацию программы они не влияют) и только на стадии линковки они собираются вместе поэтому для того, чтобы на стадии компиляции не возникло ошибки "функция не найдена", нужно её объявить в том файле, где она используется - просто написать заголовок функции без тела
например, содержимое main.cpp:
-------------------- qqq |
||||||||
|
|||||||||
zkv |
|
||||||||||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 16 Всего: 92 |
Mishail, не знаю как делается в VB, но в С/С++ принято разносить отдельно объявления функций (прототипы), и их реализацию.
Объявления функций или классов помещают в хедеры (файлы с расширением .h), а реализацию в .cpp-файлы. К примеру, мы хотим вынести функцию:
в отдельный файл. Поступаем так: 1. создаем файл-хедер, пусть будет называться myfunc.h, в него нужно поместить прототип нашей функции:
ну и всех остальных, которые нужно сделать интерфейсными (доступными в других файлах). Еще, что очень рекомендуется сделать в хедере - это защитить его от двойного подключения, делается это директивами компилятору. Например можно в начале хидера поставить #pragma once - это проще, нагляднее, но не во всех компиляторах будет работать, лучше использовать более стандартный вариант, его я и использую в этом примере. В общем хедер в целом будет выглядеть так:
2. создаем файл-с реализацией наших функций, пусть будет называться myfunc.cpp. Выглядеть он будет так:
3. подключаем созданный хедер в файл (пусть будет main.cpp), где необходимо использовать функции:
Вот и все. Вдогонку пару советов: - Пока пишешь хедер забудь про директиву using. В cpp-файлах по желанию. - В своем хедере постарайся сократить количество подключаемых хедеров (как то криво выразился, ну если что переспросишь ![]() - Не забывай, что можно создавать свои пространства имен (namespace), их придумали, чтобы сократить вероятность конфликтов имен. Удачи! PS На грамотно заданный вопрос всегда приятно ответить, пусть он даже освящен в каждой второй книге по C++ ![]() |
||||||||||
|
|||||||||||
Mishail |
|
||||||||||
Новичок Профиль Группа: Участник Сообщений: 20 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
Огромное спасибо!!!
![]() Почитал, разобрался и даже получилось. Радость, увы, была недолгой - возникла необходимость использования глобальных перемнных. Узнал о волщебном слове "extern", но потратил еще немного времени, прежде чем уяснил, что объявлять эти глобальные переменные необходимо в каждом файле. На этом мои успехи, пока, заканчиваются. И сегодня, я обращаюсь к Вам с просьбой помочь разобраться с таймером (тайимерами). Итак, в программе я использую таймер следущим образом: testDlg.h
testDlg.cpp
В рамках testDlg.cpp все работает хорошо, но стоит поместить функцию MyFunc в MyFunc.cpp происходит следующее: сначала обнаруживается ошибка 'ID_TIMER_2' : undeclared identifier впринципе логично - добавляем в MyFunc.h #define ID_TIMER_2 200 получаем новую ошибку: error C2660: 'KillTimer' : function does not take 1 parameters О каком недостающем параметре толкует компилятор? И почему когда KillTimer(ID_TIMER_2); находился в рамках test.cpp - подобных вопросов не возникало? Полагаю, что все упирается в т.н. callback - но как правильно описать сие чудо в моем случае, никак разобраться не могу. С уважением, Михаил. P.S.
Спасибо, и впредь буду стараться ![]() И еще, в процессе поиска истины среди таймеров, родился еще вопрос: Допустим, с таймерами все получилось ![]() Пример (алгоритм - который пока мне пришел в голову): test.ini
теперь как это реализовать в программе: посредством условий?
или может есть более рациональные варианты? или этот вопрос лучше выделить в отдельную тему? ![]() |
||||||||||
|
|||||||||||
zkv |
|
||||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 16 Всего: 92 |
это не может работать. Смотри, в эту функцию скрыто передается параметр this - указатель на объект класса (если она не статическая у тебя):
и компилятор интерпретирует запись KillTimer(ID_TIMER_1); как this->KillTimer(ID_TIMER_1); Под KillTimer в этом случае подразумевается CWnd::KillTimer(int) - она приимает 1 параметр В первом же случае компилятор считает что ты работаешь с WinAPI-функцией ::KillTimer(HWND,int) - тут он ищет 2 параметра. что-то я не понял. Куда не подключать? Если компилировать/не компилировать - то директивами компилятору #ifndef/#endif и пр. Если другое, то уточняй Добавлено через 1 минуту и 6 секунд если конечно ты собственную функцию KillTimer не написал ![]() |
||||
|
|||||
Прохожий |
|
||||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 79 Регистрация: 12.1.2007 Репутация: 1 Всего: 1 |
Лучше по возможности избегать ВСЕМИ СИЛАМИ глобальных переменных. Есть большое количество способов передать данные и без них.
Но если и возникла необходимость в глобальных переменных и без них нельзя обойтись то "extern" здесь не причём просто это еcли есть в функции переменная с такимже именем как и ну допустим глобальная и необходимо обратиться именно к внешней переменной то указываем, при помощи "extern" что имеется в виду именно та переменная. Пример
поместите вашу переменную в заголовочный файл который виден во всех частях проги где его надо видеть и всё. Например если поместить её в stdafx.h то видна такая переменная во всей программе. Ну ваащето это не есть правильно. ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ НАДО ИЗБЕГАТЬ! Это сообщение отредактировал(а) Прохожий - 30.7.2007, 12:10 |
||||||
|
|||||||
zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 16 Всего: 92 |
||||
|
||||
Прохожий |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 79 Регистрация: 12.1.2007 Репутация: 1 Всего: 1 |
Ну дак я и сам если удобнее пользуюсь глобальными переменными. Но кода не совсем понимаешь где и что обьявлять. То стоит и поберечся. Пока не освоишся с областями видимости.
![]() |
|||
|
||||
maxim1000 |
|
||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 1 Всего: 110 |
extern тут очень даже при чём
если поместить строку
в заголовочный файл, то в каждом компилируемом файле, который подключает этот header, будет сохдана переменная x, в лучшем случае это приведёт к ошибке линковки часто используемая практика такая: в одном из cpp-файлов создаём переменную:
а во всех остальных просто говорим, что она находится в другом месте:
таким образом при компиляции файла с "int x" всё будет, как обычно, а при компиляции остальных вместо x будут поставлены ссылки, которые свяжутся с этой же переменной на жтапе линковки Добавлено через 4 минуты и 36 секунд
именно для этого и используются хэдеры т.е. через некоторое время накапливается немало объявлений функций, глобальных переменных, возможно, каких-то define'ов и т.д., которые нужно писать в нескольких файлах, их просто выделяют в отдельный файл с расширением h и пишут
-------------------- qqq |
||||||||||
|
|||||||||||
Mishail |
|
||||
Новичок Профиль Группа: Участник Сообщений: 20 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
Спасибо всем откликнувшимся!
Читал - много думал ![]() Раздобыл (на всякий случай) труд часто цитируемого на форуме Дж.Рихтера - осилил "ВВЕДЕНИЕ" и тщательно изучил содержание... вернулся к "Самоучителю"... Поискал в сети... но мой воз, как говорится: "и ныне там" ![]() Перечитал свое предыдущее сообщение и понял что допустил ошибку - слишком много вопросов и ненужной лирики, отсюда итог: 1. мои предположения по поводу правильности использования "extern" - оправдались и это радует ![]() 2. Однако, как управлять таймером за рамками *.cpp - файла в котором он установлен я, увы, так и не понял. Посему, позвольте еще раз, обратиться к вам с, теперь (как мне кажется) уже вполне конкретным вопросом: Каким образом можно уничтожить таймер из функции или за пределами *.cpp - файла в котором он установлен. Например: есть проект в нем имеются: test.cpp, testDlg.cpp, MyFunc.cpp. в testDlg.cpp имеется
теперь, собственно, как в myFunc1 и в myFunc2 уничтожить ID_TIMER_1 и ID_TIMER_2? Опять, чувствую что все это как-то незамысловато делается. Но все мои попытки приводили либо к ошибкам компиляции либо к "неубиваемости" таймера ![]() Если это и впрямь - просто, буду очень признателен за несколько строчек кода, вроде: MyFunc.cpp
С уважением, Михаил. |
||||
|
|||||
zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 16 Всего: 92 |
Mishail, тут все просто, чтобы убить таймер, надо иметь два параметра - ID таймера, и окно, к которому он привязан. Можно конечно передавать их в эти функции, но такое решение по-моему неправильное, с точки зрения проектирования, работы с таймером следует ограничивать в классе окна, в котором он создан.
|
|||
|
||||
Mishail |
|
||||||
Новичок Профиль Группа: Участник Сообщений: 20 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
СПАСИБО!!!
Вот уж действительно - все оказалось просто. А самое главное работает именно так как и было задуманно ![]() Еще раз спасибо за разъяснения и пример. Теперь же хотелось бы вернуться к частично ранее затронутому вопросу - возможность управления функциями пользователем. Не знаю верно ли я сформулировал вопрос, поэтому переложу его на пример. Итак, допустим имеется код следующего вида:
Мы имеем: пограмму, которая по нажатию на кнопку последовательно выдаст пользователю 5 (в данном случае) сообщений. Замысел "управления" заключается в том, чтобы дать пользователю возможность "выбирать" какие из этих сообщений он хотел бы видеть. Например посредством ini-файла. Мне это, пока представляется возможным лишь путем добавления условий:
предположем что ini-файл перед чтением вылядит следующим образом: test.ini
таким образом из 5-ти сообщений пользователь прочтет лишь выбранные им 2-ое и 3-е. В общих чертах - примерно так. Вариант с условиями - работает. Но учитывая, по сути безграничные, возможности Си - хотелось бы спросить - может есть в Си какая-нибудь "фишка" вроде (назовем ее так) "динамического заполнения функции содержимым в соответствии с выбором пользователя" (во написал-то - прям как тема для диссертаци). Другими словами - можно ли избавиться от массы, по сути ненужных, условий (в данном примере MassegeBox-ов - пять, в принципе терпимо - можно обойтись и условиями, а если их будет под сотню!!! Сколько "лишних" проверок). С уважением, Михаил. |
||||||
|
|||||||
zkv |
|
|||
![]() ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 2133 Регистрация: 23.7.2006 Где: Санкт-Петербург Репутация: 16 Всего: 92 |
Mishail, вопрос слишком абстрактный, а средства языка и MFC слишком обширны, чтобы дать конкретный ответ.
почему ненужных? А откуда мы тогда будем брать информацию? В том или ином виде нам все равно нужно получить, а затем применить информацию о том, какие функции использовать, а какие нет. Притом, по моему, главное не избежать проверок вовсе, а избежать их повторения. В твоем случае, возможно вполне подойдет даже приведенный тобой вариант решения задачи. Чтобы посоветовать что то еще, надо знать условия конкретной задачи. Часто решения для таких, локальных вопросов мы получаем на этапе продумывания более общих вещей. Взять хрестоматийный пример применения механизма наследования и полиморфизма - "фигуры", существует базовый класс - "Фигура", и его наследники - "Круг", "Квадрат" и пр. Например мы хотим сохранять/загружать список фигур в/из файл(а). Производится одна единственная проверка на этапе загрузки/сохранения, а дальше используется единый набор интерфейсных методов. Надо упомянуть механизм сериализации MFC, который вообще освобождает нас от кучи подробностей этого процесса. Вообщем помочь могут многие средства: механизм ООП, сериализация, ассоциативные контейнеры типа std::map, указатели на функции (C-стиль), ну и никто не отменял простые if/else, switch/case и пр. |
|||
|
||||
likehood |
|
|||
666 ![]() ![]() Профиль Группа: Участник Сообщений: 536 Регистрация: 21.12.2005 Репутация: нет Всего: 24 |
Если у всех функций один прототип, можно создать массив указателей на эти функции, а в OnButton1 в цикле проверять содержимое ini файла и вызывать нужные функции по указателю.
|
|||
|
||||
Ln78 |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 274 Регистрация: 25.11.2006 Репутация: 1 Всего: 15 |
Кроме использования ini-файла можно сделать вызов диалога, в котором будет находиться список с чекбоксами, класс CCheckListBox. А выбор пользователя, используя сериализацию, сохранять в файл. Этим файлам можно придумать своё расширение и ассоциировать их с приложением (аналогия как doc-файлы обычно ассоциируются с Word-ом).
Ну и я бы тоже постарался использовать массивы, там где можно применить циклы, иногда может быть удобнее искусственно приводить к одному прототипу, например, один аргумент - указатель на void. Это сообщение отредактировал(а) Ln78 - 3.8.2007, 07:40 |
|||
|
||||
![]() ![]() ![]() |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |