C++ primer 第五版 第七章学习笔记
2018-01-20 22:33
495 查看
参考博客:http://blog.csdn.net/libin1105/article/details/48664019
7.1 定义抽象数据类型
定义类的成员函数 isbn combine bookNo
定义与类相关的非成员函数 add read print
1.类的基本思想是数据抽象和封装,数据抽象是一种依赖于接口和实现分离的编程(以及设计)技术。类的接口包括用户所能执行的操作:类的实现则包括类的数据成员、负责接口实现的函数体以及定义类所需的各种私有函数。
2.成员函数通过一个名为this的额外隐式参数来访问调用它的那个对象。当我们调用一个成员函数时,用请求该函数的对象地址初始化this。
3.C++允许把const关键字放在成员函数的参数列表之后,此时,紧跟在参数列表后面的const表示this是一个指向常量的指针。像这样使用const的成员函数被称作常量成员函数。
4.每个类都分别定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数。构造函数的任务是初始化类对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。
5.如果我们的类没有显式的定义构造函数,那么编译器回味我们隐式的定义一个默认构造函数。编译器创建的构造函数又被称为合成的默认构造函数。对于大多数类来说,这个合成的默认构造函数将按照如下规则初始化类的数据成员:
⑴如果存在类的初始值,用它来初始化成员
⑵否则,默认初始化该成员
6.在C++11新标准中,如果我们需要默认的行为,那么可以通过在参数列表后面写上=default来要求编译器生成构造函数。其中=default 既可以和声明一起出现在类的内部,也可以作为定义出现在类的外部。和其他函数一样,如果=default在类的内部,则默认构造函数是内联的;如果它在类的外部,则该成员默认情况下不是内联的。
7.2 访问控制与封装
1.在C++语言中,我们使用访问说明符加强类的封装性:
⑴定义在public说明符之后的成员在整个程序内可悲访问,public成员定义类的接口
⑵定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问,private部分封装了类的实现细节。
2.类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为它的友元。如果类想把一个函数作为它的友元,只需要增加一条以friend关键字开始的函数声明语句即可。
7.3 类的其他特性
1.mutable修饰一个可变数据成员,永远不会是const,即使它是const对象的成员。因此,一个const成员函数可以改变一个可变成员的值。
2.一个const成员函数如果以引用的形式返回*this,那么它的返回类型将是常量引用。
7.4 类的作用域
1.名字查找的过程:
⑴首先,在名字所在的块中寻找其声明语句,只考虑在名字的使用之前出现的声明
⑵如果没有找到,继续查找外层作用域
⑶如果最终没有找到匹配的声明,则程序报错
2.类的定义分两步处理
⑴首先,编译成员的声明
⑵直到类全部可见后才编译函数体
3.成员函数中使用的名字按照如下方式解析
⑴首先,在成员函数内查找该名字的声明。和前面一样,只有在函数使用之前出现的声明才被考虑。
⑵如果在成员函数内没有找到,则在类内继续查找,这时类的所有成员都可以被考虑。
⑶如果内类也没有找到该名字的声明,在成员函数定义之前的作用域内继续查找。
7.5 构造函数再探
1.成员的初始化顺序与它们在类定义中的出现顺序一致:第一个成员先被初始化,然后第二个,以此类推。构造函数的初始值列表中初始值的前后位置关系不会影响实际的初始化顺序。
2.一个委托构造函数使用它所属类的其他构造函数执行它自己的初始化过程,或者说它把它自己的一些职责委托给了其他构造函数。
[cpp] view
plain copy
//非委托构造函数
Sales_data(std::string s,unsigned cnt,double price):bookNo(s),units_sold(cnt),revenue(cnt*price){}
//委托构造函数
Sales_data():Sales_data("",0,0){}
Sales_data(std::string s):Sales_data(s,0,0){}
Sales_data(std::istream &is):Sales_data(){read(is,*this);}
3.在要求隐式转换的程序上下文中,我们可以通过将构造函数声明为explicit加以阻止。
关键字explicit只对一个实参的构造函数有效。需要多个实参的构造函数不能用于执行隐式转换,所以无须将这些构造函数指定为explicit的。只能在类内声明构造函数时使用explicit关键字,在类外部定义时不应重复。
4.聚合类使得用户可以直接访问其成员,并且具有特殊的初始化语法形式。当一个类满足如下条件时,我们说它是聚合的:
⑴所有成员都是public的
⑵没有定义任何构造函数
⑶没有类内初始值
⑷没有基类,没有virtual函数
7.6 类的静态成员
1.静态成员函数也不与任何对象绑定在一起,它们不包含this指针。作为结果,静态成员函数不能声明成const的,而且我们也不能在static函数体内使用this指针。这一限制既使用于this的显式使用,也对调用非静态成员的隐式使用有效。
静态成员可以作为默认实参。
静态成员存在于任何对象之外,被所有对象共享。
习题7.1
7.1 定义抽象数据类型
定义类的成员函数 isbn combine bookNo
定义与类相关的非成员函数 add read print
1.类的基本思想是数据抽象和封装,数据抽象是一种依赖于接口和实现分离的编程(以及设计)技术。类的接口包括用户所能执行的操作:类的实现则包括类的数据成员、负责接口实现的函数体以及定义类所需的各种私有函数。
2.成员函数通过一个名为this的额外隐式参数来访问调用它的那个对象。当我们调用一个成员函数时,用请求该函数的对象地址初始化this。
3.C++允许把const关键字放在成员函数的参数列表之后,此时,紧跟在参数列表后面的const表示this是一个指向常量的指针。像这样使用const的成员函数被称作常量成员函数。
4.每个类都分别定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数。构造函数的任务是初始化类对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。
5.如果我们的类没有显式的定义构造函数,那么编译器回味我们隐式的定义一个默认构造函数。编译器创建的构造函数又被称为合成的默认构造函数。对于大多数类来说,这个合成的默认构造函数将按照如下规则初始化类的数据成员:
⑴如果存在类的初始值,用它来初始化成员
⑵否则,默认初始化该成员
6.在C++11新标准中,如果我们需要默认的行为,那么可以通过在参数列表后面写上=default来要求编译器生成构造函数。其中=default 既可以和声明一起出现在类的内部,也可以作为定义出现在类的外部。和其他函数一样,如果=default在类的内部,则默认构造函数是内联的;如果它在类的外部,则该成员默认情况下不是内联的。
7.2 访问控制与封装
1.在C++语言中,我们使用访问说明符加强类的封装性:
⑴定义在public说明符之后的成员在整个程序内可悲访问,public成员定义类的接口
⑵定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问,private部分封装了类的实现细节。
2.类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为它的友元。如果类想把一个函数作为它的友元,只需要增加一条以friend关键字开始的函数声明语句即可。
7.3 类的其他特性
1.mutable修饰一个可变数据成员,永远不会是const,即使它是const对象的成员。因此,一个const成员函数可以改变一个可变成员的值。
2.一个const成员函数如果以引用的形式返回*this,那么它的返回类型将是常量引用。
7.4 类的作用域
1.名字查找的过程:
⑴首先,在名字所在的块中寻找其声明语句,只考虑在名字的使用之前出现的声明
⑵如果没有找到,继续查找外层作用域
⑶如果最终没有找到匹配的声明,则程序报错
2.类的定义分两步处理
⑴首先,编译成员的声明
⑵直到类全部可见后才编译函数体
3.成员函数中使用的名字按照如下方式解析
⑴首先,在成员函数内查找该名字的声明。和前面一样,只有在函数使用之前出现的声明才被考虑。
⑵如果在成员函数内没有找到,则在类内继续查找,这时类的所有成员都可以被考虑。
⑶如果内类也没有找到该名字的声明,在成员函数定义之前的作用域内继续查找。
7.5 构造函数再探
1.成员的初始化顺序与它们在类定义中的出现顺序一致:第一个成员先被初始化,然后第二个,以此类推。构造函数的初始值列表中初始值的前后位置关系不会影响实际的初始化顺序。
2.一个委托构造函数使用它所属类的其他构造函数执行它自己的初始化过程,或者说它把它自己的一些职责委托给了其他构造函数。
[cpp] view
plain copy
//非委托构造函数
Sales_data(std::string s,unsigned cnt,double price):bookNo(s),units_sold(cnt),revenue(cnt*price){}
//委托构造函数
Sales_data():Sales_data("",0,0){}
Sales_data(std::string s):Sales_data(s,0,0){}
Sales_data(std::istream &is):Sales_data(){read(is,*this);}
3.在要求隐式转换的程序上下文中,我们可以通过将构造函数声明为explicit加以阻止。
关键字explicit只对一个实参的构造函数有效。需要多个实参的构造函数不能用于执行隐式转换,所以无须将这些构造函数指定为explicit的。只能在类内声明构造函数时使用explicit关键字,在类外部定义时不应重复。
4.聚合类使得用户可以直接访问其成员,并且具有特殊的初始化语法形式。当一个类满足如下条件时,我们说它是聚合的:
⑴所有成员都是public的
⑵没有定义任何构造函数
⑶没有类内初始值
⑷没有基类,没有virtual函数
7.6 类的静态成员
1.静态成员函数也不与任何对象绑定在一起,它们不包含this指针。作为结果,静态成员函数不能声明成const的,而且我们也不能在static函数体内使用this指针。这一限制既使用于this的显式使用,也对调用非静态成员的隐式使用有效。
静态成员可以作为默认实参。
静态成员存在于任何对象之外,被所有对象共享。
习题7.1
#include <iostream> #include <string> using std::cin; using std::cout; using std::endl; using std::string; struct Sales_data { string bookNo; unsigned units_sold = 0; double revenue = 0.0; }; int main() { Sales_data total; if (cin >> total.bookNo >> total.units_sold >> total.revenue) { Sales_data trans; while (cin >> trans.bookNo >> trans.units_sold >> trans.revenue) { if (total.bookNo == trans.bookNo) { total.units_sold += trans.units_sold; total.revenue += trans.revenue; } else { cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; total = trans; } } cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl; } else { std::cerr << "No data?!" << std::endl; return -1; } return 0; }习题7.2
#ifndef CP5_ex7_02_h #define CP5_ex7_02_h #include <string> struct Sales_data { std::string isbn() const { return bookNo; }; Sales_data& combine(const Sales_data&); std::string bookNo; unsigned units_sold = 0; double revenue = 0.0; }; Sales_data& Sales_data::combine(const Sales_data& rhs) { units_sold += rhs.units_sold; revenue += rhs.revenue; return *this; } #endif习题7.5
#ifndef CP5_ex7_05_h #define CP5_ex7_05_h #include <string> class Person { std::string name; std::string address; public: std::string& getName() const { return name; } std::string& getAddress() const { return address; } }; #endif习题7.9
#ifndef CP5_ex7_09_h #define CP5_ex7_09_h #include <iostream> #include <string> class Person { std::string name; std::string address; public: const std::string& getName() const { return name; } const std::string& getAddress() const { return address; } }; std::istream& read(std::istream& is,Person& person) { is >> person.name >> person.address; if(!is) person = Person(); return is; } std::ostream& print(std::ostream& os,const Person& person) { os << person.name << " " << person.address; return os; } #endif
相关文章推荐
- c++ primer(第五版)学习笔记及习题答案代码版(第七章)类
- c++ primer(第五版)学习笔记及习题答案代码版(第十二章)动态内存与智能指针
- c++ primer第五版学习笔记 第一章
- c++ primer(第五版)学习笔记及习题答案代码版(第九章)顺序容器
- c++ primer 第五版学习笔记-第二章-类型转换
- c++ primer(第五版)学习笔记及习题答案代码版(第四章)表达式
- c++ primer(第五版)学习笔记及习题答案代码版(第二章)
- C++ 11 从C++ primer第五版的学习笔记
- c++ primer 第五版学习笔记-第二章-链接的那些事
- C++ Primer(第五版) 学习笔记
- c++ primer 第五版学习笔记-第二章-typedef不等于#define
- c++ primer 学习笔记-第七章
- c++ primer(第五版)学习笔记及习题答案代码版(第一章)
- C++ Primer(中文第五版)学习笔记
- c++ primer(第五版)学习笔记及习题答案代码版(第三章)字符串、向量和数组
- c++ primer(第五版)学习笔记及习题答案代码版(第十三章)拷贝控制
- c++ primer(第五版)学习笔记及习题答案代码版(第十章)泛型算法
- c++ primer(第五版)学习笔记及习题答案代码版(第十一章)关联容器
- c++ primer 第五版学习笔记-第二章-decltype类型推断
- c++ primer(第五版)学习笔记及习题答案代码版(第十四章)重载运算与类型转换