Главная » C++, C++ Builder » Общие вопросы программирования CBuilder (FAQ)

0

Что такое «Compiler Error #1» и как мне от нее избавиться?

Ошибка компилятора №1 (Compiler Error #1) может быть вызвана различными причинами. Как правило, вы сможете избавиться от нее, закрыв CBuilder, а затем запустив вновь и загрузив свой проект при помощи команды File ä Reopen. Если это не поможет, вам придется разобраться в том, что же происходит на самом деле. Перейдите в окно DOS, запустите программу make, задав ей в качестве параметра make-файл вашего проекта; изучите выдаваемые ошибки и исправьте их.

Что такое AnsiString и как его преобразовать в Char *?

AnsiString — это Delphi-совместимые строки, используемые в  CBuilder. Если у вас есть возможность выбора, используйте лучше AnsiString, а не строки STL и массивы символов. Благодаря наличию большого количества весьма достойно оформленных методов использовать их проще, чем просто строки или char *.

Например, вместо того, чтобы использовать чреватые ошибками методы типа strcat и strcpy, вы

можете использовать методы AnsiString, соответственно += и =, как это показано в следующем фрагменте кода:

// Если вам не сделать по другому

char szBuffer[20];

strcpy ( szBuffer, "This is a good test"); strcat ( szBuffer, " and so is this!");

// А лучше сделать так

AnsiString strBuffer;

strBuffer = "This is a good test"; strBuffer += " and so is this!";

В этом примере текст, скопированный в szBuffer, на самом деле переполнит буфер и вызовет появление ошибки, которую будет очень трудно найти. Во втором случае, использовав AnsiString вы будете гарантированы от подобных проблем.

Что же касается второй части вопроса, то для преобразования AnsiString в char * вам надо использовать метод AnsiString c_str. Например:

void func(char *strBuffer); // Прототип некоей функции

AnsiString s = "This is a good test"; func(s.c_str());

Как добавляют элементы в множество?

Для добавления элемента в множество, например, в свойство FontStyle используется оператор <<. Для добавления элемента «полужирный» (bold) в объект-стиль шрифта надо написать следующую строку:

pMyFont->Style << fsBold;

Что означает ошибка «Member function must be called …»?

Ошибка «Member function must be called …» («Должна вызываться функция класса …») случается достаточно часто у программистов, которые привыкли программировать на языке Pascal, и, переключаясь на C++, забывают о скобках. Как правило, эта ошибка означает, что если, например, у вас есть класс Foo, у которого есть метод Bar, то вы пишите:

Foo f; f.Bar;

На самом деле вы должны написать:

Foo f; f.Bar();

В языке Pascal вы можете вызывать функцию или метод, не имеющие аргументов, не используя скобки, а в C++ наличие скобок в вызовах функций строго обязательно. По наличию скобок компилятор определяет, что вы пытаетесь вызвать функцию, а не передать чему-нибудь адрес функции класса. Например:

void func(int x); func(f.Bar);

кардинально отличается от:

func(f.Bar);

В первом примере результат вызова метода Bar передается в функцию. Во втором же — адрес функции класса Bar передается в функцию func в качестве аргумента. Это и вызывает ошибку компилятора.

Что означает ошибка «Structure required»?

Ошибка «Structure required» («Требуется структура») означает, что вы пытаетесь вызвать что-то используя точку (.) вместо стрелки (->). Когда вы используете указатель на структуру или объект, используйте стрелку. Если вы имеете дело с реальным объектом или ссылкой на объект, используйте точку. Например:

Foo *pFoo;

pFoo->Bar(); // ОК

pFoo.Bar(); // Ошибка: нужна стрелка. В этом случае и

//генерируется ошибка, о которой мы говорим.

Foo foo;

foo->Bar(); // Ошибка: нужна точка

foo.Bar(); // ОК

Как исправить ошибку «Linker Error: Failed to create map file»?

Опять же, к возникновению этой ошибки может  привести  множество  причин.  Например недостаток места на диске или нарушение набора файлов пошагового линкера (incremental linker). Для того, чтобы перебороть эту проблему, закройте CBuilder и удалите из директории с вашим проектом все файлы с расширением IL?. Кроме того, в некоторых случаях может помочь выполнение команды Build All (собрать все).

Как добавить ресурсы в проект?

Выберите пункт Add To Project (добавление в проект) и добавьте RC или RES файл, содержащий ресурс, с которым вы хотите работать в вашем проекте. CBuilder автоматически распознает эти файлы и запускает компилятор ресурсов для файла RC, а также встраивает RES файл в ресурсы проекта. Вы также можете использовать макросы USERC и USERES в вашем файле проекта:

USERES("myresources.res"); USERC("myresources.rc");

Можно ли динамически подгрузить библиотеку VCL?

Нет. На данный момент VCL может быть только статически подгружена в программу, фирма Borland клятвенно обещала, что в следующих версиях CBuilder VCL можно будет подгружать динамически.

Как пошагово выполнить исходный код VCL при отладке?

Вы должны собирать программу, используя отладочную версию VCL. В использовании исходного кода VCL есть три стадии. Во-первых, вам надо включить информацию отладчика, с тем чтобы вы могли использовать его. В главном меню выберите пункт Options ä Environment и щелкните на

закладке Library. Щелкните на кнопке Build with debug info (собирать с информацией отладчика). Далее вам надо присоединить версию VCL, предназначенную для отладки. На той же самой странице страничного диалога установите флажок Link with debug VCL (линковать с отладочной версией VCL). И, наконец, вам надо сообщить отладчику, где находится исходный код VCL. Все в том же страничном диалоге щелкните на закладке Preferences и введите путь к исходному коду в поле Path for Source (путь к исходному коду). Разделяйте каждый путь точкой с запятой (;).

Почему отладка столь медленна? Как ее ускорить?

Есть несколько способов для ускорения отладки. Самый действенный, конечно, это добавить оперативной памяти в ваш компьютер. У вас не получится сколько-нибудь серьезной работы с ОЗУ менее 32 Мбайт. Есть и другие способы. Уберите все неиспользуемые или ненужные переменные из окна просмотра. Чем меньше вещей система должна отслеживать, тем быстрее она работает. На время отладки закройте окно Object Inspector. Оно обновляется при каждом шаге, так что это позволит вам чуть-чуть убыстрить процесс.

Компилятор нагло врет! Мои переменные имеют неправильное значение!

Скорее всего, с компилятором все в порядке. Попробуйте выполнить в CBuilder следующий код: int func()

{

int x = 2; int y = 3;

MessageBox(NULL, "Добрались до функции!", "Info", MB_OK);

}

В свое приложение вставьте вызов функции func и пройдитесь по ней по шагам при помощи отладчика. Взгляните на значения переменных x и y в окне просмотра. Скорее всего, они будут равны 0.  Ошибка  компилятора? Нет. Компилятор увидел, что вы их никогда не используете,  и поэтому не рассматривает их. Отладчик знает об их существовании (поскольку они все-таки есть в коде), но также знает и то, что у них нет значений. В результате вы видите 0. Если вы не используете переменные, они не будут иметь значений при отладке. Если  вы  действительно хотите знать их значения, попробуйте следующее:

int func(void)

{

int x = 2; int y = 3;

AnsiString strTemp = " X = " + AnsiString(x) +  " Y = " + AnsiString(y); MessageBox(NULL, strTemp.c_str(), "Info", MB_OK);

}

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

Как получить доступ к принтеру или буферу обмена?

В CBuilder уже определены объекты для принтера и буфера обмена. Лучше использовать их, а не пытаться создавать свои собственные объекты. Для принтера определен объект, называющийся Printer, который вызывается как функция. Например:

// Начать новую страницу в принтере

Printer()->BeginPage();

Точно также и буфер обмена используется как функция Cliboard().

Как поставить выравнивание байтов в CBuilder?

К сожалению, CBuilder игнорирует опции компилятора по выравниванию, заменяя их своими собственными. Следовательно, вы не можете использовать флаги компилятора -a1/2/3.  Вместо этого, используйте директиву pragma pack, как показано ниже:

// Выровнять на один байт

#pragma pack(push,1)

struct  StructureNeedingAligment

{

// Данные структуры

}

// Отключить выравнивание

#pragma pack(pop)

Как принимать перетаскиваемый (drag-and-drop) файл в моей форме?

Как всегда, с улыбкой. На самом деле вам надо обработать метод WM_DROPFILES. Пример: void  TMainForm::WMDropFiles(TWMDropFiles& Msg)

{

char szTemp[256];

int nNumberOfFiles = DragQueryFile(Msg.Drop, 0xFFFFFFFF, szTemp, 256 );

for ( int nFile = 0; nFile < nNumberOfFiles; ++nFile)

{

// Получаем имя перетаскиваемого файла

DragQueryFile( Msg.Drop, nFile, szTemp, 256 );

// Делаем что-то с файлом

ProcessFileName(szTemp);

}

// Заканчиваем процесс

DragFinish(Msg.Drop);

}

Как изменить размер компонента до размера формы?

Самый простой способ — установить свойство компонента Aligment в значение alClient. Это будет автоматически изменять размер компонента в размер формы каждый раз, когда ее размер будет изменяться (включая и первое ее появление).

Если у вас есть какая то особая причина изменять размер компонента во время исполнения (например, вам может понадобиться оставить вокруг него 1 пиксель), вы можете сделать это при помощи свойств компонента Top, Left, Height и Width. Например:

// Увеличиваем поле редактирования до размера формы,

// оставляя вокруг него границу в 2 пикселя

Edit1->Top = 2;

Edit1->Left = 2;

Edit1->Width = Width – 4; Edit1->Height = Height – 4;

Как использовать макрос TRACE в CBuilder?

Для использования макроса TRACE вам надо сделать две вещи. Во-первых, определить символ

__TRACE. Во-вторых, подключить заголовочный файл checks.h. Пример:

#define     TRACE

#include <checks.h> TRACE("Я здесь!\n");

Замечание

Вывод из макроса TRACE осуществляется в файл с названием OutDbg1.TXT, который загружается в редактор файлов. Он не сохраняется автоматически, вам надо сохранить его из редактора. Кроме того, CBuilder не предложит вам сохранить его при закрытии проекта, так что если вы  его открыли, то не забудьте сохранить.

Как отобразить кусочек растрового рисунка?

Используйте  класс TImageList.  У  компонентов  TImageList  есть  метод  Draw,  в  который  можно задать границы; он очень похож на функцию Windows API BitBlt.

Как динамически создать компонент во время исполнения? Очень просто. Используйте оператор new:

*pEdit = new TEdit(this) pEdit->Parent = this; pEdit->Left = 10;

pEdit->Top = 10;

pEdit->Height = 20;

pEdit->Width = 200; pEdit->Visible = TRUE;

Не забудьте  установить свойство parent компонента, а то он не будет отображаться. В примере подразумевается, что «this» — это форма, но это может быть любой компонент, имеющий окно.

Как эмулировать sprintf при работе со строками?

Используйте  класс  String.  Например,  для  того,  чтобы  отформатировать  десятичное  число,  вы должны написать что-то вроде:

// Вместо sprintf(szBuffer, "%d", nNumber); String s = String(nNumber);

// Можно создавать форматированные строки внутри текста

String s = " Hello, world! Мне " + String(nNumber) + "лет от роду";

Источник: Теллес М. – Borland C++ Builder. Библиотека программиста – 1998

По теме:

  • Комментарии