如何将C++程序转为Pascal语法
原文出处: by Paul Fulford of Komodo Software
翻译:http://delphi.ktop.com.tw
将C++ 转为 Pascal/Delphi
==============================
目录
概论
数据型态
关键词
叙述结尾
变量宣告
字符串
数组
数值的指定与比较
常数宣告
函数与程序
with ...do
叙述
批注
流程控制
对象导向结构
Containers
例外处理
资料流(Streaming)
项目档的设计
如何转换
结论
=================================
概论:
这篇文章的目的是让您了解C++与Object Pascal的不同
也让您能够有能力将C++转为Object Pascal(以下称为OP)
=================================
数据型态
这一章可学到如何将 C++ 的数据型态 转成 OP 的数据型态.
变量宣告时可参考下列对照表
C++ OP 大小 (bytes) 值范围
==================================================================
char ---- 1 -128 to 127
---- char 1 1 ASCII character
int integer 2 -32,768 to 32,767
short ---- 2 -32,768 to 32,767
---- shortint 1 -128 to 127
long longint 4 -2,147,483,647 to 2,147,483,647
unsigned char byte 1 0 to 255
unsigned int word 2 0 to 65,535
unsigned short word 2 0 to 65,535
unsigned long ---- 4 0 to 4,294,967,295
float single 4 3.4E-38 TO 3.4E+38
doubledo
uble 8 1.7E-308 TO 1.7E+308
longdo
uble extended 10 3.4E-4932 TO 3.4E+4932
---- comp 8 1.7E-308 TO 1.7E+308
---- real (for backwards compatibility only -- usedo
uble)
void pointer 8 n/a -- an untyped pointer
---- boolean 1 True or False
(C++ may soon have a boolean type)
String ---- a C++ standard object
---- string an array of up to 255 ASCII characters
---- PChar pointer to a null-terminated string
=================================================================
=================================
关键词
C++ 有 59 个关键词, OP 有 60 个关键词. Thisdo
es not include the many vendor
C++ 大小写有分 OP 大小写不分
C++的关键词
asm auto break case catch cdecl char class const const_cast continue
default deletedo
do
uble dynamic_cast else
enum extern far float for
friend goto huge if inline interrupt int near new operator pascal private
protected public register reinterpret_cast return short signed sizeof
static static_cast struct switch template this throw try typedef typeid
union unsigned virtual void volatile wchar_t while
OP的关键词
and as asm array begin
case class const constructor destructor divdo
downto else
end except exports file finally for function goto if implementation
in inherited inline initialization interface is label library mod nil not
object of or packed procedure program property raise record repeat set shl
shr string then
to try type unit until uses var while with xor
=================================
叙述结尾
C++叙述结尾
大部份的叙述都用 ;
号结尾
有一些例外如:
#include
#define MAXNAMELENGTH 35
OP叙述结尾
所有的叙述都用 ;
号结尾
=================================
变量宣告
C++变量宣告
变量名称只有前32个字有效
变量名称宣告可在程序的任何地方宣告(当然,宣告后才可用)
// ... 如在程序中宣告
{
char i;
for (i=0;i<10;i++)
{
char sName[10];
// 在区块中也可宣告变量
int iCount, iLoop, iValToReach;
double dMaxLoan, dTotal;
float fMaxRate = 123.875;
}
}
OP变量宣告
变量名称只有前63个字有效
变量名称要宣告在var之后,且要在function或procedure开始时宣告
不可在区块内宣告变量
如:
function PayBack_d(var dAmount:do
uble):do
uble;
var
iCount, iLoop, iValToReach: integer;
dMaxLoan, dTotal, dMaxRate:do
uble;
begin
dMaxRate := 123.875;
{...}
=================================
字符串
C++字符串
在C++现在也有了字符串对象,但并不和以"/0"结束的char相容.
大部份的字符串就是char数组,可以无限长度.
下面是一些char数组宣告的例子:
char sName[26];
// 25 个chars长
char psDemo[] = "Hello, there!";
char * psDemo = new char[26];
对字符串变量最常做的事就是strcpy与strcat
您要确定strcat或strcpy后的长度够不够存放.
以下是strcpy/strcat的例子.
class Ticker
{
...
public:
char sBuf[10],
sLatestTrade[TRADELENGTHBUF],
saTradeRecords[50] [TRADELENGTHBUF];
...
void OptnFormat2_v(unsigned long &
ulQuantity,
CompanyC * poC,
int &
iSeries);
...
};
...
void TickerC::OptnFormat2_v(unsigned long &
ulQuantity,
CompanyC * poC,
int &
iSeries)
{
ultoa(ulQuantity, sBuf, 10);
strcpy(sLatestTrade, sBuf);
AddMosToString_v(sLatestTrade,
poC->oSOS.oSeries[iSeries].oExpDate.enMonth);
itoa(poC->oSOS.oSeries[iSeries].oExpDate.iDay, sBuf, 10);
strcat(sLatestTrade, sBuf);
strcat(sLatestTrade, poC->oS.sTicker);
double dStrike = poC->oSOS.oSeries[iSeries].dStrike;
gcvt(dStrike, 3, sBuf);
strcat(sLatestTrade, sBuf);
if(poC->oSOS.oSeries[iSeries].enCallPut == Call)
strcat(sLatestTrade, "Calls"
;
else
strcat(sLatestTrade, "Puts"
;
}
OP字符串
Delphi 1.0字符串最多255bytes,Delphi 2.0以后无此限.
在OP内的String所占的记忆空间会比您宣告的大小大.
因为字符串为数组,在数组[0]放长度.
例:
var
sMyName: string[25];
{最大25字符}
sYourName: string;
begin
sMyName := 'Paul Fulford';
{单引号表字符串}
在OP中,您可用:=和+处理字符串运算,例:
TickerC = class
...
public
sLatestTrade: string[TRADELENGTHBUF];
saTradeRecords: TStringList;
...
procedure TickerC.OptnFormat2(var lQuantity: longint;
poC: CompanyC;
var iSeries: integer);
...
end;
...
procedure TickerC.OptnFormat2(var lQuantity: longint;
poC: CompanyC;
var iSeries: integer);
begin
sLatestTrade := IntToStr(lQuantity);
AddMosToString(sLatestTrade,
poC.oSOS.oSeries[iSeries].oExpDate.enMonth);
sLatestTrade := sLatestTrade +
IntToStr(poC.oSOS.oSeries[iSeries].oExpDate.iDay) +
poC.oS.sTicker +
FloatToStr(poC.oSOS.oSeries[iSeries].dStrike);
if poC.oSOS.oSeries[iSeries].enCallPut = Call then
sLatestTrade := sLatestTrade + 'Calls'
else
sLatestTrade := sLatestTrade + 'Puts';
end;
{OptnFormat2}
您会发现OP处理字符串容易得多.
C++中字符串以"/0"结尾,OP中数组[0]放字符串长度.
=================================
数组
数组是数据的一序列排列.
C++与OP的数组宣告很不同.
但取用方式很像.
C++数组
数组从0开始,第一个元素为 [0], 第二个为[1]...类推,初学者要小心
// 宣告 数组...
DateC aoCANHolidays[SIZE_HOLIDAYARRAY];
double dAverageLast31Days[31];
// 取用数组
for(int i = 30, j = 29;
i > 0;
i--,j--)
dAverageLast31Days
= dAverageLast31Days[j];
OP数组
数组通常从[1]开始,但也不全然.
在Delphi中您也可以发现某些对象也是从[0]开始的.
像TList就是从TList[0]开始,我们要小心看对象的说明文件.
例子:
var
aoCANHolidays: array[1..SIZE_HOLIDAYARRAY] of DateC;
dAverageLast31Days: array[1..31] ofdo
uble;
i,j: integer;
begin
j := 30;
for i := 31do
wnto 2do
begin
dAverageLast31Days = dAverageLast31Days[j];
Dec(j);
{ or j := j-1;
}
end;
两个语言都可用多维数组,见下例:
C++
double dMatrix[50] [20];
OP
var
dMatrix: array[1..50, 1..20] ofdo
uble;
=================================
数值的指定与比较
C++数值的指定与比较
比较相等时用 == 号
给定值时用 = 号
如:
if (dMaxRate == 15.75)
{ ...
dMaxRate = 12.5;
...
}
OP数值的指定与比较
比较相等时用 = 号
给定值时用 := 号
如:
if dMaxRate = 15.75 then
begin
...
dMaxRate := 12.5;
...
end;
有一个例外就是OP在Const的值的给定是用=号,如:
const max=100;
=================================
常数宣告
常数是无法改变值的,所以一定要在宣告时给值.
C++常数宣告
const int iMax = 2000;
constdo
uble dMaxValue = 1234.75;
也可用宏定义常数
#define nMAXAMOUNT 1000
OP常数宣告
function PayBack_d(var dAmount:do
uble):do
uble;
const
iMAX = 2000;
{notice value assigned with single equal sign this time}
dMAXVALUE = 1234.75;
var
iCount, iLoop, iValToReach: integer;
dMaxLoan, dTotal, dMaxRate:do
uble;
begin
dMaxRate := dMAXVALUE;
{...}
=================================
函数与程序
在C++中所有的Function一定会传回值.
在OP中function要传回值,procedure不用
在C++中所有的function一定要()号,就算无参数
在OP中function无参数不用()号
C++函数与程序
例:
double IntSinceLastAddDate_d(double &dAvailCash);
// prototype
void SetNewIntRate();
// no parameters or return value
...
double LoanC::IntSinceLastAddDate_d(double &dAvailCash)
{
double dSomething;
...
return dSomething;
}
void LoanC::SetNewIntRate()
{ ... }
OP函数与程序
例:
function IntSinceLastAddDate_d(var dAvailCash:do
uble):do
uble;
procedure SetNewIntRate;
{无参数也无传回值}
...
function LoanC.IntSinceLastAddDate_d(var dAvailCash:do
uble):do
uble;
var
dSomething:do
uble;
begin
...
result := dSomething;
{the global variable "result"
is assigned the return value!}
end;
procedure LoanC.SetNewIntRate;
begin
...
end;
两个语言可以在参数传递时采用 pass by valye 或 pass by reference:
C++ pass by value ...do
uble IntSinceLastAddDate_d(double dAvailCash);
OP pass by value ... function IntSinceLastAddDate_d(dAvailCash:do
uble):do
uble;
C++ pass by reference ...do
uble IntSinceLastAddDate_d(double &dAvailCash);
OP pass by reference ... function IntSinceLastAddDate_d(var dAvailCash:do
uble):do
uble;
C++ pass constant ...do
uble IntSinceLastAddDate_d(constdo
uble dAvailCash);
OP pass constant ... function IntSinceLastAddDate_d(const dAvailCash:do
uble):do
uble;
=================================
with ...do
叙述
C++无 with ..do
叙述
在C++中当您要取用资料时:
poC.oStock.aoTradesLast130Days[0].lVol = 0;
poC.oStock.aoTradesLast130Days[0].dHigh = 0;
poC.oStock.aoTradesLast130Days[0].dLow = 0;
poC.oStock.aoTradesLast130Days[0].dClose = 0;
但在OP中可以简化成:
with poC.oStock.aoTradesLast130Days[0]do
begin
lVol := 0;
dHigh := 0;
dLow := 0;
dClose := 0;
end;
=================================
批注
C++
有两种
// 双斜线后为批注
/* 批注 */
OP
有三种
// 双斜线后为批注
{ 批注 }
(* 批注 *)
=================================
流程控制
有五种流程控制指令,C++与OP都有,用法满像的.
~~~~~~~~~~~~~~~~~~~~~~~~~
1) if ... else
指令
C++
if(<逻辑表达式>) // 一定要有()号
{ ...
}
else
if(<逻辑表达式>)
{...
}
else
{...
}
OP
if <逻辑表达式> then
// 不一定要有()号,因有then
begin
...
end
else
if <逻辑表达式> then
begin
....
end
else
begin
...
end;
{最后一个end才要加;分号}
~~~~~~~~~~~~~~~~~~~~~~~~~
2) switch/case ... 指令
C++
switch()
{
case iX: ... break;
case iY: ... break;
default: ...
}
OP
case of
{no "
begin
"
here}
iX:
begin
...
end;
{每个end都要;分号}
iY:
begin
...
end;
else
{此处不用;号}
begin
...
end;
end;
{这个end要;分号}
~~~~~~~~~~~~~~~~~~~~~~~~~
3) for ... loop 指令
C++
for(iCount = 0;
iCount <= 10;
iCount++)
{
// iCount++, 每次循环值加一
...
break;
// 中断循环
continue;
// 跳到下一个循环
...
}
OP
for iCount := 1 to 10do
begin
... {iCount每次自动加 1}
break;
{ 中断循环 }
continue;
{ 跳至下一个循环 }
...
end;
~~~~~~~~~~~~~~~~~~~~~~~~~
4) while ... loop 指令
C++
while(<逻辑表达式>)
{
...
break;
// 中断循环
continue;
// 跳到下一个循环
...
}
OP
while <逻辑表达式>do
begin
...
break;
{ 中断循环 }
continue;
{ 跳至下一个循环 }
...
end;
~~~~~~~~~~~~~~~~~~~~~~~~~
5)do
/repeat ... 指令
C++
do
{
// 逻辑表达式 False循环终止
...
break;
// 中断循环
continue;
// 跳到下一个循环
...
}while(<逻辑表达式>);
OP
repeat
// 逻辑表达式 True循环终止
...
break;
{ 中断循环 }
continue;
{ 跳至下一个循环 }
...
until <逻辑表达式>;
=================================
对象导向结构
C++与OP都可称为是对象导向式的语言.
C++可以用多重继承(multiple inheritance),OP只能单一继承(single inheritance)
让我们来看看建立对象的基本语法:
C++
Classes必须定义在header檔中...
class LoanC // 未有继承时
{
private: // 内定为private
...
protected: // 要有冒号
...
public:
...
};
//分号结尾
在C++中单一继承的语法如下:
class B: A
{...};
在C++中多重继承的语法如下:
class D: A, B, C
{...};
classes继承对象时可标明public, protected, 或 private.
内定是为 private
class D: public A, public B, private C
{...};
OP
Classes是在unit/file中的 "type"
结构中宣告...
type
LoanC = class(TObject)
{这表是从TObject继承下来. }
{此处不用 "
begin
"
指令}
private
...
protected {此处不用冒号}
...
public
...
published
...
end;
关键词 private, protected, public, 及 published (只有OP有) 指明了
每一个数据元素的数据范围宽广.
private:只能给在Class内部使用
protected:只能给这个Class或演生的Class使用
public:可以在程序所有的地方使用
Publishedelphi专用,用来建立接口
每一个Class需要一个建立者(constructor)
在C++理,建立者与class同名.
建立者可加参数:
ie:
LoanC();
// 无参数
LoanC(double &dCurrentBal);
// 一个参数
LoanC(double &dBalOne,do
uble &dBalTwo);
// 两个参数
在OP理,建立者与class不同名.
ie:
constructor MyLoanOne;
{no parameters}
constructor MyLoanTwo(var dCurrentBal:do
uble);
constructor MyLoanThree(var dBalOne, dBalTwo:do
uble);
C++与OP都提供解构者(destructors),也可称为释放内存(free memory)
在C++理, 解构者与建构者一样,与class同名.
如:
~LoanC();
// C++ destructor
在OP理, 解构者与class不同名.
如:
destructor LoanC.Destroy;
begin
oLoanDate.Free;
...
inherited Destroy;
{"inherited"
is a keyword}
end;
建立一个新对象,宣告一个变量:
double dAmount = 1515.75;
LoanC oMyLoan(dAmount);
如此做会配置一块内存,
如果用只标方式可以如下宣告:
double dAmount = 1515.75;
LoanC * poMyLoan = new LoanC(dAmount);
在OP理则不同,每一个都是指标.
var
dAmount:do
uble;
oMyLoan: LoanC;
begin
{oMyLoando
es not yet exist!}
dAmount := 1515.75;
oMyLoan := LoanC.MyLoanTwo(dAmount);
{now itdo
es}
在OP理也可也 Override.
type
LoanC = class
...
constructor Create;
{overrides TObject's Create}
...
end;
... and call the inherited Create constructor in the LoanC definition...
constructor LoanC.Create;
begin
inherited Create;
{calls TObject's Create}
...
end;
C++与OP理引用内部元素采用如下语法:
oMyLoan.dPrincipal;
在C++中,使用指针引用内部元素采用如下语法:
poMyLoan->dPrincipal;
在C++中有三个运操作数:
1. &
取地址
2. * 取指标
3. -> 印用元素
在OP中都用.(逗点号)
=================================
Containers
C++:Containers
typedef TISetAsVector tdCompanySet;
typedef TISetAsVectorIterator tdCSetIter;
...
int OwlMain(int, char*[])
{...
tdCompanySet oCompColl;
...
}
...
void MainForm::AddNewCompany()
{
CompanyC * poC = new CompanyC;
oCompColl.Add(new CompanyC(poC));
...
// now iterate
tdCSetIter oCIter(oCompColl);
while(oCIter)
{
poC = oCIter++;
// now use poC
...
}
}
OP:Containers
TMainForm = class(TForm)
...
public
oCompColl: TList;
...
end;
...
procedure TMainForm.AddNewCompany;
var
poC: CompanyC;
iCount: integer;
begin
poC := CompanyC.Create;
...
oCompColl.Add(poC);
...
{now iterate}
for iCount := 0 to oCompColl.Count - 1do
begin
poC := oCompColl.Items[iCount];
{now use poC}
...
end;
=================================
例外处理
C++:例外处理
try
{
...
}
catch()
{
...
}
catch(...)
{
...
}
OP:例外处理
try
{不用 begin
... end;
指令}
...
finally
{例外处理}
...
end;
取得Run Time 错误讯息时:
try
...
except
ondo
... ;
end;
=================================
资料流(Streaming)
C++:资料流
class CompanyC
{
...
friend ofstream &
operator <<(ofstream &oS, CompanyC * poC);
...
};
...
friend ofstream &
operator <<(ofstream &oS, CompanyC * poC)
{
oS << poC->dVersion
<< poC->dLastDivPerShare
<< poC->enIndustry
...
<< poC->sName;
return oS;
}
friend ofstream &
operator <<(ofstream &oS, CompanyC * poC)
{
oS.write( (char*) &
(*poC), sizeof(*poC));
return oS;
}
// 打开 a stream
ofstream ofS("gamedata.gam"
if(!ofS)
return;
...
// 存档
tdCSetIter oCIter(oCompColl);
// see container section
while(oCIter)
{
poC = oCIter;
ofS << poC;
}
ofS.close();
OP:资料流
type
CompanyC = class
public
procedure Read(var f:file);
procedure Write(var f:file);
...
end;
...
procedure CompanyC.Write(var f:file);
begin
BlockWrite(f, dVersion, sizeof(dVersion));
BlockWrite(f, dLastDivPerShare, sizeof(dLastDivPerShare));
BlockWrite(f, enIndustry, sizeof(enIndustry));
...
BlockWrite(f, sName, sizeof(sName));
end;
开档:
procedure TMainForm.FileSaveItemClick(Sender: TObject);
var
oGameFile: file;
iCount: integer;
poC: CompanyC;
sNameFile: string[13];
begin
...
sNameFile := 'gamedata.gam';
AssignFile(oGameFile, sFileName);
Rewrite(oGameFile, 1);
{the 1 means 1 byte at a time}
...
for iCount := 0 to oCompColl.Count - 1do
begin
poC := oCompColl.Items[iCount];
poC.Write(oGameFile);
end;
CloseFile(oGameFile);
end;
=================================
项目档的设计
在 C++中,常数定义放在.h文件中,程序放在.cpp中(会用#include .h檔)
在 Delphi中,常数定义与程序都在一个文件.pas中
不同的.pas可用uses指令引用别的.pas宣告个变量
=================================
如何转换
如果要转有画面的C++程序要比转无画面的C++程序困难的多.
如果要转有画面的C++程序,要先在Dlephi开一Form,再将c++的程序代码转入.
要将程序copy 至delphi中再来改.
1) 先整体性的转换 ,将 C++ 的{...} 改为 begin
...end;
double CompanyC::NewAnnualReport_v(Economy &
oE)
{ ... // delimiter starts on a new line
}
...versus this...
double CompanyC::NewAnnualReport_v(Economy &
oE){ // delimiter at end of line
...
}
2) a) 将 C++ 的 || 转为 "or"
b) 将 C++ 的 &&
转为 "and"
c) (1)将 C++ 的 == 转为 =
(2)将 C++ 的 = 转为 :=
d) 将 C++ 的 /* */ 转为 { }
e) C++的 // 不用转
f) 将 双引号转为单引号 "
-> '
3) C++的每个if要加 then
如:
C++
if(oE.enDirection == Up &&
oE.uNumMosUpYr >= oE.uNumMosDownYr)
{
...
}
OP
if (oE.enDirection = Up) and
(oE.iNumMosUpYr >= oE.iNumMosDownYr) then
begin
...
end;
4) 将控制指令修改
5) C++的 overloaded 运算可 re-written,那就看您在OP中要如何处理.
6) 将 C++ 的 :: 转为 .
procedure TForm1.Memo1Change(Sender: TObject);
{要加上分号}
begin
...
end;
7) 将 C++ 的 ++ 和 decrement -- 改为inc(x) 与dec(
8) 将C++在区块 中宣告的变量全部移到var区中.
9) 将C++的函数名称前加上 "function"
或 "procedure"
10) 将 C++ 的 -> 转为 . (句点)
DateC oBirthDate;
var
oBirthDate: DateC;
begin
oBirthDate := DateC.Create;
11) 将 C++ 的strcpy(...) 与 strcat(...) 转为 := 与 +
12) 那多重继承呢?( multiple inheritance).
用Class B继承Class A,再用class C继承 B的方式 .
=================================
结论
C++ 是简短的语言, 而 OP 比较像英文.
然而C++较紧密,但不易阅读.
============完结=============