posts - 29, comments - 0, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

摘自:《高质量的 C++编程》 

 

8.2.1重载与覆盖
    成员函数被重载的特征:
1)相同的范围(在同一个类中);
2)函数名字相同;
3)参数不同;
4)virtual关键字可有可无。
    覆盖是指派生类函数覆盖基类函数,特征是:
1)不同的范围(分别位于派生类与基类);
2)函数名字相同;
3)参数相同;
4)基类函数必须有virtual关键字。
 
 
“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
 
 
如下示例程序中:
1)函数Derived::f(float)覆盖了Base::f(float)。
2)函数Derived::g(int)隐藏了Base::g(float),而不是重载。
3)函数Derived::h(float)隐藏了Base::h(float),而不是覆盖。
 
#include <iostream.h>
    class Base
{
public:
    virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
void g(float x){ cout << "Base::g(float) " << x << endl; }
            void h(float x){ cout << "Base::h(float) " << x << endl; }
};
    class Derived : public Base
{
public:
    virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
void g(int x){ cout << "Derived::g(int) " << x << endl; }
            void h(float x){ cout << "Derived::h(float) " << x << endl; }
};

  
void main(void)
{
Derived d;
Base *pb = &d;
Derived *pd = &d;
// Good : behavior depends solely on type of the object
pb->f(3.14f); // Derived::f(float) 3.14
pd->f(3.14f); // Derived::f(float) 3.14
 
// Bad : behavior depends on type of the pointer
pb->g(3.14f); // Base::g(float) 3.14
pd->g(3.14f); // Derived::g(int) 3        (surprise!)
 
// Bad : behavior depends on type of the pointer
//行为(即方法的调用)依赖于指针的类型
pb->h(3.14f); // Base::h(float) 3.14      (surprise!)
pd->h(3.14f); // Derived::h(float) 3.14
}

 

posted @ 2007-05-28 15:45 change| 编辑 收藏

引用就是别名。
引用的一些规则如下:
1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。

(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。

“引用传递”的性质象“指针传递”(能够改变原来的参数值),而书写方式象“值传递”。

posted @ 2007-05-28 15:45 change| 编辑 收藏

  最近找工作,几乎所有的公司有要考C/C++ ,没有办法,呵呵~~~~只有慢慢的开始 拾起 C++ 来,好久没有弄过C++ 了,基本语法都忘得差不多了,呵呵~~~今天看了《高质量的 C++编程》,现摘下一些话,已备忘记查找。

  

C++内存分配方式
内存分配方式有三种:
(1)      从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
(2)      在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3)      从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
EG:
           用函数返回值来传递动态内存
 
char *GetMemory3(int num)
{
    char *p = (char *)malloc(sizeof(char) * num);
    return p;
}
void Test3(void)
{
    char *str = NULL;
    str = GetMemory3(100); 
    strcpy(str, "hello");
    cout<< str << endl;
    free(str); 
}

 但是下面这种事有问题的:

    
char *GetString(void)
{
    char p[] = "hello world";
    return p;   // 编译器将提出警告
}
void Test4(void)
{
char *str = NULL;
str = GetString(); // str 的内容是垃圾
cout<< str << endl;
}

 

这里强调不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡,如上面的示例。  用调试器逐步跟踪Test4,发现执行str = GetString语句后str不再是NULL指针,但是str的内容不是“hello world”而是垃圾。

 

如果把示例7-4-4改写成示例7-4-5,会怎么样?
 

char *GetString2(void)
{
    char *p = "hello world";
    return p;
}
void Test5(void)
{
    char *str = NULL;
    str = GetString2();
    cout<< str << endl;
}

示例7-4-5 return语句返回常量字符串
 

函数Test5运行虽然不会出错,但是函数GetString2的设计概念却是错误的。因为GetString2内的“hello world”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块

 

posted @ 2007-05-28 15:44 change| 编辑 收藏

在jxta里面,所有的资源都是通过广告来发布的,这里的服务业不例外,在这里的服务  发布里面有两个很总要的概念,

• ModuleClassAdvertisement— defines the service class; its main purpose is to formally document the
existence of a module class. It is uniquely identified by a ModuleClassID.
• ModuleSpecAdvertisement — defines a service specification; uniquely identified by a ModuleSpecID.
Its main purpose is to provide references to the documentation needed in order to create conforming
implementations of that specification. A secondary use is to make running instances usable remotely,
by publishing any or all of the following:
• PipeAdvertisement
• ModuleSpecID of a proxy module
• ModuleSpecID of an authenticator module
• ModuleImplAdvertisement — defines an implementation of a given service specification. 

这里的 ModuleClassAdvertisement  仅仅用来告知服务的存在,对等点若是需要访问该服务的话,还需要发现与之关联的 ModuleSpecAdvertisement  广告信息。

而这里的 ModuleSpecAdvertisement  则包含了 对等点节点 要访问该服务所需要的所有相关信息,比如:管道广告信息,通过它才能够连接上所需要的服务。

服务端的代码示例大抵如下:

创建发布 ModuleClassAdvertisement  :

ModuleClassAdvertisement mcadv = (ModuleClassAdvertisement)AdvertisementFactory.newAdvertisement(ModuleClassAdvertisement.getAdvertisementType());
   mcadv.setName("JXTAMOD:JXTA-EX1");
   mcadv.setDescription("Tutorial example to use JXTA module advertisement Framework");
   ModuleClassID mcID = IDFactory.newModuleClassID();
   mcadv.setModuleClassID(mcID);//通过mcID来建立ModuleClassAdvertisement 与ModuleSpecAdvertisement 的联系

discovery.publish(mcadv);
 discovery.remotePublish(mcadv);

创建发布 ModuleSpecAdvertisement :

ModuleSpecAdvertisement mdadv = (ModuleSpecAdvertisement)AdvertisementFactory.newAdvertisement(ModuleSpecAdvertisement.getAdvertisementType());

mdadv.setName("JXTASPEC:JXTA-EX1");
   mdadv.setVersion("Version 1.0");
   mdadv.setCreator("sun.com");
   mdadv.setModuleSpecID(IDFactory.newModuleSpecID(mcID));
   mdadv.setSpecURI("http://www.jxta.org/Ex1");

PipeAdvertisement pipeadv = null;
   try {
    FileInputStream is = new FileInputStream("pipeserver.adv");
    pipeadv = (PipeAdvertisement)AdvertisementFactory.newAdvertisement(MimeMediaType.XMLUTF8, is);
    is.close();
   } catch (Exception e) {
    System.out.println("failed to read/parse pipe advertisement");
   }

mdadv.setPipeAdvertisement(pipeadv);

discovery.publish(mdadv);
 discovery.remotePublish(mdadv);
  myPipe = pipes.createInputPipe(pipeadv);

在客户端,通过不断的查找广告(分本地查找和远端查找)来 获取 所需要服务的广告信息,通过它就可以获取 管道信息 来创建管道以达到通讯的目的。客户端代码示例大抵如下:

Enumeration en = null;
  while (true) {
   try {
    /* let's look first in our local cache to see if we have it! We try to discover an adverisement which as the (Name, JXTA-EX1) tag value
    en = discovery.getLocalAdvertisements(DiscoveryService.ADV,"Name","JXTASPEC:JXTA-EX1");
    //  Ok we got something in our local cache does not
    //  need to go further!
    if ((en != null) && en.hasMoreElements()) {
     break;
    }
    //  nothing in the local cache?, let's remotely query
    //  for the service advertisement.
    discovery.getRemoteAdvertisements(null,DiscoveryService.ADV,"Name","JXTASPEC:JXTA-EX1",1, null);
    //  The discovery is asynchronous as we do not know
    //  how long is going to take
    try { // sleep as much as we want. Yes we
     //  should implement asynchronous listener pipe...
     Thread.sleep(2000);
    } catch (Exception e) {}
   } catch (IOException e) {
    //  found nothing! move on
   }
   System.out.print(".");
  }
  System.out.println("we found the service advertisement");
  //  Ok get the service advertisement as a Spec Advertisement
  ModuleSpecAdvertisement mdsadv = (ModuleSpecAdvertisement)en.nextElement();
  try {
   //  let's print the advertisement as a plain text document
   StructuredTextDocument doc = (StructuredTextDocument)mdsadv.getDocument(MimeMediaType.TEXT_DEFAULTENCODING);
   StringWriter out = new StringWriter();
   doc.sendToWriter(out);
   System.out.println(out.toString());
   out.close();
   //  we can find the pipe to connect to the service
   //  in the advertisement.
   PipeAdvertisement pipeadv = mdsadv.getPipeAdvertisement();
   //  Ok we have our pipe advertiseemnt to talk to the service
   //  create the output pipe endpoint to connect  to the server
    myPipe = pipes.createOutputPipe(pipeadv, 10000);
   }

   //  send the message to the service pipe
   myPipe.send (msg);

posted @ 2007-05-28 15:41 change| 编辑 收藏

JXTA 双向通讯 可以通过 JxtaServerSocket /JxtaSocket和 JxtaServerPipe/JxtaBiDiPipe 来实现 其实现的过程非常的类是我们做FTP的时候所采用的ServerSocket/Socket机制,也就是服务断监听客户端连接的原理。以JxtaServerPipe为例,在服务端:

serverPipe = new JxtaServerPipe(eg.netPeerGroup,eg.pipeAdv);

serverPipe.setPipeTimeout(0);然后就是服务端的循环监听客户端的连接

while (true) {
   try {
    JxtaBiDiPipe bipipe = serverPipe.accept();
    if (bipipe != null ) {
     System.out.println("JxtaBidiPipe accepted,sending 100 messages to the other end");
     //Send a 100 messages
     sendTestMessages(bipipe);
    }
   } catch (Exception e) {
     }
  }

在客户端则是通过JxtaBiDiPipe 来进行连接服务断的操作:pipe = new JxtaBiDiPipe();

pipe.connect(eg.netPeerGroup,null,eg.pipeAdv,
    180000,
    // register as a message listener
    eg);当有消息来得时候就会触发 pipeMsgEvent(PipeMsgEvent event)事件

posted @ 2007-05-28 15:41 change| 编辑 收藏

最近在JXTA的官方网站上面下载了一份JxtaProgGuide看了看,练习了一下上面的示例程序~~~~大抵上感觉的编程的模式就是:

//Method to start the JXTA platform.

NetPeerGroupFactory factory  = new NetPeerGroupFactory();//这是默认的创建的一个组。
        netPeerGroup = factory.getInterface(); 

然后就是获取相应的服务如发现服务(用于发现和发布广告,那么什么是广告呢?

Advertisements 就是:
All JXTA network resources— such as peers, peer groups, pipes, and services —are represented by an
advertisement. Advertisements are language-neutral meta-data structures represented as XML documents. The
JXTAprotocols use advertisements to describe and publish the existence of a peer resources. Peers discover
resources by searching for their corresponding advertisements, and may cache any discovered advertisements
locally.),管道服务(用于创建IN/OUT管道来接发消息,这里创建OutPipe管道会触发outputPipeEvent(OutputPipeEvent event) 事件,而当 Inpipe 管道有消息到来的时候会触发pipeMsgEvent(PipeMsgEvent event)事件 ,而这里In/Out 管道间的联系则就是广告的用处了,它通过PipeID标示出所用的管道来建立他们之间的联系而不至于混乱。对等点间的通讯就要依赖于它了)

discovery = netPeerGroup.getDiscoveryService();
 rdv = netPeerGroup.getRendezVousService();

然后是通过所获取的服务来注册监听器在通过发现事件来获取一个广告,或者是直接通过服务来获取一个广告,总之目的就是要获取一个所要找的广告 。如监听:

discovery.addDiscoveryListener(this);此时需要implements DiscoveryListener接口,

实现里面的 discoveryEvent(DiscoveryEvent ev) 方法,然后通过 DiscoveryEvent  获取广告

DiscoveryResponseMsg res = ev.getResponse();
  // Get the responding peer's advertisement
  PeerAdvertisement peerAdv = res.getPeerAdvertisement();

或者是直接通过服务来获取一个广告

discovery.getRemoteAdvertisements(null, DiscoveryService.GROUP, null, null, 5);

在要不就是i通过一个发现服务来发布一个广告,这里的发布广告分本地发布和远程发布

discoveryService.publish(Adv,PeerGroup.DEFAULT_LIFETIME,PeerGroup.DEFAULT_EXPIRATION);
 discoveryService.remotePublish(Adv,PeerGroup.DEFAULT_EXPIRATION);

 那么一个对等点如何才能够加入一个Group呢

StructuredDocument creds = null;

// Generate the credentials for the Peer Group
   AuthenticationCredential authCred = new AuthenticationCredential( grp, null, creds );
   // Get the MembershipService from the peer group
   MembershipService membership = grp.getMembershipService();
   // Get the Authenticator from the Authentication creds
   Authenticator auth = membership.apply( authCred );
   // Check if everything is okay to join the group
   if (auth.isReadyForJoin()){
    Credential myCred = membership.join(auth);
    System.out.println("Successfully joined group " + grp.getPeerGroupName());
    // display the credential as a plain text document.
    System.out.println("\nCredential: ");
    StructuredTextDocument doc = (StructuredTextDocument)myCred.getDocument(new MimeMediaType("text/plain"));
    StringWriter out = new StringWriter();
    doc.sendToWriter(out);
    System.out.println(out.toString());
    out.close();
   }

 

posted @ 2007-05-28 15:40 change| 编辑 收藏

最近也算是闲来无事, 于是乎开始玩玩 J2ME 无线编程,找了一本书翻翻,然后下载了一个 ME插件和诺基亚的模拟器 做了几个小例子,发觉其实也没有什么,感觉基本上可以说是windows 窗口编成的一个缩版(新手愚见,高手见效了)。就是所谓的添加一个form(类是面板),在给他添加几个TextField(类是文本框),添加相应的响应事件,然后就是在不同的现实面板间切换,做一些业务上的事情,至于手机上的存储嘛,基本上是依赖于 DataStore 这个类的,用它获取recordID在获取记录等等,也就是通常的数据库操作(增删改查)都依赖于它。至于手机的联网通讯则是依赖于Connector这个对象了,通过它 既可以创建一个Socket连接,也可以创建一个HTTP连接,只是连接的URL 字符串不同罢了。如:

conn =  (HttpConnection)Connector.open(URL.toString());

想想它的难点的话应该是如何的精简代码,高效的利用存储空间,和网络通讯的安全吧。因为这毕竟是一个手持设备的局限性问题。这方面就确实没有什么经验了,希望有高手的经验共享。呵呵~~~我只是感觉她的编程模型还是蛮好理解的。没有什么神秘可言。我翻的那本书比较的老了,也许现在的MIDP2.0 已经有了很大的改观也说不来噢,个人没有怎么了解。不过在J2ME的开发包里面有好多的Demo,但是现在是没有什么时间去研究它了,呵呵~~~以后再说吧,欢迎大家批评指正。

posted @ 2007-05-28 15:40 change| 编辑 收藏

以前的同步操作 基本上都是用到 synchronised 关键字,类似代码如下:

synchronised(obj){

//dosomething...

}来做到同步,

在 JDK5.0  里面有这么一个对象,ReentrantLock,发觉她的加锁编程的方式非常的适合日常的加锁习惯,

EG:

package com.thread.synchronise;

import java.util.concurrent.locks.ReentrantLock;

public class SynchroTest extends Thread{
 private int count = 0;
 private final ReentrantLock lock = new ReentrantLock();
 
 public void run()
 {

//这里加了几次锁,在后面就的要相应的解锁 几次
     
lock.lock();  // block until condition holds
      try {      
       count++;
       System.out.println(" count = "+count);
       try {
    Thread.sleep(3000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
       System.out.println(" count = "+count);
      } finally {
      
lock.unlock();
      }
 }
 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  SynchroTest st1 = new SynchroTest();
//  SynchroTest st2 = new SynchroTest();
//  SynchroTest st3 = new SynchroTest();
  

//这里不能够调用   new Thread(st1).run();方法,否则就不是多线程的了
  new Thread(st1).start();
  new Thread(st1).start();
  new Thread(st1).start();
 }

}

如果该线程等待某暂时获取不到的资源,那么我们可以用Condition Object来避免死锁情况。
sufficientFunds = lock .newCondition();
如果条件不满足:
sufficientFunds.await();
这时线程就会释放锁并进入blocked状态,其他线程就有机会执行操作。当其他线程执行完后,就可通知等待的线程继续执行它的操作了:
sufficientFunds.signalAll();


posted @ 2007-05-28 15:39 change| 编辑 收藏

//解决二次提交问题(提交前)

          preSubmitValid(servletRequest,servletResponse);
          
//解决二次提交问题(提交)
    if(!submitValid(servletRequest,servletResponse))
     try
              {
               servletResponse.sendRedirect("public/repeatdeal.jsp");
               return null;
              }
              catch (Exception error)
              {
               servletRequest.setAttribute("errorMSG", "重复提交造成页面跳转出错:" + error.getMessage());
              }   
             
/**
         * 解决二次提交问题(提交前)

         * @param request
         * @param response
         */
        public void preSubmitValid(HttpServletRequest servletRequest,HttpServletResponse response)
        {
         counter = -1;
            servletRequest.getSession().setAttribute("submissioncount",
                    new Integer(counter));
            /**
             * 重要:

             * 通过调用 saveToken(request)方法,动态生成一个token,并且存放到session中,
             * 以便在以后可以在动态生成的页面中加入隐藏字段 <input type="hidden" name="org.apache.struts.taglib.html.TOKEN" value="动态值">
             * 只要调用了该方法,此后包含<html:form...>标签的页面中都会动态生成上面所说的隐藏字段。

             */
            this.saveToken(servletRequest);         
        }
        /**
         * 提交验证,检验是否是重复提交,如果重复提交跳转到统一处理页面
         * @param servletRequest
         * @param servletResponse
         * @return
         */
        public boolean submitValid(HttpServletRequest servletRequest,HttpServletResponse servletResponse)
        {
         counter += 1;
         servletRequest.getSession().setAttribute("submissioncount",new Integer(counter));
            if (!this.isTokenValid(servletRequest))
             return false;

            /**
             * 在认可了用户的合法提交后,一定要调用resetToken(request)重置token,这样session中就没有相应的token啦

             * 这样才能够保证用户再次提交相应数据时,能够检测出来。

             */
            this.resetToken(servletRequest);
            return true;         
        }                      

posted @ 2007-05-28 15:38 change| 编辑 收藏

以前用得的是hibernate3.0.5的版本~~~~而且关于queryfactory 的配置如下:

<prop key="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</prop>

因为数据量超出了10万条~~~~结果出现了 heap 溢出问题,想想了,也确实该溢出了,呵呵~~~

这种查询方式,是将所有的查询出来的结果以对象的形式进行缓存,如此巨大的数据,不把她给称爆炸才怪呢:)

查查hibernate 的文档,有关于大数据量的处理~~~,流程大抵如下:

Transaction tx = session.beginTransaction();

        String hqlDelete = "delete VbufferGis ";
        int deletedEntities = session.createQuery( hqlDelete ).executeUpdate();
        tx.commit();
        session.close();

测试运行出现如下异常:query must begin with SELECT or FROM ,文档是清清楚楚是这样写的嘛,怎么会出现这样的问题呢,是不是和我刚开始的时候一样觉得挺纳闷的,呵呵~~~原来是配置的问题,将上面的配置改为:

<prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</prop>

本以为这下是万事大吉了,呵呵~~~~问题有出来了,define class not foundexception :antlr.antlrexception

在网上授了一把,原来hibernate用她来解析 hql ,而我用myEclipse的时候,有没有导入那个包,自然有问题了,

于是将那个包导入,测试删除运行,一切ok!这下是真的万事大吉了吗?还没有,这也难怪我的多磨难了,呵呵

原来在进行待汉字的参数查询的时候出现了乱码现象,感觉挺奇怪的,百思不得其解,幸好有网络这个好东西,google了一下,^_^ 原来值需要换一个版本就ok了,呵呵~~~于是在取sourceforge上面取下了 hibernate-3.1rc2.zip,这下子就ok了!一切运行正常!!!虽然问题是解决了,原理缺不甚明白,有待学习。。。。

posted @ 2007-05-28 15:37 change| 编辑 收藏

仅列出标题
共3页: 上一页 1 2 3 下一页