这两天在学C++ Primer第五版的十二章动态内存和智能指针,看到定义StrBlob类这么一个例子,发现有些遗忘之前的知识,故写篇读书笔记的博客复习一下。附上书中代码(我在这里省略了std作用域)

//编译器会首先编译成员声明,然后再编译成员的函数体
class StrBlob{
public:
    typedef vector<string>::size_type size_type;

    StrBlob();   //默认构造函数
    StrBlob(initializer_list<string> il);  //构造函数

    size_type size() const { return data->size(); }  //size成员函数
    bool empty() const { return data->empty(); }  //empty成员函数
    void push_back(const string &t) {data->push_back(t);}  //push_back成员函数
    void pop_back();
    string& front();    //访问元素的函数声明
    string& back();
private:
    shared_ptr<vector<string>> data;   //声明data成员
    void check(size_type i, const string &msg) const;
};

如上述代码所示:
类中声明了指向vector<string>的shared_ptr指针类型的data成员;
通过data成员定义了size, empty, push_back这些成员函数;
定义一个默认构造函数和一个构造函数,构造函数接受了一个initializer_lIst<string>类型的参数il。</string></string>

类的成员函数

在第五版的第七章,P230

定义成员函数

常量成员函数

成员都必须在类的内部声明,dan的函数体可以定义在类内或者类外。

size_type size() const { return data->size(); }

参数列表之后的const修改隐式this指针的类型,表明this是指向常量的指针,也就是说这个成员函数不会对类对象的数据成员做任何改变。这种成员函数被称作常量成员函数

想要理解this指针,首先观察类的对象b1对size()成员函数的调用:

b1.size()

成员函数通过一个名为this的额外的隐式参数来访问调用它的对象,编译器负责把对象的地址传递给size的隐式形参this,上方的代码等价于

StrBlob::size(&b1.data)

也可以理解为

size_type size() const { return b1.data->size() }

默认情况下,this是指向类类型非常量版本的常量指针(PS:这里的类类型非常量版本不是很明白,理解的是对象是非常量的?)。既然是指针,那么this也遵循初始化规则,因此无法将this绑定到一个常量对象上。因为若常量对象与this初始化值不符,则会产生矛盾。所以默认情况下,无法在常量对象上调用普通的成员函数。当const关键字放在函数的参数列表之后,const表示this是一个指向常量的对象的指针,此时该函数可以被常量对象调用。这样的成员函数也被称作是常量成员函数
值得注意的是,常量对象以及对象的指针或引用都只能调用常量成员函数。

在类的外部定义成员函数

和其他函数一样,若在类内部声明,在外部定义,那么其定义与声明必须相匹配。即返回类型、参数列表和函数名需要保持一致。在外部定义时,加上类作用域。

string& StrBlob::front()
{
    check(0, "front on empty StrBlob");
    return data->front();
}

元素访问成员函数首先调用check,如果成功则继续利用底层vector的操作来完成自己的工作。

构造函数

概念

类通过一个或几个特殊的成员函数来控制其对象初始化的过程,这些函数就叫做构造函数

特点

①构造函数名字和类名相同
②没有返回值
③可以有多个构造函数,但是需要在参数数量和类型上有所区别
④不能被声明为const
⑤编译器只有发现类不包含任何构造函数时才会帮我们生成一个默认的构造函数。这也就是说一旦我们定义了其他的构造函数,必须再定义一个默认构造函数

默认构造函数

在参数列表后面加上default,例如

StrBlob() = default;

定义这个函数是因为我们需要其他形式的构造函数(原来函数也有工具人XD)。当编译器支持类内初始值时,可以这么用;不支持时就需要使用初始值列表了。

初始值列表

Note:通过初始值列表初始化对象时,对象的成员变量根据其声明顺序来进行初始化,而不是根据初始值列表顺序来初始化。
如P217的代码

Sales_data(const string &s, unsigned n, double p) : 
           booksNo(s), units_sold(n), revenue(p*n) {};

还有P433的代码

class TextQuery{
public:
    shared_ptr <vector<string>> file;
    ...
};
TextQuery::TextQuery(ifstream &is): file(new vector<string>)
{
    string text;
    while(getline(is, text)){
        file->push_back(text);
        int n = file.size()-1;
        ...
}


第一个例子中,花括号{}定义了函数体;
booksNo(s), units_sold(n), revenue(p*n)这部分称为初始值列表,为新创建的对象的一个或几个数据成员赋初值。
当没有其他任务时,函数体可为空。
第二个例子,对象的数据成员file是一个shared_ptr指针,为其分配内存空间。有个疑问就是,C++不推荐智能指针与普通指针混用,这里为什么不用make_shared?

大致内容就是这些,若是后续看到相关知识会加以补充。