春暖花开
雪化了,花开了,春天来了
posts - 149,comments - 125,trackbacks - 0
以前看过很多关于设计模式的书籍,但是没怎么用过,都想过眼烟云一般,烟消云散了,在我的脑海里无影无踪了。
近期有开始看起,想想这方面还是蛮重要的,抱着HeadFirst看起来了,不过是影印版,也权当一块练英语了。加油!

发现,如果不写出来,知识摆在那里依旧是死的知识,不能活跃在自己的脑海里。所以借此一角,发发我的小感知。
posted @ 2009-06-29 18:48 Sandy 阅读(187) | 评论 (0)编辑 收藏
今天解决了两个BUG,但是原因都是自身的原因。
第一个BUG是由于修改,一份代码发生了变化,另一份代码没有相应进行变化,导致了BUG的发生。可能你也很好奇为什么有两份代码呢?一个是加长版,一个是缩减版。主要是另一个地方只用到了一个功能,而这个功能又牵涉了一些小函数,都搬过去感觉有些臃肿。但是不搬过去就存在了这种情况,两个代码不统一。

不知道怎么解决这个情况,也只能维持现状,保持两段代码了。不过需要人为的维护代码了。

第二个BUG主要是细心的问题吧。new很隐蔽,导致没有释放,这样造成了内存泄露,进而引发了数据读取的异常。这个类似的BUG见过一些了。内存泄露还是一个值得注意的大问题。所以要好好检查一下代码。

就写这么多吧。
posted @ 2009-06-29 18:44 Sandy 阅读(163) | 评论 (0)编辑 收藏
1、接口类似于类,但接口的成员都没有执行方式,它只是方法、属性、事件和索引符的组合而已,并且也只能包含这四种成员;类除了这四种成员之外还可以别的成员(如字段)。
2、不能实例化一个接口,接口只包括成员的签名;而类可以实例化(abstract类除外)。
3、接口没有构造函数,类有构造函数。
4、接口不能进行运算符的重载,类可以进行运算符重载。
5、接口的成员没有任何修饰符,其成员总是公共的,而类的成员则可以有修饰符(如:虚拟或者静态)。
6、派生于接口的类必须实现接口中所有成员的执行方式,而从类派生则不然。

那么为什么还要有接口呢?
    主要原因是它是一种有效的契约。类有一些成员,不考虑把这些成员组合在一起,类只是一个拥有各种方法、字段和属性的列表,但为了能以某种方式使用类,必须知道类能执行那些功能,具体的操作就是声明执行一个或多个接口的类,类执行接口的方式是从接口中派生,再提供这个接口中定义的所有成员的执行方式。

摘自: http://www.cnblogs.com/ajayumi/archive/2008/06/10/1216746.html
posted @ 2009-06-26 17:32 Sandy 阅读(239) | 评论 (0)编辑 收藏

摘自:
http://www.cnblogs.com/randylee/archive/2007/07/19/824555.html
WM5以前的系统中一般都是使用的CEDB数据库,EDB是WM5中的新特性之一。为了改善应用程序的性能和长期可移植性,CEDB 已经被 EDB 所取代。EDB 利用了 SQL Mobile 使用的存储子系统,并且提供了明显优于 CEDB 的性能(尤其是在与持久存储区一起使用时)。因为 CEDB 提供了与 EDB 完全相同的函数集 ,所有函数都具有相同的名称和参数列表。但是EDB中也包含了CEDB中所没有函数,并且创建方法也不相同了,要比CEDB复杂。以下就是EDB的创建和使用法:

一。创建:
1。CeMountDBVol( );//创建卷
2。CeCreateDatabaseWithProps();//卷创建成功后创建EDB
3。CeCreateSession();//EDB创建成功后创建session,用于打开EDB
4。CeOpenDatabaseInSession();//打开EDB
创建EDB时前还要创建一个CEDBASEINFOEX对象,这个对象用于创建EDB中的info,用于设定EDB。
在打开时还要维护一个全局的HANDLE,在以后的操作中是要使用的

二。选择数据
1。CeSeekDatabaseEx();//定位所要找的数据
2。CeReadRecordPropsEx();//读出定位的数据
创建一个CEPROPVAL对象,将所要定位数据的条件传给这个结构。

三。插入数据
CeWriteRecordProps();//数据写入EDB
创建一个CEPROPVAL对象,或对象数组,将所要写入的数据传给这些对象。

四。删除数据
1。CeSeekDatabaseEx();//定位要删除的数据
2。CeDeleteRecord();//删除定位的数据

五。更新数据
所插入数据基本相同,就是将已有数据覆盖
1。CeSeekDatabaseEx();//定位所要找的数据
2。CeWriteRecordProps();//数据写入新数据到EDB覆盖原数据

六。关闭EDB
CloseHandle(打开时的句柄);

在这里关键是创建EDB时所选的参数,和对结构体的使用,这样才能正确定位数据,否则选择、更新、删除都无法实现。


另外, MSDN中也有相关的文章
EDB Database Support
http://msdn.microsoft.com/en-us/library/ms885373.aspx

一定要理解的清楚一些。
呵呵,加油。

posted @ 2009-06-26 13:48 Sandy 阅读(936) | 评论 (0)编辑 收藏
现在做的这个项目,需求总是不停的变,稀稀拉拉做了很长时间了。

最近终于快做完了,感觉有一个就是让自己能够以不变应万变,写一个可扩展的接口,能够应对各种不同的变化。

可扩展性,就要有前瞻性,这是我一个同事的口头禅,要有前瞻性,你能预测到这一点。

想想也很有道理。

所以写程序的时候,不要简单的为实现功能而实现,要考虑程序的可扩展性。
posted @ 2009-06-25 17:49 Sandy 阅读(199) | 评论 (0)编辑 收藏
写的程序还是有很多问题的,慢慢积累经验,积攒一些调试和修改BUG的经验,对以后还是很有裨益的。

看着改掉的一个个BUG,心里还是很有成就感的。

呵呵,继续加油。

虽然最近加班多一些,但是努力哈,就快看到黎明了,这只是最黑暗的时刻而已。
posted @ 2009-06-23 21:02 Sandy 阅读(201) | 评论 (0)编辑 收藏
今天一直很疑惑手机的语言,其实是对API函数GetSystemDefaultLCID的不解。

今天在实际中终于摸清楚了该值是怎么一回事,原来他取得是设置中区域设置中的语言标号,而非手机界面的语言标号。

怎么判断呢?

我是通过下面的方式进行的。

                        LCID lcid = GetSystemDefaultLCID();
                        WORD   PriLan   
=   PRIMARYLANGID(lcid);   
                        WORD   SubLan   
=   SUBLANGID(lcid); 

                        
switch (PriLan)
                        
{
                        
case LANG_CHINESE:
                            
{
                                
if (SubLan == SUBLANG_CHINESE_SIMPLIFIED)
                                
{
                                    MessageBox(GetForegroundWindow(), _T(
"simple chs"), _T("note"), MB_OK);
                                }

                                
else if (SubLan == SUBLANG_CHINESE_TRADITIONAL)
                                
{
                                    MessageBox(GetForegroundWindow(), _T(
"traditional chs"), _T("note"), MB_OK);
                                }

                            }

                            
break;

                        
case LANG_ENGLISH:
                            
{
                                MessageBox(GetForegroundWindow(), _T(
"English"), _T("note"), MB_OK);
                            }

                            
break;
                        
default:
                            
{
                                MessageBox(GetForegroundWindow(), _T(
"others"), _T("note"), MB_OK);
                            }

                            
break;
                        }

这个有什么作用呢?Mobile手机更改语言设置后,其实对手机显示的语言没有多大影响,只是提示框框,菜单什么的可能会出现指定的文字,排版什么的按这种语言。

那么界面显示的语言怎么获得呢?利用GetUserDefaultUILanguage,判断方式可同上。

不错吧!
posted @ 2009-06-18 16:38 Sandy 阅读(349) | 评论 (0)编辑 收藏
对于成员初始化列表,熟悉有不是很熟悉。什么情况下使用呢?心里还是发怵,说不出所以然来。

学习是王道,搜索是方法。有了网络就是好。

摘自:http://www.cnblogs.com/heyutao/archive/2009/05/22/1487081.html

成员初始化列表

类对象的构造顺序是这样的:
1.分配内存,调用构造函数时,隐式/显示的初始化各数据成员
        初始化阶段可以是显式的或隐式的,取决于是否存在成员初始化表。隐式初始化阶段按照声明的顺序依次调用所有基类的缺省构造函数,然后是所有成员类对象的缺省构造函数。
2.进入构造函数后在构造函数中执行一般计算

        计算阶段由构造函数体内的所有语句构成。在计算阶段中,数据成员的设置被认为是赋值,而不是初始化。

使用初始化列表有两个原因:

1.必须这样做:

        三种情况下需要使用初始化成员列表
        1)对象成员;
        2)const修饰的成员;
        3)引用成员数据;

(1)如果有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。

using namespace std;
class ABC
{
public:
    ABC(
int x,int y,int z):a(x),b(y),c(z){};
private:
  
int a;
    
int b;
    
int c;
}
;
class MyClass
{
public:
    MyClass(
int a,int b,int c):abc(a,b,c){}
private:
    ABC abc;
}
;

int main()
{
    MyClass o(
1,2,3);
    
return 0;
}

(2)当类成员中含有一个const成员时

(3)当类成员中含有一个引用时

#include<iostream>
using namespace std;

class ConstRef {
public:
    ConstRef(
int i);
    
void print();
private:
    
int a;
    
const int b;//const成员
    int &c;//引用
}
;

ConstRef::ConstRef(
int i):b(i),c(a)//含有一个const对象时,或者是一个引用时使用初始化成员列表
{
    a 
= i;       // ok
    
//b = i;         // 错误
    
//c = a;       // 错误
}

void ConstRef::print()
{
    cout
<<a<<endl;
    cout
<<b<<endl;
    cout
<<c<<endl;
}

int main()
{
    ConstRef o(
1);
    o.print();
    
return 0;
}


 

2.效率要求这样做:

类对象的构造顺序显示,进入构造函数体后,进行的是计算,是对他们的赋值操作,显然,赋值和初始化是不同的,这样就体现出了效率差异,如果不用成员初始化列表,那么类对自己的类成员分别进行的是一次隐式的默认构造函数的调用,和一次复制操作符的调用,如果是类对象,这样做效率就得不到保障。

注意:构造函数需要初始化的数据成员,不论是否显式的出现在构造函数的成员初始化列表中,都会在该处完成初始化,并且初始化的顺序和其在声明时的顺序是一致的,与列表的先后顺序无关,所以要特别注意,保证两者顺序一致才能真正保证其效率。

现在明白为什么要使用成员初始化列表了。

这里再强调一下类的初始化的顺序,应该是类成员变量的初始化不是按照初始化表的顺序被初始化的,而是按照在类中声明的顺序被初始化的。
这是摘自:Effective C++学习笔记:初始化列表中成员列出的顺序和它们在类中声明的顺序相同 http://www.cppblog.com/xczhang/archive/2008/01/22/41613.html

为什么会这样呢?我们知道,对一个对象的所有成员来说,它们的析构函数被调用的顺序总是和它们在构造函数里被创建的顺序相反。那么,如果允许上面的情况(即,成员按它们在初始化列表上出现的顺序被初始化)发生,编译器就要为每一个对象跟踪其成员初始化的顺序,以保证它们的析构函数以正确的顺序被调用。这会带来昂贵的开销。所以,为了避免这一开销,同一种类型的所有对象在创建(构造)和摧毁(析构)过程中对成员的处理顺序都是相同的,而不管成员在初始化列表中的顺序如何。

注意:上述内容不适用于static变量,static变量应该在类的构造函数前被初始化。



好文章拿来学习,请作者见谅哈!

posted @ 2009-06-18 13:33 Sandy 阅读(441) | 评论 (0)编辑 收藏
对于拷贝构造函数引用传递,似乎司空见惯,认为理所当然。但是被问起这个问题,的确是一片茫然,为什么呢?

去网上搜索了一下,的确有很多这方面的知识讲解。

我们先看一下CSDN上的一个帖子的回答:
简单的回答是为了防止递归引用。
具体一些可以这么讲:
 当一个对象需要以值方式传递时,编译器会生成代码调用它的拷贝构造函数以生成一个复本。如果类A的拷贝构造函数是以值方式传递一个类A对象作为参数的话,当需要调用类A的拷贝构造函数时,需要以值方式传进一个A的对象作为实参; 而以值方式传递需要调用类A的拷贝构造函数;结果就是调用类A的拷贝构造函数导致又一次调用类A的拷贝构造函数,这就是一个无限递归。

这个解释还是蛮具体的。
利用值传递的话,会导致递归引用。

还有一片文章也谈到了这个问题, 我觉得写得也非常好!

为什么拷贝构造函数必须为引用传递,不能是值传递?
链接地址:http://www.cnblogs.com/chio/archive/2007/09/14/893299.html

其中讲到了3个问题
1是拷贝构造函数的作用。
      作用就是用来复制对象的,在使用这个对象的实例来初始化这个对象的一个新的实例。
2是参数传递过程到底发生了什么?
      将地址传递和值传递统一起来,归根结底还是传递的是"值"(地址也是值,只不过通过它可以找到另一个值)!
i)值传递:
    对于内置数据类型的传递时,直接赋值拷贝给形参(注意形参是函数内局部变量);
    对于类类型的传递时,需要首先调用该类的拷贝构造函数来初始化形参(局部对象);如void foo(class_type obj_local){}, 如果调用foo(obj);  首先class_type obj_local(obj) ,这样就定义了局部变量obj_local供函数内部使用
ii)引用传递:
    无论对内置类型还是类类型,传递引用或指针最终都是传递的地址值!而地址总是指针类型(属于简单类型), 显然参数传递时,按简单类型的赋值拷贝,而不会有拷贝构造函数的调用(对于类类型).
3是在类中有指针数据成员时,拷贝构造函数的使用?
        如果不显式声明拷贝构造函数的时候,编译器也会生成一个默认的拷贝构造函数,而且在一般的情况下运行的也很好。但是在遇到类有指针数据成员时就出现问题了:因为默认的拷贝构造函数是按成员拷贝构造,这导致了两个不同的指针(如ptr1=ptr2)指向了相同的内存。当一个实例销毁时,调用析构函数free(ptr1)释放了这段内存,那么剩下的一个实例的指针ptr2就无效了,在被销毁的时候free(ptr2)就会出现错误了, 这相当于重复释放一块内存两次。这种情况必须显式声明并实现自己的拷贝构造函数,来为新的实例的指针分配新的内存。

问题1和2回答了为什么拷贝构造函数使用值传递会产生无限递归调用的问题;
问题3回答了回答了在类中有指针数据成员时,拷贝构造函数使用值传递等于白显式定义了拷贝构造函数,因为默认的拷贝构造函数就是这么干的。

这样我终于看明白了。作者写得的确好。



posted @ 2009-06-18 11:13 Sandy 阅读(606) | 评论 (0)编辑 收藏
摘自: http://www.cppblog.com/yearner/archive/2008/11/09/66447.html

对于智能指针,也只是听说而已,对深层的东西也不甚了解。昨日又重听这一字眼,想想多少也该了解一些。

浅谈C++的智能指针

        内存泄露是C++程序员都头疼的大问题。C++缺乏像JAVA、C#一样,拥有GC这么一项有利的武器,它将内存管理的部分权限交给了程序员。虽然GC的存在节约了开发、排错的时间与成本,但是C++为了追求运行速度而20年来坚决不予补充进其标准。(题外话:C++通过加大开发难度去换取执行速度的做法,在现在看来不知是否能给与正面的评价,还是留给将来再说吧。)

       从此,在堆上申请了内存忘了释放、所造成的内存泄露的问题就一直困扰着C++程序员。也许为了稍许弥补没有垃圾回收器所造成的开发门槛高,各大厂商开发的C++库中都像COM学习引入智能指针试图解决部分目前存在的问题。

       智能指针是存储指向动态分配(堆)对象指针的类, 用于生存期控制, 能够确保自动正确的销毁动态分配的对象,防止内存泄露。它的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。

        说到智能指针,我们一定要看看标准C++库提供的“搞笑的”智能指针:auto_ptr。

       标准库中提供了C++程序的基本设施。虽然C++标准库随着C++标准折腾了许多年,直到标准的出台才正式定型,网上评论C++标准库时都说:“在标准库的实现上却很令人欣慰得看到多种实现,并且已被实践证明为有工业级别强度的佳作。”但目前的标准C++中,只有一种独苗智能指针:std::auto_ptr。

        auto_ptr指针是一个RAII对象,它初始化时获得资源,析构时自动释放资源(生命期结束).它的缺点数不胜数:
1、auto_ptr要求一个对象只能有一个拥有者,严禁一物二主
2、缺少对引用数和数组的支持。
3、不可将auto_ptr对象作为STL容器的元素。C++标准明确禁止这样做,否则可能会碰到不可预见的结果。(这一条晕死一大片)。
4、auto_ptr在被复制的时候会传输所有权

        反正由此可见:标准库的智能指针就是无甚大用。

       在这样的情况下,C++标准委员会自然需要考虑引入新的智能指针。目前由C++标准委员会库工作组发起的Boost 组织开发了Boost系列智能指针。

        在Boost中的智能指针有五种: scoped_ptr,scoped_array,shared_ptr,shared_array,weak_ptr.

        前4种完全是针对标准库中的auto_ptr提出解决方案,如:scope_ptr是针对“auto_ptr在被复制的时候会传输所有权”这一弱点提出的。最后一种没见过,看名字像是弱引用智能指针,我怀疑是不是类似于JAVA中弱引用一样,有待进一步学习。

        还查到一篇:
 
       C++深度探索系列:智能指针(Smart Pointer) [一] 
        http://dev.csdn.net/develop/article/17/17530.shtm

        有空可以看看!


posted @ 2009-06-18 10:47 Sandy 阅读(352) | 评论 (0)编辑 收藏
仅列出标题
共15页: First 2 3 4 5 6 7 8 9 10 Last