1 hibernate 一级缓存
Session
evict(Object o) 从缓存中清除指定的持久化对象
clear() 清除缓存中所有对象
2 批量更新于批量删除
1) 批量更新
Iterator customers=session.find("from Customer c where c.age>0");
while(customers.hasNext()){
Customer customer=(Customer)customers.next();
customer.setAge(customer.getAge()+1);
}
tx.commit();
session.close();
缺点:内存中加载了大量数据
执行了多次update 语句
改进
Iterator customers=session.find("from Customer c where c.age>0");
while(customers.hasNext()){
Customer customer=(Customer)customers.next();
customer.setAge(customer.getAge()+1);
session.flush();
session.evict(customer);
}
tx.commit();
session.close();
遗留问题
执行了多次update 语句
采用jdbc api 进行调用
Connection con=session.connection();
PrepareStatement stmt=con.prepareStatement("update customers set age=age+1 where age>0");
stmt.executeUpdate();
tx.commit();
另外,也可以调用底层的存储过程进行批量更新
create or replace procedure batchUpdateCustomer(p_age,in number) as
begin
update customer set age=age+1 where age>p_age;
end;
tx=session.beginTransaction();
Connection con=session.connection();
CallableStatement cstmt=con.prepareCall(batchUpdateCustomer);
cstmt.setInt(1,0);
cstmt.eqecuteUpdate();
tx.commit();
2) 批量数据的删除
session.delete("from Customer c where c.age>0");
实际调用的过程
session * from Customer where age>0;
在把所有数据加载到内存之后执行多条delete 语句
delete from customer where id=i;
.......................
改进办法采用jdbc api 进行批量数据的删除
tx=session.beginTransaction();
Connection con=session.connection();
con.execute("delete from customers where age>0");
tx.commit();
Hibernate java sql oracle
integer or int int or Integer INTEGER
long long or Long BIGINT
short short or Short SMALLINT
byte byte or Byte TINYINT
float float or Float FLOAT
double double or Double DOUBLE
big_decimal java.math.BigDecimal NUMBERBIC
character char java.lang.Character CHAR(1)
String
string String VARCHAR
boolean boolean or Boolean BIT
date java.util.Date DATE
java.sql.Date
time Date or java.sql.time TIME
timestamp Date or java.sql.Timestamp TIMESTAMP
binary byte[] blog blog
text String clob clog
serializable blog blog
clob java.sql.clob clob clob
blob java.sql.blob blog blob
1 动态连接
Windows 运作机制的核心是一个称作动态连接的概念
#include <windows.h>
int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MessageBox (NULL, TEXT ("Hello, Windows 98!"), TEXT ("HelloMsg"), 0);
return 0 ;
}
1) #include <windows.h>包含其它的头文件
2) 程序入口
int WINAPI WinMain ( HINSTANCE hInstance,HINSTANCE hPrevInstance,
PSTR szCmdLine,int iCmdShow)
a #define WINAPI __stdcall 指定一个呼叫约定,包括如何生产机器码,参数如何入栈
b HINSTANCE hInstance 执行体代号,唯一标识该程序
c HINSTANCE hPrevInstance 已经不采用
d PSTR szCmdLine 参数列表
e int iCmdShow 显示方式
3) MessageBox 函数
MessageBox (NULL, TEXT ("Hello, Windows 98!"), TEXT ("HelloMsg"), 0);
参数1 窗体代号
参数2 主题显示文字
参数3 标题显示文字
参数4 按钮,0 为确认 使用C语言的OR(|)操作符号将上面显示的一个常数与代表内定按钮的常数组合:
#define MB_OK 0x00000000L
#define MB_OKCANCEL 0x00000001L
#define MB_ABORTRETRYIGNORE 0x00000002L
#define MB_YESNOCANCEL 0x00000003L
#define MB_YESNO 0x00000004L
#define MB_RETRYCANCEL
#define MB_DEFBUTTON1 0x00000000L
#define MB_DEFBUTTON2 0x00000100L
#define MB_DEFBUTTON3 0x00000200L
#define MB_DEFBUTTON4
图示的外观
#define MB_ICONHAND 0x00000010L
#define MB_ICONQUESTION 0x00000020L
#define MB_ICONEXCLAMATION 0x00000030L
#define MB_ICONASTERISK
#define MB_ICONWARNING MB_ICONEXCLAMATION
#define MB_ICONERROR MB_ICONHAND
#define MB_ICONINFORMATION MB_ICONASTERISK
#define MB_ICONSTOP
2 c 语言编译过程 c--compile -- .obj ---linking---- .exe
一 文件
1 c 标准文件驱动器,可以支持两种文件类型,二进制文件,和文本文件。c 标准文件是在头文件
stdio.h 中声明。
标准文件类型通过指针来进行存储 FILE * fp;
2 c++ 流式文件类 fstream,ifstream 和ofstream,分别对应读写,读和写,并支持文本和二进制文
件。
3 非缓冲文件
二 文件对话框组件
1 OpenDialog 两种.TXT and .PAS 两种类型的过滤器。
1) Filter OpenDaalog1->Filter="Text files{*.txt}|*.TXT|Pascal files{*.pas}|*.PAS";
同一个过滤器中,还可以有多种文件后缀
OpenDialog1->Filter="Pascal files|*.PAS;*.DPK;*.DPR";
2) FilterIndex 设置对话框一打开时选中的文件过滤。数值从1开始计算。
3) InitialDir 设置对话框打开时定位的目录。
4) Options
OpenPictureDialog1->Options.Clear();
OeenPictureDialog1->Options<<ofFileMustExist<<ofHideReadOnly<<ofNoChangeDir;
5) Title 设置对话框标题中显示的内容。
2 SaveDialog 组建可以选择并保存文件
3 OpenPictureDialog 可以选择并打开图形文件。
4 SavePictureDialog 可以选择并保存图形文件。
三 Win3。1 相关组件
FileListBox,DirectoryListBox,DriveCombox,FilterComboBox
四 常用文件管理函数
1 文件函数常用函数
将一个文件从记录盘上删除,如果不存在或无法删除。则返回False。
extern PACKAGE bool __fastcall DeleteFile(const AnsiString FileName);
void __fastcall TFORM1::ButtonClick(TObject *Sender)
{
char buffer[256];
GetWindowsDirectory(buffer,sizeof(buffer));//获取Windows 系统目录
AnsiString asFileName=FileSearch(Edit1->Text,GetCurrentDir()+AnsiString(";")
+AnsiString(buffer));//在当前目录下和windows系统}//目录下查询文件。
if(asFileName.IsEmty()) ShowMessage(AnsiString("Couldn't Found")+Edit1->Text1);
2 FileSeek
extern PACKAGE int __fastcall FileSeek(int Handle, int Offset, int Origin);
extern PACKAGE __int64 __fastcall FileSeek(int Handle, const __int64 Offset, int Origin);
Description
Use FileSeek to reposition the read/write point in a file that was opened with FileOpen or
FileCreate. Handle is the file handle that was returned by FileOpen or FileCreate.
Offset specifies the number of bytes from Origin where the file pointer should be
positioned. Origin is a code with three possible values, denoting the beginning of the file,
the end of the file, and the current position of the file pointer.
Origin Action
0 The file pointer is positioned Offset bytes from the beginning of the file.
1 The file pointer is positioned Offset bytes from its current position.
2 The file pointer is positioned Offset bytes from the end of the file.
If FileSeek is successful, it returns the new position of the file pointer; otherwise, it
returns -1.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int iFileHandle;
int iFileLength;
int iBytesRead;
char *pszBuffer;
if (OpenDialog1->Execute())
{
try
{
iFileHandle = FileOpen(OpenDialog1->FileName, fmOpenRead);
iFileLength = FileSeek(iFileHandle,0,2);
FileSeek(iFileHandle,0,0);
pszBuffer = newchar[iFileLength+1];
iBytesRead = FileRead(iFileHandle, pszBuffer, iFileLength);
FileClose(iFileHandle);
for (int i=0;i<iBytesRead;i++)
{
StringGrid1->RowCount += 1;
StringGrid1->Cells[1][i+1] = pszBuffer[i];
StringGrid1->Cells[2][i+1] = IntToStr((int)pszBuffer[i]);
}
delete [] pszBuffer;
}
catch(...)
{
Application->MessageBox("Can't perform one of the following file operations: Open,
Seek, Read, Close.", "File Error", IDOK);
}
}
}
3FileExists
if(FileExist(SaveDialog1->FileName))
{
RenameFile(SaveDialog1->File,SaveDialog1->FileName+".bak");
}
iFileHandle=fileCreate(SaveSialog1->FileName);
for(int i=0;i<Memo2->Lines->String[i].length())
{
FileWrite(iFileHandle,Memo2->Lines->String[i].c_str(),length);
}
FileClose(iFileHandle);
4 FileGetAttrs
FileGetAttr returns the attributes of the file as a string of bits. This value is the same
as the Attr field of a TSearchRec struct. Check for individual attributes with code such as
the following:
int Attrs = FileGetAttr("MyFile.sys");
if x(Attrs & faHidden)
FileSetAttr("MyFile.sys", Attrs & !faHidden);
A return value of -1 indicates that an error occurred.
5 FileSetAttrs
FileSetAttr sets the file attributes of the file given by FileName to the value given by
Attr. The value of Attr is formed by combining the appropriate file attribute constants, as
in the following:
FileSetAttr("MyFile.sys", faReadOnly | faSysFile);
FileSetAttr returns zero if the function was successful. Otherwise the return value is an
error code.
三 目录操作常用函数
1 CreateDir
#include <Filectrl.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (!DirectoryExists("c:\\temp"))
{
if (!CreateDir("C:\\temp"))
throw Exception("Cannot create c:\\temp directory.");
}
}
2 ForceDirectories
ForceDirectories creates a new directory as specified in Dir, which must be a fully-
qualified path name. If the directories given in the path do not yet exist, ForceDirectories
attempts to create them.
ForceDirectories returns true if it successfully creates all necessary directories, false
if it could not create a needed directory.
Important
Do not call ForceDirectories with an empty string. Doing so causes ForceDirectories to
throw an exception.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Dir = "C:\Apps\Sales\Local";
if (ForceDirectories(Dir))
Label1->Caption = Dir + " was created";
}
3 GetCurrentDir
获取当前的目录完整的路径名
4 RemoveDir
删除一个存在的目录,目录必须为空
5 SetCurrentDir设置系统的当前目录
6 SelectDirectory
extern PACKAGE bool __fastcall SelectDirectory(constAnsiString Caption, const WideString
Root, AnsiString &Directory);
Call SelectDirectory to let the user enter a directory name.
Use the first syntax to display the Windows directory browser. The Caption parameter
specifies a caption for the dialog. The Root parameter specifies the root directory from
which to browse. The selected directory is returned as the Directory parameter. When using
this syntax,
SelectDirectory does not change the value of the current directory.
extern PACKAGE bool __fastcall SelectDirectory(AnsiString &Directory, TSelectDirOpts
Options, int HelpCtx);
enum TSelectDirOpt { sdAllowCreate, sdPerformCreate, sdPrompt };
typedef Set<TSelectDirOpt, sdAllowCreate, sdPrompt> TSelectDirOpts;
sdAllowCreate An edit box allows the user to type in the name of a directory that
does not exist. This option does not create a directory: the
application
must read the name of the selected directory and create it i
f desired.
sdPerformCreate Used only in combination with sdAllowCreate. If the user enters a
directory
name that does not exist, the directory selection dialog creates it.
sdPrompt Used only in combination with sdAllowCreate. Displays a message box
that informs the user when the entered directory does not exist
and asks if the directory should be created.
If the user chooses OK, the directory is created
if the option set includes sdPerformCreate.
If the option set does not include sdPerformCreate,
the directory is not created:
the application must read the directory name and create
#include <FileCtrl.hpp>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Dir = "C:\\Program Files\\MyApp";
if (SelectDirectory(Dir, TSelectDirOpts() << sdAllowCreate << sdPerformCreate <<
sdPrompt,1000))
Label1->Caption = Dir;
}
三 驱动器常用函数
1 DiskFree 指定驱动器中剩余空间的字节数
2 DiskSize 驱动器容量
四文件名常用函数
1 ChangeFileExt
2 ExtractFileDir
3 ExtractFileDriver
4 ExtractFileExt
5 ExtractFileName
6 ExtractFilePath
7 ExtractRelativePath
实例
1
1
L a b e l 1 目录列表( & D ) : FocusControl: DirectoryListBox1
D i r e c t o r y L i s t B o x 1 D i r L a b e l : L a b e l 6 ;
FileList: FileListBox1
L a b e l 2 文件列表( & S ) : FocusControl: FileListBox1
F i l e L i s t B o x 1 FileEdit: Edit1
L a b e l 3 驱动器( & R ) : FocusControl: DriveComboBox1
D r i v e C o m b o B o x 1 DirList: DirectoryListBox1
L a b e l 4 文件类型( & F ) : FocusControl: FilterComboBox1
F i l t e r C o m b o B o x 1 FileList: FileListBox1
Filter: 所有文件 ( * . * ) | * . * |文本文件( * . t x t ) | * . t x t
L a b e l 5 路径名:
L a b e l 6 C : \ S a m p l e s \ S 0 6 B
L a b e l 7 文件名( & N ) : FocusControl: Edit1
E d i t 1
B u t t o n 1 文件长度( & L ) . . . Te x t : * . *
#include<stdio.h>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
FILE* fp;
AnsiString FileFullName;
long size;
AnsiString PropertyMes;
FileFullName=Label2->Caption+"\\"+Edit1->Text;
if(FileExists(FileFullName))
{
fp=fopen(FileFullName.c_str(),"rt");
if(fp!=NULL)
{
fseek(fp,0L,SEEK_END);
size=ftell(fp);//get the length of file
PropertyMes="file is total"+IntToStr(size)+"bytes.";
MessageDlg(PropertyMes,mtInformation,TMsgDlgButtons() << mbOK, 0);
}else
{
MessageDlg(PropertyMes,mtWarning,TMsgDlgButtons() << mbOK, 0);
}
fclose(fp);
}
}
2 获取驱动器类型信息
UINT GetDriveType(
LPCTSTR lpRootPathName //获取根目录的路径名称
)
表6-5 函数G e t D r i v e Ty p e的返回值及其含义
数 值 含 义
0 无法检测驱动器的类型
1 根目录不存在
D R I V E _ R E M O VA B L E 可移动驱动器
D R I V E _ F I X E D 不可移动驱动器
D R I V E _ R E M O T E 网络驱动器
D R I V E _ C D R O M C D - R O M驱动器
D R I V E _ R A M D I S K 虚拟驱动器
Result=GetDriveType(Edit2->Text.c_str());
3 操作ini 文件
动态连接库(Dynamic link library),是一些编译过的可以执行的代码模块,后缀为.dll
1 DLL的基本理论
在使用普通函数库时,可以在程序连接时将库中的代码拷贝到执行文件中,这时静态链接,在多个同样程序执行时,体统保留了许多
代码副本,造成了内存资源的浪费。在使用dll时,不必将dll链接到程序中,而是在应用程序运行时动态的装载dll,装载dll被映射
到进程的地址空间中。同时,使用dll 并不时将库代码拷贝,只是在程序中记录了函数的入口点和接口。
2 DLL 的优点
1) 节省系统资源
2) 不仅可以包括可执行代码,还可以包括数据和各种资源
3)支持多语言
4)升级可以仅仅覆盖dll 文件
5)dll 独立编程语言,c++builder 中的dll vc 也可以使用
3导入导出匹配
DLL函数一般有两种函数,内部函数(internal)和导出函数(export).在实际情况下,许多DLL 调用了其他DLL里面的函数,因此
DLL可以同时有导入和导出函数。
DLL 包含有一个导出函数表,可以通过函数的符号化的名字和称为序号的正书来识别这些函数,函数表中包含了函数在dll内部的
地址。在动态链接进程好建立一张表,把客户的调用与dll里的函数的地址连接起来。
double dbValue(value);//内部函数
double dbValue(value);//内部函数
extern"c" _declspec(dllexpoert) double changeValue(double,bool);//外部函数
double dblValue(double value)
{
return value*vlaue;
}
double changeValue(double value,bool whichOp)
{
return whichOp?doublValue(value):halfValue(value);
}
如果我们希望dll可以用于其他语言或不同版本的c++ 需要在声明导出函数的时候加上extern "C."
4 隐式的链接和显示的链接
隐式链接(前面所讲)在创建dll 的时候,链接器产生一个lib 文件把拿获了dll中的导出符号和序号
显示链接调用Win32 的LoadLibrary 函数,使用完后,调用 FreeLibrary.
5 查找dll
依次顺序为包含exe 的目录,进程的当前目录,Windows 目录,path 环境变量里列出的目录。
6 创建动态链接库
(如何查看dll 文件的定义)
7 导出函数:extern "C" __declspec(dllexport) ExportType FunctionName(Parameter)
extern "C" __declspec(dllimport) __stdcall void CreateFromFunct();
extern "C" __declspec(dllexport) __stdcall void CreateFromFunct();//导出函数
导出类:class __declspec(dllexport) ExportType ClassName{...}
class __declspec(dllexport) __stdcall MyDllClass { //导出类
public:
MyDllClass();
void CreateAForm();
TDllFrm* DllMyForm;
};
__declspec(dllimport) class __stdcall MyDllClass {
public:
MyDllClass();
void CreateAForm();
TDllFrm* DllMyForm;
};
静态调用,build 生成dll 文件和lib 文件,并把lib 文件导入到工程中
void __fastcall TForm1::Button1Click(TObject *Sender)
{ // 导出类实现,导出类只能使用静态方式调用
DllClass = new MyDllClass();
DllClass->CreateAForm();
}
void __fastcall TForm1::Button2Click(TObject *Sender)
{ // 导出函数实现
CreateFromFunct();
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
delete DllClass;
}
动态调用
class TForm1 : public TForm
{
...
private: // User declarations
void (__stdcall *CreateFromFunct)();
...
}
HINSTANCE DLLInst = NULL;
void __fastcall TForm1::Button2Click(TObject *Sender)
{
if( NULL == DLLInst ) DLLInst = LoadLibrary("DLL.dll"); //上面的 Dll
if (DLLInst) {
CreateFromFunct = (void (__stdcall*)()) GetProcAddress(DLLInst,
"CreateFromFunct");
if (CreateFromFunct) CreateFromFunct();
else ShowMessage("Could not obtain function pointer");
}
else ShowMessage("Could not load DLL.dll");
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
if ( DLLInst ) FreeLibrary (DLLInst);
}
8 bcb 调用vc 编写的DLL
1) 名字分解
1. 名字分解:
没有名字分解的函数
TestFunction1 // __cdecl calling convention
@TestFunction2 // __fastcall calling convention
TESTFUNCTION3 // __pascal calling convention
TestFunction4 // __stdcall calling convention
有名字分解的函数
@TestFunction1$QV // __cdecl calling convention
@TestFunction2$qv // __fastcall calling convention
TESTFUNCTION3$qqrv // __apscal calling convention
@TestFunction4$qqrv // __stdcall calling convention
使用 extern "C" 不会分解函数名
2)
__cdecl 缺省
是 Borland C++ 的缺省的 C 格式命名约定,它在标识符前加一下划线,以保留
它原来所有的全程标识符。参数按最右边参数优先的原则传递给栈,然后清栈。
extaern "C" bool __cdecl TestFunction();
在 def 文件中显示为
TestFunction @1
注释: @1 表示函数的顺序数,将在“使用别名”时使用。
__pascal Pascal格式
这时函数名全部变成大写,第一个参数先压栈,然后清栈。
TESTFUNCTION @1 //def file
__stdcall 标准调用
最后一个参数先压栈,然后清栈。
TestFunction @1 //def file
__fastcall 把参数传递给寄存器
第一个参数先压栈,然后清栈。
@TestFunction @1 //def file
3)
3. 解决调用约定:
Microsoft 与 Borland 的 __stdcall 之间的区别是命名方式。 Borland 采用
__stdcall 的方式去掉了名字起前的下划线。 Microsoft 则是在前加上下划线,在
后加上 @ ,再后跟为栈保留的字节数。字节数取决于参数在栈所占的空间。每一个
参数都舍入为 4 的倍数加起来。这种 Miocrosoft 的 DLL 与系统的 DLL 不一样。
4 查看dll 的调用接口tdump -ee MyDll.dll >1.txt (查看 1.txt 文件即可)
5 编辑c++ builder build 为一个可以直接调用的 .exe 。 点击project option 中linker 标签 去掉user dynamic RTL 选项 和package 中 去掉builder with runtime package 选项.
6 调用代参数的vl 编写的dll 调用的实例。
int (__cdecl *fun)(char*,char*,char*);
HINSTANCE DLLInst = NULL;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if( NULL == DLLInst )
{
DLLInst = LoadLibrary("HollyIVRCard.dll");
}
if(DLLInst)
{
fun=(int (__cdecl*)(char*,char*,char*))GetProcAddress(DLLInst,"hTrade");
if(fun)
{
cardid=Edit1->Text.c_str();
num=Edit2->Text.c_str();
ShowMessage(fun(cardid,num,res));
//cout<<cardid<<endl;
//cout<<num<<endl;
}
} else{
ShowMessage("load dll fail");
}
ShowMessage(AnsiString(res));
}
Containing your beans
Tere i sno single Spring container.Spring actually comes with two distince types of containers:Bean factories and Application
contexts.Beyong there two basic types of contains .Srping come with sereral implementss of BeanFacotory and ApplicationContext.
1 introducing the BeanFactory
There are several implementations of BeanFactory in Spring .But the most userful one is XmlBeanFactory,whick loads
its bean based on the definitions contained in an xml file.
Creat a XmlBeanFactory BeanFactory factory=new XMLBeanFactory(new FileInputStream("beans.xml"));
But at that time ,the BeanFactory does not initialize the bean ,it is loaded lazliy.
Get the Bean :MyBean myBean=(MyBean)factory.getBean("myBean");
When getBean() is called ,the factory will instantiate the bean and being setting the bean using dependency injection.
2 Working with an application context
an ApplicationContextis prefered over a BeanFactory in nearly all application ,the only time you might consider using a BeanFactory
are in circumtance where resource s are scarce.
Amony the many implements of ApplicationContext are three that are commonly used:
ClassPathXmlApplicationContext,FileSystemXmpApplicationContext,XmlWebApplicationContext.
ApplicationContext context=new ClassPathXmlApplicationContext("foo.xml");
wiring the beans
<beans>
<bean id="foo" class="com.springinaction.Foo" />
</beans>
Prototyping vs.singleton
By default ,all Spring beans are singletons.When the container dispenses a bean it will always give the exact same instance of the
In this case ,you would want to define a prototype bean .Defining a prototype means that instead of defining a single bean.
<bean id="foo" class="com.springinaction.Foo" single/>on="false" />
Initialization and destruction
<bean id="foo" class="com.springinaction.Foo" init-method="setup" destory-method="teardown">
Injectiong dependencies via setter method
<bean id="foo" class="com.srpinginaction.Foo" >
<property name="name">Foo McFoo</value>
</bean>
Referencing other beans
<bean id="foo" class="com.springinaction.Foo">
<property name="bar" >
<ref bean="bar" />
</property>
</bean>
<bean id="bar" colass="com.srpinginaction.Bar" />
Inner beans
<bean id="courseService"
class="com.CourseWericeImpl">
<property nanme="studentService">
<bean
class="com....." />
</property>
</bean>
Wiring collections
1Wiring lists and arrays java.util.List
<property name="barList">
<list>
<value>bar1</value>
<ref bean="bar2"/>
</lsit>
</property>
2 Wiring set java.tuil.Set
<property name="barSet">
<set>
<value>bar1</value>
<ref bean="bar2" />
</set>
</property>
3 Wiring maps java.util.Map
<property name="barMap">
<ebtry key="key1">
<value>bar1</value>
</property>
4 Wiring propertyies
<property name="barProps">
<props>
<prop key="key1">bar1</prop>
<prop key="key2">bar2</prop>
</props>
</property>
5 Setting null values
<property name="foo"><null/><property>
injecting dependencies via constructor
<id="foo" class="com.springinaction.Foo">
<constructor-arg>
<value>42<value>( <ref bean="bar">)
</constructor-arg>
<bean id="foo" class="com.springinaction.Foo">
<constructor-arg>
<value>http://www.manning.com</value>
</constructor-arg>
<constructor-arg>
<value>http://www.manning.com</value>
</constructor-arg>
</bean>
代码会生锈吗?这真是一个很奇怪的问题,代码怎么会生锈呢?但是现在的许多软件企业,却总认为代码放久了就会发霉,会生锈,因此每次发布的新版本总抛弃了原来所有的代码从头来过。这种做法真的可取吗?我们且不说这么做要浪费多少人力物力(反正公司有的是钱 really?但为什么工资只开这么一点点,配的电脑也这么烂),就仅仅从新版本的质量来讲,也不见得尽如人意。谁能够保证新版本的核心人员与原来版本是同一批人,那么又怎么来保证原来的“经验积累”能够在新版本中发挥作用。另外,老版本的代码多是经过项目实践来检验的,它们身上可能带着修复bug后,留下的伤疤,但是至少它已经痊愈
了,他已经成为了一名经历过战场洗礼的战士。而新版本呢,好比是在军校学习的学生,它们可进行了更为先进的战略战术的学习(一些更先进的技术)但是,遗憾的是他们从来没有在战场上真枪实弹的打过仗,(在项目中许多新技术的应用往往是程序员边学边用的,当然,这也是软件行业的一个特点)因此能否成为合格的战士还需要经过实战(项目)的考验,而不仅仅是考试(测试人员)的成绩。如果我们把一些战斗经验丰富的老战士,进一步培训(对老版本进行修复,重构)我想他们的战斗力可能会远远超过这些新兵?
但是为什么这么多的企业,都会不约而同的选择重新编写代码呢,我想很可能是那些程序员在作怪(呵呵,不好意思我也是一个程序员,在这里只是就事论事 不敢含有任何贬低咱程序员的意思)。程序员总是不停的在抱怨,原来的代码事如何如何的乱,几页的代码竟然没有任何注释,许许多多的代码我竟然不知道做什么用的,让我修改,我还不如重写一遍呢?这是发生在程序员修改别人写的代码时,时常会发的牢骚。 原来的代码真的真么糟吗,其实并不尽然。那写你看起来一团糟的代码,也许就是修改某个
bug 时留下的伤疤,如果从头写一段新的代码,谁能保证你的代码没有原来那bug呢?其实我们可以采用很多重构的方法来解决,如设计模式的开闭原则,就可以很好的规避这一类问题。
因此我认为,一个企业不要总是频繁的发布新版本,只有可以明确的指出现有版本已经满足不了市场的需求了,我们才需要重新规划。我们需要明确,我们当前最需要做的是对现有版本修修补补,使之不断完善,不断健壮。君不见,网景的netscape 和borland 的dbasde就是前车之鉴吗?
注:网景的netscape 因新版本重写代码,整整用了3年的时间,其市场份额从80% 降到了20%
borland 从些Arago(dbase的前身) 也把市场白白的让给了 access
现在各行各业都兴采用什么,矩阵管理的方式,号称可以提高效率,但是在软件行业一定适用吗?
据说,微软采取的就是这种矩阵管理的方式,每一个项目由技术人员,项目经理,测试人员三个
部门的人员组成。其中,项目经理负责项目的协调。看起来,是人尽其用,每个人只需完成它分内的工作
即可,但是在一个项目中,涉及到大量的沟通(正式的和非正式的,内部的和外部的),和协调。如果项目组成员仅仅完成自己分内的工作,而把剩下的工作全部交给项目经理去完成,那么工作效率之低就可想而知了。这理涉及到一个问题,如何提高项目组成员的工作主动性,主动去完成自己分外的,但是自己最合适的工作呢?当然可以提高员工的工资,但是人的欲望是没有止境的,长到多少合适呢,在说公司能够承受多少呢?
可见,涨工资不是解决问题的根本方法。因此我们需要想一些别的办法。
在矩阵管理的模式下,由于每个人不隶属于任何的项目,只隶属于自己的部门。因此,在项目经理
与组员进行沟通时,也仿佛在与其他部门进行交互一样,存在这推诿,敷衍等等许多问题。如何解决这
个问题呢,那就是让每个项目组成员都要与这个项目荣辱与共。这恰恰就是矩阵管理存在的最大问题。
在矩阵管理中,当项目组成员完成一步份工作后,可能就会撤出这个项目,因此这个组员也不会全
身心的投入项目的开发,因为它还要想着下一个项目。项目经理常常挂在嘴边的一句话,我的项目
怎么怎么样了(先不管这样说会让其它项目组成员心里怎么想),但是很少有项目组成员会说我的项目。。。。,这是为什么呢。因为不管嘴里怎么说,项目组成员在内心深处就没有把他当作自己的项目
他只需要完成自己的工作就可以了,没有必要作一些额外的工作,不在其位,不谋其政吗?这里所提到的
是矩阵管理存在的一些共性的问题,对软软件小组进行矩阵管理存在的问题更大了。众所周知,软件开发
是一种创造性的工作,其工作主动性所产生的作用更远远大于其它行业。在《人件》认为软件工程的管理
其实就是对人的管理,一切管理都要以人为核心。但是某些领导,往往忽视了这一点,把软件人员当作一种可以重复利用的资源,结果吃亏的将会是项目本身。
也许大家会说了,你是不当家不知柴米贵,不作领导你不知领导的难处,在这里发发牢骚谁都会,如果你是领导,你会怎么办呢?
当然了,作为非领导的我,只是从我的角度讲了一下我对这个问题的看法,另外我也不只是在这里
夸夸其谈,我呢,在下面也阐述一下,如果是我,我会如何管理,希望某个领导看到后也也考虑考虑。
1 软件小组依然存在,但是其作用已经发生的变化。首先软件小组对已经进入项目的小组成员不能
进行工作的安排。只能对在项目之外的软件人员进行工作安排。其次,软件小组需要担付起对新入职的
软件人员进行培训的工作,不能把培训大量的工作放到真实项目中,这样必然会降低项目的质量。再次
软件小组,对项目中一些通用的问题集中解决,对项目中的疑难问题提供技术支持。另外软件小组还需要
对小组成员代码的质量进行走查,提高软件小组的成员的技能。当然作为软件小组成员的行政单位,软件小组成员的考核还是要有软件小组主导的。
2 软件人员,尽能的参与项目真个生命周期,项目紧张人紧张,项目不紧张人员可以稍微放松,或及时进行充电。忽略了软件人员的对不断学习的需求,是当前软件管理的一大弊病。(可能有些上岗上线了,但这对调动软件人员的积极性和保持相对稳定的团队有这意想不到的作用)
3 项目经理,需要对软件开发的特点,和软件人员的管理有所了解,建议读一读《人件》这本书。当然
提高项目经理本身的软件素养才能根本解决问题,建议软件项目的项目经理一定要具备较强的开发能力和较为丰富的开发经验,公司不要心疼一点点工资,它可以给公司带来的效益要远远高于此。
4 项目经理不要说,“我的项目”,应该改成“我们的项目”,让项目组的每个成员由一种归属感。
作为一个项目组成员,我们需要的是一种经历风雨见彩虹的成功感,而不是一种机械的忙碌的工作。
5 最后,也是每一个软件人员都十分关心的问题,什么时候给我们换一个快点的机器呀。一个好一点的机器
比可能比更高一点的工资更具备吸引力,对公司来讲也是更划算的。(效率和人员流动上,呵呵)
1 写出用户级的需求用例。在现在的需求调研中,更多的是把客户提出的需求用流程图的方式表达。但是
在给客户讲解的时候效果不是很好,主要存在以下问题:
1)流程图不适合描述分支很多的流程。分支过多,将导致流程图十分复杂,不具有可读性。
2)流程图的受众比较少。在实际的业务业务调研中,面对的用户往往是系统的使用者,而不是作为
技术人员的维护和开发者,由于不具备相关技术背景,因此这些人在阅读流程图的时候,往往觉的眼花缭乱,更不要说提什么修改建议了。这将会使很多本应在需求调研阶段发现的问题,遗留到了用户正式使用的时候,由此带来的损失不可估量。
3)由于流程图是一个粗线条的流程描述,因此许多客户提出的细节问题,需要以另外的方式进行记录
这可能会导致在设计阶段遗漏掉。如 系统使用这在使用时的心态,等等
2 采用用例和流程的结合形式来描述客户的需求,原因如下:
1)由于用例采用自然语言描述,所以任何人可以轻松的进行阅读。
2)在一定格式的辅助下,用例描述不必受流程分支多少的约束。
3)采用自然语言描述,可以详细的描述处用户的使用细节,这些细节可能会对这个项目的开发起着
决定作用。
4)加入流程图,让具有相关背景知识的人迅速的了整个流程的全貌。如果分支不是很多流程图
还是可以画的十分简洁易懂的。
5)好的用例对后期的设计,开发,测试都是很有帮助的。甚至可以直接作为客户的培训素材
3 如何写用例
1)写用例需要结合用例图,用例图可以让用例的读者了解整个系统提供的功能,和与其他系统的关系。 这样可以使读者的在阅读用例时,在一个限定的范围内思考问题。
2)用例的格式大体上可以分为前提条件,主成功用例,扩展。当然,作者可以丰富用例的格式,这里
仅仅是一个最简单的框架。
3)由于是在需要阶段的用例,因此用例尽量用轻松的语调来写用例。你甚至可以把用例当作一片散文来写。这里需要注意的是,在写用户级用例的时候需要把系统当作一个黑盒,不要去描述系统内部是如何工作的
此时作者一定要以一个客户的角度来考虑问题,来描述系统。
4)用例可以也可以想写函数是的写一些通用性比较强的模块,以便其他用例可以复用。如用户身份验证模块。
5)在写用户级的用例时候,对用户使用系统的细节需要描述,如使用者的心态。这可能决定着用户易用度的设计。
6)在写用例的时候一定需要用完整的主谓宾来写。及谁,在做什么
4 用例描述仅仅是对用户需求一个梳理的过程,我们还需分析出其中的主要实体,和他们的关系,在分析
的过程中可能会对产生新的疑惑,可以和客户及时沟通。当然在设计的过程中,也可以继续和客户沟通
但是,客户方不一定能够随时协调到合适人员,这将导致项目的推后。因此,在集中讨论期间
多做一些分析,乃至设计(原型的设计),可以大大减少后期的工作了量,提高客户满意度。用例,分析,和原型 可以是在需求期间一个小的迭代周期。
5 在讨论需求的时候,最好是以集中会议的形式进行,参会者应为 相关领导,系统将来的实际使用者
,技术把关人员。为什么者样作,和如何利用其中的微妙关系,需要大家自己去体会,去琢磨。呵呵
用了几年java 了,突然想学习c++ ,昨天用了一天的时间疯狂的学习了一天c++ 基础知识,发现感觉还不错,不过精验告诉我,学编程语言一定要实践,在这里指记录了一些学习中的点滴。
1 const 与volatile 的用法
1 const
#include<conio.h>
#include<iostream.h>
//行参数指向const 类型变量的指针
void display_c(cons int * pi)
{
cout<<"display_c:"<<*pi<<endl;
}
//行参为普通类型变量的指针
void display(int *pi)
{
cout<<"display_c:"<<*pi<<endl;
}
//const 类型变量
const int i1=1;
//error i1=3;
//const 类型变量的指针
int i2=2;
const int * pi2=&i2;
//error *pi2=3
// const 指针
int * const pi3=&i3;
*pi3=5;
// error *pi3=&i4 可以赋予不同的值,但是不可一指向不同的变量
//指向const 内容的const 指针
const int * cosnt pi5=&i5;
2 sizeof 返回某个便赖宁嘎或数据类型的长度
3 引用
1 引用变量
int i=1;
int & r_i=i;
5 名空间
1 namespace
namespace car
{
int model;
int length;
int width;
}
namespace plane
{
int model;
namespace size
{
int lenth;
int width;
}
}
namespace car //添加名空间的成员
{
char * name;
}
namespqce c=car; //定义别名
int Time //外不变量属于全局名空间
car::length=3;
plane::size::length=70;
int Time=1996;
::Time=1997;
2 using
void main()
{
using namespace car;
length;
using namespace phane;
model;
}
6 new 与delete 运算符
double * pd; // define pointer variable
pd=new double; // allocate memory
if(pd!=null)
{
...
delete pd; // free memory
}
double1=null
* pds=new double[100];
if(pds)
{
....
delete[] pds;
}
如果是使用new 进行内存空间分配没有成功,则返回空指针null
释放一个数组分配的内存是,常常采用带[]的形式
7 void 指针 它指向一个地址值,但是不说名数据类型,可以使用void 指针创建一个通用的函数,在使用
的时候将指针类型转化成相应的具体类型。
void ShowHex(void *pv,int siae)
{
....
((unsigned char *)pv)[i]
}
void main()
{
void *pv=null;
unsigned char c1=0x12;
pv=&c1;
ShowHex(pv,sizeof(c1));
}
9 typeid 运算符 用来求得变量或队形爱女嘎的数据类型,返回一个type_info 类型的对象,通过该对象
可以获取数据类型的名称
include<typeinfo.h>
int i;
const type_info &t0=typeid(i);
t0.name();
10 函数
1 模板函数
template<class T> T min(R &x,Tv&y)
{
return x<y?x:y;
}
2 指向函数的指针
int max(int x,int y)
{
...
}
int min(int x,int y)
{
...
}
int (* m_pfunction)(int,int);
void main()
{
m_pfunction=max;
(*m_pfunction)(2,3);
m_pfunction=min;
(*m_pfunction)(2,3);
}
11 类与对象
1 构在函数和析构函数
#include <iostream.h>
#include <string.h>
#include <conio.h>
class Book
{
private:
char * pBookName;
public:
int PageNum;
public:
Book(char * pBN=NULL);
~ B o o k ( v o i d ) ;
void SetBookName(char * pBN);
int GetBookName(char * pBN,unsigned int MaxSize);
} ;
Book:Book(char *PBN)
{
cout<<"构造函数"<<endl;
pBookName=null;
if(oBN!=null)
{
pBookName=new char[strlen(pBN)+1];
if(pBookName!=null)
strcyp(pBookName,pBN);
}
}
Book::~Book()
{
delete[] pBookName;
}
void Book::SetBookName(char * pBN)
{
if(pBookName!=null)
delete[] pBookName;
pBookName=new char[strlen(pBN)+1];
if(pBookName!=null)
strcyp(pBookName,pBN);
}
int Book::GetBookName(char * pBN,unsigned intmaxSize)
{
if((pBookName!=null))&&(MaxSize>strlen(pBookName))
{
strcpy(pBN,pBookName);
retrun strlen(strlen(pBookName));
}
}
// 使用
Book b1;
b1.SetBookName("test");
Book b2(test1);
2 对象的引用参数传递
void Add(Book b)
void AddRef(Book & b);
3 静态成员变量 是一个公共变量
在初始化 的时候利用作用运算符:: 对私有类型的静态成员变量可以向公有类型的静态成变量一样赋值
但不能直接引用
3 const 类型成员函数与mutable
class CDate
{
public:
int year;
mutable int month;
CDate(int y=2000,int m=1)
{
year=y;
month=m;
};
int BetMonth() const ;//read only
void SetMonth(int m);// write only
}
void CDate::SetMonth(int m)
{
month=m;
}
void main()
{
CDate d1;
}
在const 类型的成员函数定义中,不可一直接或简介的修改普通类型的成员变量
如果象修改const 类型对象的成员函数,可以使用关键字mutable 对该成员变量进行修改
5 对象的初始化与初始化行
将参数类表中的数值赋予成员变量时,不仅可以在构造函数的函数体中进行,以阿宽衣在初始化行中进行
在初始化处惊醒初始化的情况有:
1 分层类的构在函数可以调用它的任何一个子对象的构造函数
2 对常量const 类型的成员变量的初始化必须在初始化行上
3 对于引用类型的成员变量的初始化必须在初始化行上
class CPoint
{
public:
int x,y;
CPoint(int ax=0,int ay=0)
{
x=ax;
y=ay;
}
};
class CRect
{
private:
CPoint low_right;
CPoint up_left;
public:
int & CenterX;
const int CenterY;
CRect(int x1,int y1,int x2,int y2,int &x3,int y3)
:up_left(x1,y1),low_right(x2,y2),CenterX(x3),CenterY(y3)
{
}
};
void main()
{
int cx=5;
int cy=6;
CRect r1(1,2,3,4,cx,cy);
}
6 拷贝构造函数
拷贝构造函数与普通构造函数的差别在与棋参数类表,参数列表中有一个对象,该对象的数据类型是
本类的一个引用,而且一般情况下,该对象还应该是一个const 类型的对象。
如果在类的定义是不是显示的定义一个拷贝函数,则编译器会自动的定义一个拷贝构造函数
class CPoint
{
public:
int x,y;
CPoint(int m_x=0,ubt m_y=0); // default constructor
cPoint(const CPoint &c); //copy consrucotr
};
CPoint::CPoint(int m_x,int m_y)
{
}
CPoint::CPoint(const CPoint &c)
{
x=c.y;
y=c.x;
}
void main()
{
CPoint c1(1,2); //invoke default constructor
CPoint c2-c1; // invoke copy constructor
}
7 template class
template<class t,int Size>class Array // template class
{
private:
T arr[Size];
int CurSize;
public:
Array(T * date,int n)
{
CurSize=n<Size?n;Size;
for(int i=0;i<CurSize;i++)
{
Arr[i]=data[i];
}
}
}
void main()
{
int i1[10]={1,2,3,4,5,6,7,8,9};
Array<int,6>array_i1(i1,i0);
}
1 友员类和友员函数
#include <iostream.h>
#include<string.h>
#include<conio.h>
class SoftWareEngineer; //先对SoftwareEngineer 类进行显示说明一下
class Computer // 定义Computer 类
{
private:
int Price;
public:
Computer(int p){Price=p};
friend class SoftwareEngineer; //将友员类载这里声明
frined void Judge(Computer &c,SoftwareEngineer & s) //友员函数
};
class SoftwareEngineer
{
int Salary;
char Name[20];
public:
SoftwareEngineer(int s,char *n //构造函数)
{
Salary=s;
strcpy(Name,n);
}
int GetComputerPrice(Computer &c){return c.Price} //访问Computer 的思友变量
friend void Judge(Computer &c,SoftwareEngineer & s) //友员函数
};
//判断一个软件工程师是否可以用一个月的薪水买的器一台电脑
void Judge(Computer &c,SoftwareEngineer &s) //桥友员函数
{
if(c.Price>s.Salary)
cout<<"软件工程师"<<s.Name<<"的一个月薪水买不起一台电脑"<<endl;
else
cout<<"软件工程师"<<s.Name<<"的一月薪水买的起一台电脑"<<endl;
}
void main()
{
Computer c1(100);
SoftwareEngineer s1(120,"user1");
Judge(c1,s1);
SiftwareEngineer s2(80,"user2")
Judge(c1,s2);
getch();
}
2运算符重载
#include<iostream.h>
#include<conio.h>
#include<iomanip.h>
class TValue{
private:
int value;
public:
TValue(int i){value=i}
//成员函数重载运算符
TValue operator!();
TValue operator+(TValue & rv);
// 友员函数重载运算符
friend ostream & operator<<{ostream & os,TValue & rv};
}
TValue Tvalue::operator!()
{
return TValue(!value);
}
TValue TValue:operator+(TValue& rv)
{
return TValue(value+rv.value);
}
ostream & operator<<(ostream & os,TValue rv)
{
os<<setw(5)<<rv.value;
return os;
}
void main()
{
TValue v1(3),v2(5);
cout<<
}
3 类的派生和继承
1class Box{
public:
int width,height;
void SetWidth(int w){width=w};
void SetWidth(int h){height=h;};
};
class TColorBox::public Box{
public:
int color;
void SetColor(int c){color=c;};
};
void main(){
TColorBox cb;
cb.SetColor(255); //声明非继承类的对象
cb.SetWidth(100);//声明继承类的对象
cb.SetHeight(100); //声明继承类的对象
}
2 不能被继承的成员
构造函数,析构函数,用户定义的新操作符,用户定义的赋值操作,友员关系
3 构造函数,析构函数的调用顺序
class A{
int a,b,c;
public:
A(int x,int y,int z)
{
a=x;
b=y;
c=z;
}
};
class B{
int d;
public :
B(int xx):A(xx,xx+1,xx+2)(d=xx);//内联构造函数
B(int x,int y,int z,int xx);//非内联构造函数
B:B(int x,int y,int z,int xx):A(x,y,z)
{
d=xx;
}
}
实例
class Currency
{
poublic:
double par_value;
Currency(){per_value=0.0;}
Currency(double d){per_value=d;}
Currency(Currency &rc){par_value=rc.par_value;}
Currency & operator={Currency & c}
{
par_valuc=c.par_value;
return * this;
}
Currency & operator+(Currency & c)
{
par_value+=c.par_value;
return *this;
}
}
//人民币
class RMB:public Currency
{
public:
RMB():Currency(){};//调用派生类的构造函数前,需要调用器基类的工造函数
RMB(double d):Currency(d){};
RMB(Currency& c):Currency(c){};
RMB(RMB& rmb):Currency(rnb){};
friend ostream& operator<<{ostream& os,RMB& rnb};//派生类的附加功能
};
ostream& operator<<{ostream& os, RMB& rmb} //output 运算符不能是一个类的成员函数
{
os<<"¥"<<setiosflags(ios::shwopoint|ios:fixed)<<setprecision(2)rmb.par_value;
return os;
}
void main()
{
RMB r_income(5000);
RMB r_balance;
r_balance=r_income=r_expense;
cout<<"income"<<r_income<<endl;
}
4 将iostream 运算符重载
1)ostream & operator<< (ostream &os,const Triangular & ths)
{
os<<"("<<rhs.beg_pos()<<","<<rhs.length()<<")";
rhs.display(rhs.length(),rhs.beg_pos(),os);
}
ouutput 运算符不能够设计成member function
2)istream& operator>>(istream &is,Triangular &rhs)
{
char ch1,ch2;
int bp,len;
//输入 ch1='(',bp=3,ch3=',' len=6
is>>ch1>>bp>>ch2>>len;
rhs.beg_pos(bp);
rhs.length(len);
rhs.next_reset();
return is;
}
Triangular tris;
cin>>tri2
4 虚基类
载继承关系中,同一基类被继承多次,不仅会引器歧异,而起可能浪费空间
class A
{
public:
int value;
};
class B:public virtual A(); //虚基类 编译器只产生一个基类版本。如果不定义为virtual 编译器不知到调用那个value 了,当然
class C:public virtual A();// 也可以return B::value;
class D:public b.public c
{
public
int GetValue(){return value;}
};
void main()
{
D dd;
dd.GetValue();
}
5 多态形,和虚函数
class TFirst
{
public virtual void Display();
};
void TFirst::Display()
{
cout<<"first "
}
class TSecond:public TFirst
{
public:
virtual void Display();
};
void TSecond::Display()
{
cout<<"second"
}
void Display(TRist * pFirst)
{
pFisrt=>Display();
}
void main()
{
TFirst * pFirst=new TFirst;
TSecond * pSecond=new TSecond;
pFirst->Display();
pSecond->Display();
Display(pFirst);
Display(pSecond);
delet pfirst ;
delet pSecond;
getch();
}
c++ builder 中的集合的
1 集合的概念基本
Set<type,minval,maxval>
Set<char,'A','C'> s1
tydefef Set(char,1,255) UPPERCASet;
UPPERCASESet s1;
s1<<'A'<<'B'<<'C';
sysset.h 直接包含载vcl.h 中
2 集合的操作
#include<iostream>
#include<system.hpp>
#include<conio.h>
using namespace std;
typedef Set<char,'B','Z'> UpperSet;
typedef Set<char,'a','z'> LoverSet;
typeder Set<char,'a','j'> HalfLowerSet;
void set_example()
{
LowerSet ae,ae2,ac,de;
UpperSet AE,AE2,AC,DE;
HalfLowerSet aj;
}
异常处理
1 c++ 的异常处理
#include <iostream.h>
#include <conio.h>
class Crange
{
public:
int index;
CRange(int i){index=i;}
}
class CString
{
char a[100];
int len;
public:
CString(char * s)
{
Len=strlen(s);
strcpy(a,s);
}
char & operator[](int i)
{
if(i>0 && i<len) return a[i];
else throw CRange(i);
}
void DisplayNoCatch(CString & s)
{
int j;
for(j=0lj<20;j++)
cout<<s[j]<<""endl;;
}
int DisplayHasCatch(CString & s)
{
try{
DisplayNoCatch(s);
}catch(CRange r)
{
cerr<<r.index<<endl;
}
return 99;
}
}
2 多路捕捉
#include<iostream.h>
#include<conio.h>
void MultiException()
{
int i;
double d;
int no;
cout<<"(>0 and <5)";
cin>>no;
tyr
{
switch(no)
{
case 1;
throw 123;
break;
case 2:
throw i;
break;
case 3:
throw d;
break;
case 4:
throw "Error";
break;
default:
cout<<"error";
}
}
catch(int ie)
{
cout<<"int"<<endl;
}
catch(double de)
{
cout<<"double"<<endl;
}
catch(char* se)
{
cout<<"char"<<endl;
}
}
3 bcb中的异常类
1)却省vcl 异常处理 无try catch 自动处理
int i=4,j=0;k;
k=i/k;
//下一句永远不会执行
ShowMessage(k);
2) 引发vcl 异常类
try{
}
catch(Exception &e)
{
ShowMessage(e.,Message);
}
不能引发如int double 等简单类型的异常
3) c++ 异常处理
try
{
throw 2222;
}
catch(int ErrorCode)
{
ShowMessage(ErrorCode);
}
}
4 单一捕捉异常
try{
k=10/0;
}catch(EDivByZero & E)
{
MessageDlg()
}
5 捕捉所有异常
try
{
}catch(...) or(EExternalException &E)