一、引言
C++ Buidler和Dephi同為RAD的典範,它使得快速、高效、方便地開發程式成為可能。但是在使用C++ Buidler的過程中發現,不是僅僅熟悉C++ Buidler的VCL組件就能順利地完成程式的編寫,還需要注意一些容易忽視的細節。本文列舉了一些遇到的問題,並提供解決辦法,以供參考借鑒。
二、具體問題及解決辦法
1.使用SQL語句操作資料庫時,如果語句中出現了變數,同一變數不能進行重複使用
如:需訪問資料表T1和T2中符合條件T1.T1_F1="01"及T2.T2_F1="01"的紀錄,按照常規思維,只需在SQL語句中設定一個變數p,分別用來判斷T1.T1_F1和T2.T2_F1的值是否為"01",BCB語句如下: if(ADOQuery1->Active)
{ ADOQuery1->Close();
ADOQuery1->SQL->Clear(); }
ADOQuery1->SQL->Text="SELECT * FROM T1, T2 WHERE T1.T1_F1=:p AND T2.T2_F1=:p";
ADOQuery1->Parameters->ParamValues["p"]="01";
ADOQuery1->Open();
但是在運行這段代碼後,查詢的結果為空白。(在訪問Access2003過程中得到證實)通過追蹤SQL語句中的變數p,發現第二次調用p時,BCB沒有對p賦值,即p為NULL;所以得不到期待的查詢結果。正確的參數設定應該為: ADOQuery1->SQL->Text="SELECT * FROM T1, T2 WHERE T1.T1_F1=:p1 AND T2.T2_F1=:p2";
ADOQuery1->Parameters->ParamValues["p1"]="01";
ADOQuery1->Parameters->ParamValues["p2"]="01";
從上面可以看出,BCB對SQL語句中出現的每個賦值變數只使用一次。即使需要在SQL語句中對出現兩次的變數賦予相同的值,也要申請兩個變數,分別賦值。
2. goto語句的使用
在C++ Builder的goto語句中,如果保留字goto與目標標識之間有本地變數的初始化語句: goto EndMark;// EndMark為目標標識
int a=1;
……
EndMark:;
則運行goto語句時會報錯,這給goto語句的使用帶來不便,但如果在goto與目標標識之間加上一對花括弧,則可順利運行: goto EndMark;
{ int a=1;
…… }
EndMark:;
C++ Builder將{……}內的變數初始化理解為局部變數的初始化,局部變數的初始化不會對{ }外面的語句有影響。所以適當地使用花括弧,就可以消除C++ Builder對goto語句使用的限制。
3. 動態建立視窗帶來的影響
動態建立視窗的好處是在不需要該視窗時可以用delete命令釋放記憶體。但是由於視窗是在記憶體中完成建立和釋放,也存在一些問題。如:在建立的Application中建立Form1、Form2和Form3,Form1上設有Button1和Edit1、Memo1,Form2上設有Button21、Button22和Edit2、Memo2,Form3上設有Button3和Edit3、Memo3.Form1->Button1的Click事件中動態建立視窗Form2,並設定Form2->Button21的Click事件顯示視窗Form3,且Form1、Form2、Form3分別各有一個Edit1和Memo1,現在試圖通過點擊Form3上的Button3按鈕分別將Edit3和Memo3中的文字賦給Form2的Edit2和Memo2構件,再通過點擊Form2上的Button22按鈕把Edit2和Memo2中的文字賦給Form1.
Form1中的函數: void __fastcall TForm1::Button1Click(TObject *Sender)
{ TForm2 * Form2_N=new TForm2(Form1);
Form2_N ->ShowModal();
delete Form2_N; }
Form2_N中的函數 void __fastcall TForm2_N::Button21Click(TObject *Sender)
{ Form3->ShowModal();
}
void __fastcall TForm2_N::Button22Click(TObject *Sender)
{ Form1->Edit1->Text=Form2->Edit2->Text;
Form1->Memo1->Text=Form2->Memo2->Text;
this->Close(); }
Form3中的函數: void __fastcall TForm3::Button3Click(TObject *Sender)
{ Form2->Edit2->Text=Form3->Edit3->Text;
Form2->Memo2->Text=Form3->Memo3->Text;
this->Close(); }
測試中發現,Form3上Edit3和Memo3中的文字不能賦值到Form2_N的Edit2和Memo2中,但Form2_N上Edit2和Memo2中的文字可以賦到Form1上的Edit1和Memo1中。
如果修改Form1中Button1的Click事件的執行語句,將建立Form2_N改為建立Form2,並將在其它地方出現的Form2_N改為Form2: void __fastcall TForm1::Button1Click(TObject *Sender)
{ Form2=new TForm2(Form1);
Form2->ShowModal();
delete Form2; }
這樣,Form3上Edit3和Memo3中的文字就能賦給Form2的Edit2和Memo2了。
建立屬於TForm2類的視窗Form2_N和Form2時,不同點在於,在建立Form2_N時(點擊Button1時),需要向系統申請記憶體建立。Form2_N的建立過程 “TForm2 * Form2_N=new TForm2(Form1);”中包含了定義新的表單類Form2_N和對其進行初始化兩個動作, Form2_N在定義過程中申請了記憶體空間;而Form2是在Design-Time定義的表單,在程式初始化時就完成了申請記憶體空間的動作。兩種表單申請記憶體的時間先後影響了它們對所傳遞數值的接受。
三、結語
C++ Builder中有些隱含的使用限制還不太直觀,像動態視窗的建立會給視窗之間的變數賦值帶來不便,而在Delphi中建立動態視窗(Form1:=TForm1.Create(self);)就不存在這樣的問題。因此如果遇到在C++ Builder中的不能用一般方法解決的一些問題時,還需要進一步熟悉C++ Builder,細緻分析,多進行嘗試摸索解決,積累了一些經驗,就可以提高編碼效率。