毕业后工作也快有两个月,试用期期间也没有太大的压力,工作日正常上班,平时住在公司,晚上加点班,整理整理学习到的知识。上班的感觉还不错,毕竟也有能力养活自己,比在学校的时候状态要好些,更容易约束自己。这里是不是也潜伏着很多Dotaer呢,毕业了,对DOTA的热情慢慢的淡下来了。咱还是安心的工作吧。
在学校的时候主要跟着导师学习嵌入式方面的一些知识,参与割草机项目的开发,每学期领着导师发的微薄的“工资”,两年半的时间很快,现在想想还是比较肤浅的,范围不是很广泛,使用C语言完成一些简单的功能,也不会考虑深层次方面的东西,例如:代码的优化上,内存的分配,代码的健壮性等。
进入进公司后,我被分配到了传感器网络部门,面对新的环境,咱也不虚,虽然技术不是很扎实,但是感觉前景还是有的。既来之,则安之嘛。我的直接上司在这公司已经有6年了,有着丰富的技术经验,我的目标就是要慢慢的榨干他,当然是榨干他的知识。来了2个月,感觉他人还不错,在分配了任务之后,会经常过来问问情况,我也不好意思老是问,怕一下子一大堆简单的问题吓到他,经常看到一些老员工很反感这样的新员工,咱还是在他不在的时候问baidu吧,实在不能解决的,我就记在本子上,有关于技术方面的,有关于需求方面的。用谦虚的口吻跟老员工交流还是挺受用的。
由于这个部门是用C++开发的,主要负责数据的通道和数据的处理转发,很多要用到面向对象的思想,类的继承等等,虽然在大学的时候学习过,但不曾有实质性的项目锻炼,那时候的时间都奉献给我的同学了。有失必有得嘛,至少还有几个玩的比较好的朋友。(在这里忽然想到句话:当你失去一些重要东西的时候,其实上天在告诉你,你已经得到了很多了。)在刚着手的时候,经常犯一些低级错误,其实,咱在毕业前好一段时间没认真的写过代码了。我觉得还是有必要记录下易错的知识点,免得以后再同一个地方在跌倒,也避免其他人走弯路。
先扯点从项目中得来的感受吧。这个部门不是在我来才成立的,然而它的目标也很明确,就是解决数据的通道和处理,主要是网络的通信,所以在软件架构上已经有一套体系,个人感觉写的不错,很多地方都体现了C++面向对象的特点,因此最近我也恶补了一些相关知识,好在我以前学习的不多,要不然我现在还有这感悟吗?(先找个以前不好好学习的借口)。通过类的继承,能够很好的适应不同的平台,这里指Windows和Linux上的,因为想让程序在linux上运行还不是特别的方便,可以现在Windows上测试通过,再弄到Linux上测试。相关的底层函数也已经封装了七七八八,对于我这个新码农而言,只要学会如何使用它们就行了,多看看他们以前写的代码,呵呵。
1)面向对象特点有三:其一封装,其二继承,其三多态。
① 封装防止了程序相互依赖性而带来的变动影响。最直观的是,一个类要控制另一个类里的数据成员时,不能直接对其操作,要通过相应的接口完成。当设计的好时,可以保证在面向对象模型下不会存在全局数据。
② 继承性是子类自动共享父类数据结构和方法的机制,这是类之间的一种关系。在软件开发中,类的继承性使所建立的软件具有开放性、可扩充性,这是信息组织与分类的行之有效的方法,它简化了对象、类的创建工作量,增加了代码的可重性。 例如在Windows和Linux中,它们对外的接口可以是一样的,只是在实现上会有所差异,相同的部分我们可以抽象出来,作为基类(父类)。而将类的细化作为子类。
③ 多态是指两个或多个属于不同类的对象,对于同一个消息(方法调用)作出不同响应的方式。多态则是为了实现接口重用,增强了软件的灵活性和重用性。
最近也看了博客园里很多大神的文章,也能学到一些知识,根据自己的情况,又在当当上买了三本书。
◎《设计模式:可复用面向对象软件的基础》这本书好像评论还不错。毕竟写代码不是难事,关键在于能不能设计出一个好的模式,嗯,我现在就缺这个。
◎《大话设计模式》,在网上搜索到一部分内容,写的很生动,容易理解,搭配着第一本看看吧。
◎《大象——Thinking in UML》注重软件的分析、设计与建模过程,软件江湖盛传的“UML第一书”,开发人员梦寐以求的“九阳真经”,真正助您打通软件开发“任督二脉”。希望看了它,我的“任督二脉”也能通一下。
好了,下面再简单的谈谈项目中常发生的错误吧。
2)第一个就是指针,类的指针,以前接触不多,这次就吃了大亏,先是不申请内存就使用,其实这点我也注意,但是往往理解的不彻底,例如:
A *a, *b; a=new A(); b=a;
当你看到这个知识点时,很好理解,指针是用来指向对像的。a指向类的一个对象,而b没有用new关键字,而是直接指向a这个对象。
其实,new跟指针没有关系。new是在堆上分配内存,作用域由开发人员确定。不new是在栈上分配内存,作用域由变量作用域确定。
ps:指针访问前,必须指向一段有效的内存,不管是堆的还是栈的。比如你上面的代码就是指向栈的内存。
再一个需要注意的是指针的作用域,例如:
char *GetMemory( void ) { char p[] = "hello world"; return p; } void Test( void ) { char *str = NULL; str = GetMemory(); printf( str ); }
其中一个错误是p[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期。
在项目中,刚开始我没有很好的理解生存期的意思,我就贴出一段代码来简单说明一下吧。
/******************************************************** 功能:返回没发送的任务中优先级最小的 ********************************************************/ CTaskInfo* CTaskMgr::GetLowPRI() { BOOL bFind=FALSE; CTaskInfo* pTaskInfo; for(DWORD i=0;i<MAX_TASK_COUNT && i<m_TaskCount;i++) { if(!m_TaskList[i]->HasSendFrame) { if(bFind) { if(m_TaskList[i]->PRI<pTaskInfo->PRI) { pTaskInfo=m_TaskList[i]; } } else { pTaskInfo=m_TaskList[i]; bFind=TRUE; } } } if(bFind) { return pTaskInfo; } return NULL; }
粗略一看,嗯?以上2个不是一回事吗?怎么第一个不行,第二个就行了呢?原来区别在于m_TaskList[i]是一个CTaskInfo*类型的模块变量,当return时,pTaskInfo指向的是一个堆,在没有用delete释放内存时是一直存在的,所以它是可以返回的。而上面的那个例子就不一样了,p是一个局部变量,在栈中,当函数执行完后,p就被回收掉了,所以返回是无效的。以前不认真思考的话还真是一知半解。
3)由于我做的项目中涉及到了网络多通道问题,所以要灵活使用消息队列,它是解决数据共享的,相当于一个缓存,由另一个线程再处理数据。再一个需要注意的是,对于多线程,有时候要注意使用锁机制。这里就不详细说了。
这次就先总结到这里吧,有的知识点不及时整理的话又要遗失在记忆的角落里拉。平时还要勤快点呢。知识是一点一点积累的,慢慢来。每天进步一点点。