积分规则 网站地图 帮助中心    
嵌入式软件 单 片 机 DSP 存储器 传感控制 光电显示
嵌入式硬件 CPLD/FPGA SOPC AD/DA 接口电路 模拟设计
I C设计 通信产品 汽车电子 电源产品 消费电子 数控系统
工业控制 军工/航天 安防产品 医疗电子 计算机外设 测试测量
供应 I C
求购 公司库

  IC 求购 销售 公司 论文 DATASHEET 参考设计 论坛
当前位置: 电子技术 >> 嵌入式软件 >> 综合技术
  相关分类: LINUX | WINCE | UC/OS | Bootloader | 下载 | VXWORKS | 网络协议 | JAVA | 汇编 | 驱动设计 | Symbian | XP Embedded | Nucleus | 新产品 | 相关文章 | 综合技术 |
Palm OS上的 C++ 程序设计
 
作者:未知   来源:CSDN电子杂志社区    点击数:884   更新时间:2007-1-27
您可以添加到网摘 让更多人关注此文章:

    

为什么我要考虑这个问题?

    作为一个长期从事 Palm OS 开发的人员,我见证了 Palm OS 的成熟和开发技术的变化。几年前,开发人员很关心内存空间(堆栈空间)的问题,因此尽量写小型、紧凑的代码。随着应用程序可用内存的增加,内存再也不是开发人员最担心的问题了。几年前,当 Metrowerks 开始允许开发人员使用 C++ 编程时(有一些限制),包括我本人在内的一些开发人员由于“代码膨胀”而不去使用它。那时候,由于设备上有限的可用空间,一些人认为面向对象/C++ 编程带来的价值不足以抵消它所造成的开销。我看到很多关于 C 和 C++ 的争论,认为 C++ 增加了开销。而在我看来,C++ 会增加开销只是个感觉问题。

    从那时起,事情有了很大的变化。新的设备带有大量的内存,这使我不得不重新考虑使用 C++。去年,当我正在编写后来的 Mark/Space Mail 软件的时候,有机会使用了 Brian Hall 开发的一些 C++ 类库。虽然这些类库并不像 POL 那样丰富,而且还没有把计算机课上教授的所有 C++ 技术都用上,但它确实开阔了我的眼界,使我意识到在不同的应用程序中反复使用这些类是多么的简单。

    象其它编程语言一样,使用 C++ 同样有优缺点。我见过一些商业代码,它们的作者认为所有程序都必须用 C++ 实现。我认为这些开发人员是刚刚从大学的计算机系毕业的学生,想在一个 Palm OS 程序中把从学校学到的每一样东西都用上。我觉得在 Palm OS 上这样使用C++ 并不是一个较好的方法。Palm OS 编程某些部分很好地使用了 C++,而有些部分并不使用。相反,我看到一些代码使用非常简单的C++ 特性来组织函数,并且可以很容易地访问到这些函数的公共变量。当然,肯定有开发人员不同意这个观点。如果代码由于继承、虚函数等变得太复杂而无法理解的话,那么可能就不太适合使用 C++ 了。我并不是想成为一个 C++ 专家,C++ 中的很多特性(比如,模板)我都还没有使用过。但是,由于从事了大量的 Palm OS 和 C++ 的程序设计,我知道即使是对 C++ 最基本的使用,也能通过代码重用来加快开发速度。

    我发现在Palm OS 应用程序中使用 C++ 比使用 C 有如下主要优点:

    代码重用。大多数开发人员都编写过多个 Palm OS 应用程序,这些程序之间有很多相同的部分。没有理由一遍又一遍地重新编写相同的代码。 一个bug 一经修正,所有使用这个类的应用程序都会被修正。反之,如果一个类出现一个 bug,那么所有使用它的应用程序也会同时出现此 bug。在我的某些开发中使用了基于 TCP/IP 协议的类库,只要修正了主要类中的错误,就会影响所有使用它的应用程序。例如:Mark/Space Mail 和 Mark/Space Online 都使用了一个公共的 TCP 类,这样,一个 bug 的修正将同时影响这两个产品。

    数据和函数封装。我总是教导你们,在你们的应用程序中不应该使用全局变量。然而这种做法并不实际,所以我会限制全局变量的使用,这样能提高代码的可读性,也更容易维护。把近似的功能封装成一个类,能提高代码的可读性。
在 Palm OS 和其它平台上使用 C++ 还有其他的优点,上面只是我个人喜欢使用 C++ 的原因。随着 Palm OS 设备上可用内存的增加,我没发现使用 C++ 有什么坏处。

    用 C 写过多个数据库程序的人都会知道,要一遍又一遍地重写那些访问数据库的常用函数是多么枯燥。毫无疑问,你肯定会把那些主要的数据库代码一遍又一遍地复制、粘贴。这时,使用 C++ 还是比较完美的解决方案。当第一次见到数据库类的实现时,我想这是对 C++ 的最好使用。我这里有几个数据库类的实现,在这篇文章中,我将给出一个简单的数据库类,来演示在应用程序中使用 C++ 是多么容易的一件事。

    本文中的代码可以在任何开发环境中使用。这些代码是免费的,但还没有经过全面测试。写这篇文章的时候,我使用 gcc 在 Mac OS X 上测试过这些代码。

    让我们开始吧。Palm OS SDK 中的大部分示例代码都访问了一个或多个数据库。对数据库的访问遍布整个程序,而且每个程序用来访问数据库的函数都很相似。例如,示例 Mail 通过下面的代码来取得一条记录:

    Err MailGetRecord (DmOpenRef dbP, UInt16 index, MailDBRecordPtr r,

    MemHandle * handleP)

{

    MemHandle handle;

    MailPackedDBRecordPtr src;

    handle = DmQueryRecord(dbP, index);

    ErrFatalDisplayIf(DmGetLastErr(), "Error Querying record");

    src = (MailPackedDBRecordPtr) MemHandleLock (handle);

    if (DmGetLastErr())

        {

        *handleP = 0;

        return DmGetLastErr();

        }

    MailUnpackRecord (src, r);

    *handleP = handle;

    return 0;

}

    而示例 Address 的代码如下:

    Err AddrDBGetRecord(DmOpenRef dbP, UInt16 index, AddrDBRecordPtr recordP,

                  MemHandle *recordH)

{

    PrvAddrPackedDBRecord *src;

    *recordH = DmQueryRecord(dbP, index);

    src = (PrvAddrPackedDBRecord *) MemHandleLock(*recordH);

    if (src == NULL)

        return dmErrIndexOutOfRange;

    PrvAddrDBUnpack(src, recordP);

    return 0;

}

    你们也看到了,这两个函数做的事情实际上是一样的。但是,它们在错误检查时稍微有一点区别。我怀疑其中一个曾经修改过,而另一个却没有。如果这两个函数都被封装在类 Cdatabase 中,那么对其中一个的修改也会应用到另一个上。这样,就不必在几个项目之间查找相同的 bug,进行相同的修改。

    我编写过的所有数据库访问程序差不多都会用到以下几个简单的函数:打开、关闭、查询记录、创建记录、删除记录和排序。在对数据库进行处理时还会用到很多其他的函数,这里只是简单介绍一下除排序和创建记录之外的函数。我们使用基本的 Cdatabase 类和固有的 CmailDatabase 类来演示重用类十分容易。记住,这只是个示例,或许并不能直接用在您的程序中。另外,其他开发人员都有不同的编码风格,以不同的方式组织类。这里只是用示例来演示 C++ 类是如何简化开发过程的。只要编写完基本的 Cdatabase 类,所有的应用程序都可以使用它。创建这个类需要一些时间,但从这个类衍生其他类时会节省更多的时间。

    Cdatabase 类的头文件类似下列代码:

    #ifndef __CDatabase_h__

    #define __CDatabase_h__

    #define noRecordSelected 0xFFFF

    class CDatabase

{

    public:

        CDatabase(void);

        ~CDatabase(void);

        Err Open(UInt32 type, UInt32 creator, UInt16 mode, Char *name);

        Err RemoveRecord(UInt16 recordIndex);

        Err RemoveCurrentRecord(void);

    protected:

        UInt32      mType;

        UInt32      mCreator;

        Err     Create(Char *name);

    private:

        DmOpenRef   mDatabaseRef;

        UInt16      mCurrentRecordIndex;

        Err     QueryRecord(UInt16 recordIndex, void *recordP, MemHandle *recordHandle);

        Err     UnpackRecord(void *src, void *destination);

};
 
    #endif

    这个类的构造函数和析构函数都很直观。

    // CDatabase constructor

    CDatabase::CDatabase()

{

    mCurrentRecordIndex = noRecordSelected;

    mDatabaseRef = NULL;

    mType = 0;

    mCreator = 0;

}

    // CDatabase destructor

    CDatabase::~CDatabase()

{

    if (mDatabaseRef != NULL)

    {

        (void) DmCloseDatabase(mDatabaseRef);

    }

}

    如果数据库处于打开状态,析构函数会关闭它。在析构函数中关闭数据库并且确保删除用完的对象,这样可以保证数据库总能关闭。

    我发现在大多数情况下,当打开数据库时,如果数据库不存在,就需要创建一个。因此,Open 方法考虑了这一点,它会在数据库不存在的时候试图创建一个。

    // CDatabase open

    Err CDatabase::Open(UInt32 type, UInt32 creator, UInt16 mode, Char *name)

{

    Err err = errNone;

    if (type == 0 || creator == 0)

    {

        return dmErrCantFind;

    }

    mType = type;

    mCreator = creator;

    mDatabaseRef = DmOpenDatabaseByTypeCreator(type, creator, mode);

    if (mDatabaseRef == NULL)

    {

        err = DmGetLastErr();   

        // If we can't open the database because it doesn't exist, create it

        if (err == dmErrCantFind)

        {

            err = Create(name);

            if (err == errNone)

            {

                mDatabaseRef = DmOpenDatabaseByTypeCreator(type, creator, mode); 

                if (mDatabaseRef == NULL)

                {

                    err = DmGetLastErr();

                }

            }

        }

    }
 
    return err;

}

    // Create the database given a name

    Err CDatabase::Create(Char *name)

{

    Err err = errNone;

    if (name == NULL)

    {

        return dmErrCantFind;

    }

    err = DmCreateDatabase(0, name, mCreator, mType, false);

    return err;

}

    对于熟悉 Palm OS 数据库调用的开发人员来说,这些代码无需解释。这一段代码主要是试图以指定的类型和创建者打开数据库(当然,这一段代码没有处理需要访问一个或多个相同类型和创建者的数据库的情况,例如,从一组电子图书中读取数据)。这一段代码可以很好地用在 Address Book 和 Mail 程序中。

    所有使用数据库的应用程序都要访问数据库中的记录。您会记得,在以只读的方式检索记录时使用 Query 调用。Cdatabase 类的查询例程中,查询到记录后会把它“解压缩”。如 Address Book 和 Mail 应用程序的示例所示,数据库中的记录是以压缩格式保存的,这样可以节省空间。由于每个数据库以不同的方法对记录进行压缩和解压缩,所以我只创建了一个通用的解压缩例程,在 Address Book 和 Mail 程序中将由类覆盖。

    Err CDatabase::QueryRecord(UInt16 recordIndex, void *recordP, MemHandle *recordHandle)

{

    void    *src;

    Err     err = errNone; 

    mCurrentRecordIndex = noRecordSelected;

    if (mDatabaseRef == NULL)

    {

        return dmErrNoOpenDatabase;

    }

    *recordHandle = DmQueryRecord(mDatabaseRef, recordIndex);

    if (*recordHandle == NULL)

    {

        return dmErrNotValidRecord;

    }

    src = MemHandleLock(*recordHandle);

    if (src == NULL)

    {

        return dmErrIndexOutOfRange;

    }

    err = UnpackRecord(src, recordP);

    if (err != errNone)

    {

        MemHandleUnlock(*recordHandle);

    }

    mCurrentRecordIndex = recordIndex;

    return err;

}

Err CDatabase::UnpackRecord(void *src, void *dest)

{

    Err err = errNone;

    return err;

}

    我在基类中提供的最后一个方法用来删除记录。必须首先创建记录,然后才能删除。创建记录的方法留给读者作为练习。

    Err CDatabase::RemoveRecord(UInt16 inRecordIndex)

{

    Err err = errNone;

    if (mDatabaseRef == NULL)

    {

        return dmErrNoOpenDatabase;

    }

    err = DmRemoveRecord(mDatabaseRef, inRecordIndex);

    if (inRecordIndex == mCurrentRecordIndex)

    {

        mCurrentRecordIndex = noRecordSelected;

    }

    return err;

}

Err CDatabase::RemoveCurrentRecord(void)

{

    return RemoveRecord(mCurrentRecordIndex);

}

    这些函数并不复杂,却演示了如何在基类中添加简单的错误处理机制,这样就不至于整个程序都要进行同样的错误处理。你们在自己的代码里也执行了错误处理,是这样吗?由于 RemoveRecord 方法已经处理了数据库引用为空的情况,所以就不需要每次调用 DmRemoveRecord 的时候都去检查。

    现在基类创建完成,本文剩下的部分将给出一个简单的衍生类,这个类可以用在 Mail 应用程序中,并且在这个新类中可以使用一些调用。

    要建立 CmailDatabase 类,只需覆盖一个方法(在本例中为 UnpackRecord方法)。

    #ifndef __CMailDatabase_h__

    #define __CMailDatabase_h__

    #include "CDatabase.h"

    class CMailDatabase : public CDatabase

{

    private:

        Err         UnpackRecord(void *src, void *destination);

};

    #endif

    UnpackRecord 函数如下所示:

    Err CMailDatabase::UnpackRecord(void *inSrc, void *inDest)

{

    Err err = errNone;

    MailPackedDBRecordPtr src = inSrc;

    MailDBRecordPtr dest = inDest;

    char *p;

    dest->date = src->date;

    dest->time = src->time;

    dest->flags = src->flags;

    p = &src->firstField;

    // Get the "subject" field.

    if (*p)

        {

        dest->subject = p;

        p += StrLen(p) + 1;

        }

    else

        {

        dest->subject = p;

        p++;

        }
 
    // Etc.
 
    return err;

}

    正如你所看到的,只要很少的工作,就可以创建一个能打开数据库并访问记录的 Cm



相关文章
· 智能卡读卡器总体技术介绍[737]
· 使用Java编写Palm OS程序的解决方案[658]
· 三种嵌入式操作系统的分析与比较[761]
· 基于PALM OS的通讯系统论文[725]
· Palm OS应用程序的执行和调试[930]
热门评论排行
·VHDL设计中电路简化问题的
·ARM嵌入式系统基础教程(N
·江苏嵌入式Linux教育培训
·ARM处理器应用开发4步骤
·锐极LINUX驱动培训班定于

文章评论
    没有任何评论
*只显示最新10条评论。评论内容只代表网友观点,与本站立场无关。更多评论
发表评论
  * 请先[登陆]再进行评论,谢谢。
评分: 1分 2分 3分 4分 5分
内容: *
发帖须知:
一.所发文章必须遵守《互联网电子公告服务管理规定》;
二.严禁发布供求代理信息,公司介绍,产品信息等广告宣传信息;
三.严禁恶意重复发帖;
四.严禁对个人,实体,民族,国家等进行漫骂,污蔑,诽谤。
 
热点新闻 [更多]
 
严冬期如何发展半导体业 扩
2008年中国集成电路市场回顾与展望
分析师:亚洲芯片厂商库存远超预期
2008年基础电子业十大事件点评
Aptina并购智多微手机软件平台设
凌力尔特公司推出用于多核处理器的&n
安森美半导体任命麦满权为韩国及南亚区
Broadcom:半导体产业依然机会
飞思卡尔推i.MX51芯 
日立芯片守卫新年倒数计时晚会
 
热门下载 [更多]
 
[ PCB设计] Protel99教程下载
[ ] 手把手学单片机20个例
[ ] 单片机做的智能台灯
[ ] 单片机入门书
[ ] linux系统移植开发文档
[ ] IC卡的读写程序
[ ] 8051单片机C语言彻底应用
[ 常用软件] 555定时器电路设计软件V1.2
[ 常用软件] 51定时器计算软件
[ ] ARM处理器应用开发4步骤
 
论坛新帖 [更多]
 
低价专业PCB打样 双面板20...
深圳市天漠科技超低价供应atm...
深圳市天漠科技超低价供应ARM...
[推荐]2.5米精度,高灵敏度...
830实验箱+电脑没有并口...
[原创]平望科技助力自服终端国...
低价专业PCB打样 双面板20...
[原创]低价专业PCB打样 双...
Bootloader for ...
【有奖调查】08-09嵌入式开...

 
赞助商 [更多]
 

ICP许可证号:[粤 05056597]
联系电话:010-82517432 82517615 传真: 010-82517615

版权所有 Copyright © 2006 嵌入式技术网