EffectiveC++笔记 第1章

Chapter 一:

条款 1 :视 C++为一个语言联邦 (P41 )

c++其实可以视为有四个部分:

  1. C
  2. Object-Oriented C++
  3. Template C++
  4. STL

条款 2:尽量以 const ,enum , inline 替换 #define ( P43 )

可翻译为“宁可以编译器替换预处理器”

(大写名称通常用于宏,const一般用单词开头大写)

Specially: class里的常量很多时候声明为static const xxx (至多有一份实体) 然而这只是个声明

对于class专属static常量,只有声明而没有定义式,要想取此常量地址的话,则必须有定义式,可以这么做:

假设你是在头文件的class Num里定义了静态常量static const int Num = 5,则可以在实现文件中提供此常量的定义:

const int Num::Num; 因为在头文件定声明时已经赋了初值,所以定义时不用赋值

值得注意的是,有些编译器不支持声明期间赋值,你可以在定义式中赋初值 (事实上,比较鼓励这种做法)

如果你的编译器不允许声明期间赋初值,而class里又有声明数组大小这种操作,那么可以用enum枚举类型代替:

`Class GamePlayer{`
`private:`
`   enum { NumTurns = 5 };`
`   int scores[NumTurns];`
`   ……`
`};`

事实上,enum成员不能被取到地址

另外,会有长得像函数的define,很多时候它们会带来麻烦,这时最好采用template inline函数:

扫描二维码关注公众号,回复: 1040803 查看本文章
template <typename T>
Inline void callWithMax(const T& a,const T& b)
{
    f(a>b?a:b);
}

条款 3: 尽可能使用 const

const char* const p = greeting; const pointer,const data 如果const出现在星号左侧,表示被指物是常量,在右边表示指针自身是常量。若在左侧就不能改变被指物的值,在右侧就不能改变指针指向地址的值

函数声明式返回值为const的话,可以很好应对这种情况:

if(返回值 = xxx) ,在这里,你可能将==写成了=,因为是赋值操作,是不能应用于const之上的

在class成员函数结尾加上const表明不允许此函数改动任何成员变量

如果某些成员函数即使在const成员函数内也可能会因为具体实现被修改,可以使用mutable关键字

public:
    …
    std::size_t length() const;
private:
    char* pText;
    mutable std::size_t textLength;
    mutable bool lengthIsValid;

std::size_t CTextBlock::length() const
{
    if(!lengthIsValid){
        textLength = std::strlen(pText); //现在你可以在const函数里修改成员值了
        lengthIsValid = true; //现在你可以在const函数里修改成员值了
    }
    return textLength;
}

条款 4: 确定对象被使用前已被初始化

记住,在c++中,读取未初始化的值会导致不明确的行为,最佳操作是:在使用对象之前将它初始化。
对于内置类型,最好手工初始化:
例如: int x = 0;
const char* text = “A C-style string.”;
double d;
std::cin>>d; 以读取input stream的方式初始化

对于内置类型以外的东西,责任交给构造函数身上:将每个成员初始化。

注意:
XXX(string name, int age){
this->name = name;
this->age = age;
}
这种叫做赋值,不叫初始化,这会导致对象带有你指定的值,不是最佳做法
初始化是指成员变量初始化动作发生在进入构造函数本体之前,时间更早(比进入默认构造函数时间还要早)

所以一种较佳写法是,使用成员初始化列表来初始化:
XXX(string name, int age):name(name),age(age){……}(这样似乎效率更高)
原因是用构造函数会先赋初值,然后再赋用户指定的值

我们可以规定成员初始化都用初始化列表

Important:
若有成员变量是const或引用(references)的话,它们就一定需要列表初始化,而不能被赋值

为了避免忘记这种特殊情况,最好的做法是都用成员初始化列表,它往往比赋值更高效

但是有时这种操作会使代码看起来不太美观,你就可以偷偷将一些“赋值表现得和初始化一样好”的变量改用赋值操作

Specially:
初始化次序取决于成员变量声明次序,也就是说,即使你在初始化列表里打乱了顺序,依旧按照声明顺序进行初始化

现在来关心一下static类型:
一般来说,在函数内部的static对象都叫做”local-static”,以外的叫做”non-local-static”
Local-static对象只会在函数调用之后才会被构造出来
而non…是在main后构造出来

现假设有两个cpp源文件,各自的类里有一个non-local-static对象,其中一个的初始化动作会使用到另一个static,但是被使用的对象可能还未初始化,此时会发生错误

此时可以用一个小设计:将两个类各自的non-local-static搬到属于自己的函数里,将它们变成local-static,函数会返回对象的引用。此操作保证了调用函数时,此函数包含的static对象一定会被初始化。很棒的是,只要你还未调用此函数,就不会有构造与析构成本
For example:

class FileSystrem{
    ……
    FileSystem& tfs(){
        static FIleSystem fs;
        return fs;
    }
    ……
};

//这种函数很简单,通常会成为inlining候选人

猜你喜欢

转载自www.cnblogs.com/1Kasshole/p/9092832.html