编程经验:c++初学者编程要注意哪些


 编程人员不仅仅要有很强的逻辑思维,还要有严谨的工作态度,在编程中可能会遇到很多问题,有些你觉得没关系不用在意,当时就忽略掉了,当你完成好一个项目之后,经过测试出现很多的bug,这个时候悔之晚矣,也许你要花费2-3倍的时间才能找到问题所在。
    
    这些编程准则有一些是个人的编程经验,当然,我可没那么多经验,大部分都是各个大师总结出来的,e良师益友网小编就是整理一下。
    一、宏观:
    将C++视为C、面向对象C++、模版C++、STL C++组成的语言联邦。
    任何人不得添加任何东西到STL命名空间
    不要轻易忽略编译器的警告
    一定程度的使用测试驱动的开发方法
    软件实体(类、模块、函数)应该是可扩展的,但是不可修改的
    多采用敏捷的设计方法(个体和交互胜过过程和工具、可以工作的软件胜过面面俱到的文档、客户合作胜过合同谈判、响应变化胜过遵循计划)
    经常性的交付可以工作的软件,交付的时间间隔越短越好
    在整个项目开发期间,业务人员和开发人员必须天天都在一起工作
    围绕被激励起来的个人来构建项目
    在团队内部,多进行面对面的交流
    提倡可持续的开发速度
    使要构造的系统最简单(不要设计不需要的功能,不要过分设计)
    最好的架构、需求和设计出自于自组织团队
    每隔一段时间,团队会在如何才能更有效的工作方面进行反省,然后相应的对自己的行为进行调整
    结对编程是一种比较好的选择
    不能容忍重复的代码
    持续的对代码进行重构
    要做计划游戏
    高层模块不应该依赖于底层模块。二者都应该依赖于抽象
    尽可能的保证:抽象不应该依赖于细节,细节应该依赖于抽象(任何变量都不应该持有一个指向具体类的指针或引用;任何类都不应该从具体类派生;任何方法都不应该覆写它的任何基类中已经实现了的方法)
    每个编程单元尽可能的向使用者提供使用承诺:例如资源回收保证、数据一致性保证、无异常保证
    尽可能的在程序中处理所有可能的异常,而且尽可能的精细。(try...catch)
    应该让程序体面的退出:在出现非计划内问题时自动产生dump文件。(利用SetUnhandledExceptionFilter调用MiniDumpWriteDump)
    要先设计好类,建好各个类的文件,才能写代码。
    用pragma once代替h文件头
    二、类:
    让接口容易被正确使用,不易被误用
    设计class犹如设计type
    将成员变量声明为private
    尽量不要让类支持隐式类型转换
    friend成员函数是类接口的一种表现方式,但能避免使用就尽量避免
    避免使用handles指向对象内部成分
    慎重使用inline(小函数的确该用inline,但是考虑到inline函数无法调试,所以应谨慎)
    确定public继承表现出is-a关系(即Liskov替换原则,永远可以用派生类取代基类)
    避免覆盖继承而来的名称(基类函数重载,派生不重载,则其他覆盖;派生重载基类函数,则基类函数覆盖;变量也可以覆盖)
    区别接口继承和实现继承(纯接口(virtual=0),接口+朴素实现(virtual=0+实现),接口+强制实现(non-virtual),以上为public继承,private继承全部是为了继承实现,而不继承接口)
    根据上一条,只要出现virtual,就尽可能让它=0(成虚基类)
    根据上上条,派生类不应该覆写non-virtual函数
    绝不重新定义继承而来的缺省参数值
    private继承意味着继承实现,是composition,实现的是has-a逻辑。protected继承尽量少用。两种继承在设计层面完全没有意义,只是实现层面的代码重用。
    凡是独立的对象都必须有非0大小(空对象会安插一个char)
    一个类只负责一件事
    一个类只提供一种内聚的接口(不应该让用户依赖于他们不使用的方法)
    类内部的类型定义尽量放在public,否则不能作为返回值
    类中的大属性都应该用智能指针(或返回STL时应使用move语意)
    凡是类内私有变量加m前缀,凡事类似私有仿函数,加or后缀
    静态成员初始化函数用静态类替代,可以顺便用个functor
    四大函数(构造函数、拷贝构造、赋值、析构)
    若有多态继承体系,基类析构函数尽量声明为virtual
    如果类内new了对象,并且该类负责delete,则必须要定义拷贝构造函数和赋值操作符。
    若不想使用编译器自动生成的函数,就该默认拒绝(将其声明在private或protected)
    别让异常逃离析构函数,C++不喜欢析构函数吐出异常
    绝不在构造函数或析构函数中调用virtual函数(当然其他函数调用virtual可以实现template method等有趣的模式)
    拷贝函数应该确保拷贝了对象内所有成员和基类部分
    不要以某个拷贝函数去实现另外一个拷贝函数(一个是copy函数,一个是copy assignment函数),应该把共同部分放在第三个独立函数
    三、函数:
    尽量将函数参数声明为const
    另operator =返回一个*this的引用,并且在operator =中处理自我赋值
    函数参数的构造顺序不确定,所以不要在函数参数中执行new操作,或将多个函数参数都用函数来表示(否则若一个发生异常,其他有可能不会执行)。
    尽量用传递const 引用代替传值
    non-member,none-friend函数有封装性好,跨类型操作等能力,因此在需要的时候没有必要局限于把函数全部放到类里的传统规则。
    若所有参数都需要类型转换,请为此采用non-memeber函数(典型的是双目操作符重载)
    凡是需要对指针参数做提领操作,都需要检查是否为BULL
    发布版程序维持程序的勉强工作比crash更好;debug版让程序尽量crash。(例如对NULL指针的提领)

   
    四、代码布局:
    头文件尽量不要包含头文件,尽可能的用前置声明。
    类的声明和实现应该分开(template没有export可以用时得谨慎)
    若必须要在同一文件中交叉引用定义,则可考虑类中类
    所有类都该有自己的名称空间。
    五、杂项:
    尽可能用const enum inline 替换#define
    尽可能使用const
    确定对象调用前已先被初始化。(包括基本对象、类对象、类成员)
    使用引用计数型智慧指针时,应该注意RCSPs无法打破环状引用
    成员使用new和delete时应采用相同的形式
    尽可能延后变量定义式的出现时间(Singleton)
    尽可能少用转型操作,(reinterpret_cast,static_cast,const_cast太危险,dynamic_cast效率太低),但如果要转型,尽量用C++的*cast转型关键字。
    输入流的getline尽量用全局getline函数。(可以用string)
    不用临时变量,方便调试
    轻量级对象应尽量多用临时对象
    引用只用于立即处理,若需要长久保存,则得用堆
    数值类型转化要用显式,尽量避免用隐式
    六、模版:
    大项目中,尽量不要使用显式实例化
    尽量使用包含模型组织模版代码
    模版函数所有重载版本的声明都应位于被调用位置之前
    模版函数的重载应只改变参数数或显式指定模版参数
    模版参数两个>之间要求有空格
    不得不用template不能采用分离模型时,对成员模版函数的特化必须在类外部用inline特化,否则会有重复定义问题。
    模版构造函数不能在类内定义,必须要在类外定义。如果有模版构造函数的需求,尽量全部在类体外const inline定义(支持export的话可以考虑)
    七、资源管理:
    一旦使用了资源,必须归还,并且谁用谁归还(包括内存、文件描述器、互斥锁、图形界面中的字型和笔刷、数据库连接、网络socket)
    用对象来管理资源
    资源取得的时机便是初始化的时机。
    在资源管理类中小心coping行为
    在资源管理类中提供对原始资源的访问
    RAII
    八、STL:
    可以用for_each来避免显示使用迭代器
    std内部是深拷贝
    九、设计模式:
    全局唯一对象尽量用Singleton,而不是用static
    可以用non-virtual Interface的方式实现template method
    用tr1::funtion实现strategy