Практический переход с VB v.6.0 на C++ Builder v.6.0 (24.10.2013). Печать
2013 - Октябрь
24.10.2013 19:12
Save & Share

Давайте забудем о том, что на текущий момент это достаточно старые языки: одному 15 лет, другому 11. Здесь важен только момент, что существуют 3 типа языков программирования (по распространению): VB-подобные, C-подобные и все остальные. Всю жизнь программировал на VB-подобных языках (например, VB6, LotusScript); и даже когда я менял работу - старался находить либо такой же язык, либо такой же его тип. А теперь судьба продиктовала изучение C++ Builder.

Проведем аналогию: всю жизнь человек работал в Windows - и тут его пересаживают на Linux. Ломка, неприязнь, отторжение. При условии, что Linux лучше Windows во всем, кроме игр и распространенности ПО. Может быть, освоив C++, я смогу перенять его синтаксис и доказать самому себе, что он лучше.

Читать код на C++ и писать его - совершенно разные вещи. Прочитать код может любой, и сделать аналогию на своем языке. А вот когда я столкнулся именно с написанием агентов для платформы IBM Lotus Domino (на Java, C-подобный язык) - вот тогда я прочувствовал на себе все "прелести" языка C. А если учесть ещё отсутствие компилятора на той платформе - я не буду писать, сколько страниц мата у меня вырвалось в процессе написания аналогии с другими агентами.

Теперь же ситуация сложнее. Язык дается C-подобный, а никаких аналогий нет. Программа пишется с нуля, и придется пройти весь путь ломки и освоения C++ Builder. Я читаю книгу Ю.П. Федоренко "Алгоритмы и программы на C++ Builder" (2010), она сильно помогает в этом процессе.

Первая проблема: интерфейс. Наиболее осел в голове Visual Basic v.6.0, поэтому буду проводить аналогии с ним:
- привык к тому, что окна "Project" (список объектов проекта), "Properties" (список свойств объекта проекта) находятся с правой стороны (аналогичные окна "Object Tree View" и "Object Inspector" находятся слева). Для решения проблемы достаточно переместить эти окна направо (дополнительно отыскав и прихватив окно "Project Manager", отвечающий за список файлов с исходным кодом), далее - нажать кнопку правее Help "Save Current Desktop". Кнопка рядом помогает переключать профили сохраненных положений окон (профили сохраняются в самом языке, а не в проекте).
Здесь видится, что окно VB6 "Project" в C++ Builder разделено на 2: "Object Tree View" и "Project Manager". Это сделано ради того, чтобы в "Project Manager" можно было подгружать несколько проектов в одно окно среды программирования. По желанию, можно запустить 2 среды отдельно, и в каждой из них открыть свой проект;
- присутствует кнопка "Play" для компиляции и запуска EXE-файла проекта, но в C++ впервые заметил, что отсутствует кнопка "Stop". Нелогично: приходится выключать проект комбинацией клавиш "Ctrl+F2" (при фокусе на среде программирования) и наблюдать, чтобы EXE-файл исчез из трея. Однако, если форма в трее не будет отображаться - можно наблюдать за зажиганием кнопки "Play";
- "пустота" в среде программирования, через которые можно запускать элементы рабочего стола, не убирается. Ее назначение мне неясно.

Вторая проблема: логика среды программирования. Мне данные изменения кажутся нечеловечными, т.к. направлены против удобства программирования:
- нелогичность регистра переменных/функций/объектов проекта, способа их написания и инициализации. Если в VB6 написание mSGBoX и MsgBox дают верный результат (среда сама приводит регистр в нормальное состояние) - то в C++ требуется точное соблюдение регистра. Если в VB6 "MsgBox 444" отработает нормально, что MessageBox в C++ заставляет вводить все параметры для функции: hWnd, lpText, lpCaption, uType. Если в VB6 после провозглашения переменной она имеет "нулевое" значение вида "", 0, NULL - то в C++ ей присваивается произвольная информация. Поэтому в книге написано: всегда пишите "int VB=6", а не "int VB", иначе будут трудно обнаруживаемые ошибки. Если в VB6 при написании функции "func" прощалось отсутствие скобок (функция выполнялась) - то в C++ выполнение "func" без скобок мало того, не выполнит тело функции, так ещё и не будет считаться ошибкой компиляции.
Смысл этих неудобств мне неясен. Не будет нормальный человек создавать функции с именами msGBOx и MSgbox, чтобы самому потом в них путаться. Также при написании того же MsgBox или иных функций опускание параметров дает уменьшение количества кода и не приходится заморачиваться с теми параметрами функции, которые тебе не нужны;
- пусть я получаю свойства и методы объекта "Button". При написании "Button1->" получаю их список, но список достигает гигантского значения из-за неких функций, похожих на конструкторы и деструкторы. Причем, если Button1 имеет 2 метода OnClick и OnDragDrop - это не значит, что они будут наверху списка; придется либо искать в этом огромном списке нужный метод, либо по-памяти писать вручную;
- 2^2 не будет равно 4 в C++: нужно использовать функцию Pow.

Что мне объяснили на форуме:
- про "int VB": так как автоматически инициализация не происходит - работа программы ускоряется. Но: это идет вразрез с книгой, и прирост производительности здесь не будет ощутимым. Опять же неясно: почему компилятор молчит; почему его нельзя настроить, чтобы он матерился на неинициализированные переменные?
- 2^2 не равно 4: "^" - это XOR. А чтоб работал как степень - к исполняемому файлу только для поддержки этой операции пришлось бы приковывать библиотеку с ее реализацией. Но: человек учился в школе и вузе, его учили, что "^" - это степень. Вопрос решен, но опять не в пользу здравого смысла;
- ответ мне о регистре функций/переменных: "это для красоты, в VB идентификаторы регистронезависимые. в С++ (и большинстве других) идентификаторы foo и Foo - разные идентификаторы". И опять идет упор на то, что "компилятору нравится вот так-вот", а VB6 для упрощения работы производит исправление регистра названий. Ну кому взбредет в голову сделать функции foo и Foo в 1 проекте? Будет Foo и Foo1 в лучшем случае. И если вдруг (о нет!) при подключении какого-то модуля получится "foo + Foo" - об этом VB6 непременно сообщит! Одинаковых названий быть не должно, в каком бы регистре они ни были.

Третья проблема: синтаксис. Когда читаешь код - все нормально, но когда начинаешь писать - сталкиваешься с новыми вещами:
- нужно привыкнуть к точкам с запятой в конце строки. Идут годы - а вопрос точек с запятой остается открытым: почему бы не сделать как в VB-подобных языках, который понимает перевод строки;
- в VB6 тип переменной String не соответствует типу Char C++. Char - это 1 символ, однако с его помощью можно работать и со строками. А вот AnsiString - полноценная строка (причем, если Char в C++ выделяется жирным цветом как тип данных, то AnsiString - нет). Пока испытываю проблемы с перетипированием AnsiString <-> Char и привыкаю к прочим перетипированиям, вроде StrToFloat. К перетипированию в C++ тоже отношусь негативно: в VB6 в большинстве случаев перетипирование происходит автоматически;
- композиция C++ "Try/Catch" является заменой VB6 "OnError Goto ErrorHandler"/ErrorHandler: MsgBox ...". Однако правильное ее использование на текущий момент не изучено: казалось бы, все написано верно (с запланированной ошибкой "Type mismatch") - ошибка выходит на экран, а в Catch функции не попадаю (и даже в Catch Project1.cpp не попадаю);
- проект представляет собой большое количество файлов (как в любом C-подобном языке): интерфейс формы и ее код лежат в разных файлах - терпимо. Но всякие Unit1.~cpp, Unit1.~ddp, Unit1.~h не играют смысловой нагрузки - и при этом пересоздаются при каждом сохранении проекта. Верю, что дело связано с ускорением работы (кешированием). Но в целом о компиляции: программа на C++ с одной лишь кнопкой компилируется с такой же скоростью, что программа на VB6 с кучей форм и написанного кода.

Я описал только первые 2 дня плотного знакомства с языком: читать, писать, исправлять ошибки, привыкать. И если те, кто изначально учились писать на обычном C (C-подобном языке) - не замечают тех вещей, о которых я пишу здесь; то человек, меняющий тип языка - заметит и не только написанное.

Итог: процитирую одного из пользователей форума: "вы вступили на новую территорию. Придется изучить законы и им подчиняться. Так уж устроено". Придется. 

Hello, world!

(добавлено 25.10.2013): ещё негативные выводы по C++:
- цитирование из книги Федоренко ужасов компилятора C++: "предположим, вы правильно оценили диапазон изменения вашей целочисленной переменной и подобрали ей соответствующий тип данных. Но на определённом шаге выполнения программы, из-за каких-то ошибок, значение переменной выходит за границу назначенного ей типа. В этом случае в других языках программирования заботливый компилятор (или интерпретатор) остановит программу и подсветкой выделит ту переменную, в которой произошло, например, переполнение. Вы, конечно, огорчитесь, однако легко устраните ошибку. Но в C++ Builder (и в C++) нет таких (и многих других) проверок на соответствие границам числовых типов. Именно поэтому программы, написанные на этом языке, имеют наибольшее быстродействие, ведь в них время на эти проверки не расходуется. Поэтому программист должен взять на себя всю ответственность за такой контроль. Для повышения надёжности работы программ следует контролировать интервал изменения всех, или, по крайней мере, самых основных переменных.
В противном же случае, когда с запасом выбрать тип данных, не расставлять капканы для отлова возможных ошибок, то в упомянутой выше ситуации останова программы не произойдёт, и в итоге будут ошибочные результаты вычислений. Это особенно опасно в случаях, когда такие результаты оказываются правдоподобными, поскольку они приводят к ложным выводам, ошибочность которых трудно определяется". Простой вопрос повторяется: почему компилятор пинает балду, а программист должен запоминать размеры всех переменных (и мало того, самостоятельно отлавливать ошибку типа Overflow);
- та же песня: "с целью повышения быстродействия программ Builder по умолчанию не контролирует выход номера элемента массива за его границы. Поэтому если в ходе работы программы попытаться обратиться к элементу массива, индекс которого находится за границами, указанными при определении массива (меньше 0 или больше n-1), то Builder не сообщит о допущенной ошибке: вернёт какие-то значения, хранящиеся на этот момент в соответствующих ячейках памяти;
- та же песня, но под другим ракурсом: "вся ответственность за появление указанных ошибок полностью лежит на разработчике программ". Конечно, компилятор же не отслеживает ничего. Крутись как хочешь. Однако, в свойствах проекта есть CodeGuard (подробно настраивается в "Tools -> CodeGuard Configuration") - некоторые ошибки удастся отловить (однако в int число 700000000 продолжает помещаться "без ошибки");
- свойство формы BorderStyle влияет не на рамку формы, как можно подумать, а на группу элементов "свернуть-развернуть-закрыть". Мало того, визуально в среде программирования форма не изменяется; должный вид она приобретает только у скомпилированного EXE-файла. Причем при "BorderStyle = sNone" и всех "BorderIcons = True" - все равно форма будет без группы компонентов;
- в C++ приходится писать в заголовках файлов прототипы функций; в VB6 же без разницы, где находится вызываемая функция (выше или ниже строки вызова);
- о плюсах языка. Разнообразие элементов в панели компонентов (например, простая кнопка с BMP-рисунком). Диаграммы разных видов (не требуется возиться с объектом Excel при построении графиков). Встроенные OpenDialog и его производные (не требуется подключения дополнительных компонентов или OCX-файлов). Существует возможность создать профиль настроек для новых проектов. Слово typedef позволяет объявлять любые пользовательские типы данных. Если в C требовалось писать "int ttt(void)", то теперь можно написать просто "ttt()" (по умолчанию функция возвращает int). Есть возможность создавать функции, принимающие произвольное количество параметров.

Вывод пока такой: у C++ функционал более широкий, чем у VB6. Но части синтаксиса и нереальная капризность компилятора, требующая дополнительных внимания и памяти и увеличивающая вероятность скрытых ошибок, - позволяет предположить: даже если на работе меня будут заставлять писать на C++ - домашние программы все равно буду писать на VB-подобных языках. Причина проста: я хочу, чтобы компилятор был моим защитником от ошибок, и написание кода облегчалось разными мелочами вроде автоматического исправления регистра переменных/функций.
Сформировалась аналогия перехода с VB6 на C++: с комфортабельного автомобиля с автоматической коробкой передач и кондиционером - на быстрый автомобиль с тесным салоном, ручной коробкой и ручным веером. У последнего предел скорости 360км/ч, но нужно иметь точность и сноровку вождения такого выкидыша автопрома: иначе на такой скорости просто разобьешься (да и сам скоростной предел может пригодиться 0-1 раз в жизни).

О книгах. Книга Федоренко рассказывает несколько играючи о языке C++, на учебных задачах и примерах. Рассматриваемые им примеры имеют совершенно нечитабельные названия переменных; но при этом показывают именно разнообразие способов записи кода: переменных, функций и т.д.
Книга Стенли Липпмана, Жози Лажойе "Язык программирования C++. Полное руководство" (2011) - сухая, жестко разграниченная, но с максимумом информации. Одно описание перегрузки функций и операторов чего стоит. "Полное руководство" (читай "полный подробный справочник") - нужно применять только после освоения книги Федоренко, когда появятся виртуозность работы с кодом и такое обширно-расплывчатое представление о разных сущностях C++.
Важный момент: читать все от начала и до конца. Порой даже скучно; но читаешь-читаешь, а потом вдруг "чпок" где-то посередине: "ага, ах вот оно как можно".

(добавлено 28.10.2013): теперь идет череда положительных моментов по C++:
- удобно перегружать функции и использовать их шаблоны, грамотно рассказано про указатели и примеры их использования (однако стиль обзывания переменных в книге - хоть караул кричи);
- разнообразие элементов в панели компонентов продолжает вносить свой вклад, вроде очень быстрого создания графических кнопок, меню. Правда, не смог найти встроенный Image Editor;
- объект типа TStringList упрощает работу с текстовыми файлами, в том числе бинарными;
- инструмент Tab Order, при нормальных названиях объектов, позволяет быстро настроить необходимый их порядок.

(добавлено 12.12.2013): все-таки привычка - сильная штука. Мне придется изучить этот язык, но делаю я это через не хочу и через не могу. Если мне когда-нибудь придется сменить работу - я буду выбирать именно VB-подобные языки, вроде LotusScript. Однако стоит отметить факт: PHP и CVI - C-подобные языки, но они у меня хорошо пошли в процессе изучения несколько лет назад. C++ - устаревший язык, CVI и PHP - современные. Может, современность добавила удобства в изучении C-подобных языков "нового поколения".

(добавлено 01.02.2014): к причудам этого языка привыкнуть возможно, но трудно. Одни глобальные элементы за пределами формы чего стоят. В целом ситуация следующая: на работе заставляют использовать - буду использовать. Но домашние программы буду писать на VB-подобных языках. Несмотря на то, что преимущества C++ начинают чувствоваться. Например, помещение файла в одну строку - быстрая операция; и по этой строке перемещаться быстрее, чем по массиву VB. Это диктует необходимость в скорости, когда речь идет о миллисекундах; в домашних программах, как правило, такого не требуется.

(добавлено 31.03.2014): речь тут не о языке пойдет, а о стиле написания программ. Каждый язык видоизменяет этот стиль, добавляя в него что-то свое, что ранее не было известно. В случае с C++: справочники по нему позволили перейти к следующим положительным вещам:
- грамотное использование указателей и динамических переменных;
- грамотные названия для функций и переменных: с префиксом перед названием, показывающим тип переменной или возвращаемого значения функции. К примеру, int iTemp, double dTemp, String sTemp, AnsiString asTemp, bool bTemp, bool bRandom_Function(char cInput).

(добавлено 07.08.2014): задрал меня этот Builder. Работа с одним из компонентов Windows на VB6 укладывается в 10 строчек, а в BCB6 - в 150 строк и 2 include. Подключение и вызов библиотеки ActiveX в VB6 занимает 3 строчки, в BCB6 с этим голову сломать можно (разнородные ошибки компиляции). Подключение обычной библиотеки можно наблюдать на этом примере (писать typedef и __stdcall для каждой функции, перетипирование в MYPROC и т.д.). В итоге я на VB6 написал за месяц то, что на BCB6 писал бы полгода, постоянно спотыкаясь. Также чувствуется долгая компиляция больших программ. Однако у Builder есть один плюс: много встроенных компонентов по умолчанию (вроде Chart, ApplicationEvents).

Обновлено ( 13.05.2022 17:43 )