Effective C++ 第一部分 让自己习惯C++

.

条款01 视C++为一个语言联邦

C++主要分为以下四个方面:

1、C

2、OOC++ 即面向对象:例如封装、继承、多态

3、Template C++ 即泛型编程

4、STL STL有自己的办事准则 当你使用时必须要遵守它的规定

条款02 尽量以const、enum、inline替换#define

即宁可以编译器替换替换预处理器

#define A 1.652

其实记号A可能根本就没被编译器看见,也许编译器开始处理源码时它已经被预处理器移走了。

解决方法为采用常量替换上述宏

const double A=1.652;
//两种特殊情况值得讨论

//1.定义常量指针 由于常量定义通常放入头文件 以便被包含 所以有必要将指针定义为常量
//其实是指 指针指向的对象是不变的 如

const char* const name="LBH";

//const修饰离自己近的 第一个const修饰char 代表是一个常量字符 
//第二个const修饰* 表示指针指向的方向是固定的

//2.class专属常量 将常量作用域限制在class内 必须让它成为class一个成员(private)
//若确保只有一个实体 还得加上static

class GamePlayer{
private:
    static const int Num=5;
    int score[Num];
};

//类似的有enum枚举
class GamePlayer{
private:
    enum{ Num=5; }
    int score[Num];
};
//enum类似于#define 如不能被取地址

#define一旦被定义 再之后编译过程中将一直有效 所以不能定义class常量,也没用封装性。

对于类似于函数的宏,最好用inline代替#define

inline:用于代码少、简单的函数

在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。

//无论何时写出这种宏 必须要加上小括号
#define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b))

//inline代替 利用模板 具有通用性
template<typename T>
inline void callWithMax(const T&,const T&){
    f(a>b?a:b);
}

条款03:尽可能使用const

const修饰原则: const永远修饰离自己近的!!!

char greeting[]="hello";
char* p=greeting;
const char* p=greeting;//non-const pointer,const data
char* const p=greeting;//const pointer,non-const data

除非确实有需要要改动参数,否则将它们声明为const

const成员函数:将const实施于成员函数的目的,是为了确认该函数可作用于const对象身上

class Screen {
public:
   char get() const;//函数后加上const
};

//若将成员成员函数声明为const,则该函数不允许修改类的数据成员 即无法赋值操作
class Screen {
public:
    int ok() const {return _cursor; }
    int error(intival) const { _cursor = ival; }
};
//当然 如果加上mutable 释放掉const函数的non-static,则可以改变
class A{
public:
    int change()const{
        i=2;//可以的
        return i;
}
private:
    mutable int i;
}

值得注意的是,把一个成员函数声明为const可以保证这个成员函数不修改数据成员,但是,如果据成员是指针,则const成员函数并不能保证不修改指针指向的对象,编译器不会把这种修改检测为错误。例如:

class Name {
public:
    void setName(const string &s) const;
private:
    char *m_sName;
};
 
void setName(const string &s) const {
    m_sName = s.c_str();      // 错误!不能修改m_sName;
 
    for (int i = 0; i < s.size(); ++i) 
        m_sName[i] = s[i];    // 不好的风格,但不是错误的
}

要注意:当const和non-const成员函数有着实际等价实现的时候,可以令non-const版本调用const版本避免代码重复,但是需要const_cast和static_const等完成转换。别用const调non-const!

class TextBlock{
public:
    const char& operator[](std::size_t position)const{
        return text[position];
    }

    char& operator[](std::size_t position){
        return const_cast<char&>(static_cast<const TextBlock&>(*this)[position])
        //*this从原始的TextBlock&转换成const TextBlock,才能调用const版本的operator函数
        //const_char<char&>则是从const operator的返回值中移除const
    }

private:
    std::string text;
}

 

条款04:确定对象被使用前先被初始化

永远在使用对象之前将他初始化,于内置类型,必须手工完成,对于其他东西,初始化责任落在构造函数上,确保每个构造函数都将对象的每个成员初始化。

用初始化列表代替赋值:如果成员变量是const或者&,则必须需要初值,而不能被赋值,所以:是采用初始化列表,往往比赋值高效。

初始化列表时最好按照形参顺序绑定,方便阅读!

class A{
public:
    A(const string& name,const string& address)
private:
    string thename;
    string theaddress;
}

A::A(const string& name,const string& address){
    name=thename;
    address=theaddress;//这些都为赋值 而非初始化
}
//直接初始化
A::A(const string& name,const string& address):thename(name),theaddress(address){}

为免除“跨编译单元之初始化次序”问题,用local static替换non-static local

通俗来说, local对象  ——> 有域限制的对象, 比如一个命名空间内,一个块内等等)受作用域限制)
non-local 对象 ——> main函数结束才结束,比如全局变量 不受作用域限制)

static 存在与 date区或者bbs区的变量, 不是 stack变量, heap变量等等。(知道程序完整结束才被收回)

综上所述, non-local static 变量就是  不受作用域限制 且  为static 的对象
所以当两个non-local static对象存在调用关系时,会引发问题。例如b的调用要用到a,此时a可能还未被初始化。

所以将其换位local static是必要的

例如:1.cpp

 
class eggs
{
   public:  void eggs()
   {   
       chicken().make_egg();
   }
}
 
eggs& egg()
{
    static egg a
     return a;
}

 2.cpp

class hen
{
    Public:  size_t make_eggs( );
}
 
hen& chicken()
{
   static hen ji;
   return  ji;
}


#include "1.cpp"
#include "2.cpp"
int main(){
    eggs egg();//合法了
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值