0. 首先先说作业
因为这次的作业看起来和第十周的课程更相近,所以把第十周看了。导致并没有时间回顾第九周及之前的课程,结果就是在写作业的时候一脸懵比,出现各种错误。这次出现的错误非常有启发性,所以列在最前。
0.1 错误的编译环境
更换系统后用的是官方的MinGW,几次编译都很正常,并没有什么问题。
但是今天在查询代码的时候出现了无法使用C++11中string的几个数值转换函数的问题。现象就是使用to_string等函数时显示无法解析名字。
后来更换Code::Blocks才编译正常, 怀疑是MinGW版本(5.3.0)太旧的问题,查看文档后得知Code::Blocks中用的版本是6.2.0,于是按编译说明找到了下载地址MinGW-w64。更换编译环境后编译正常。
0.2 错误的设计模式
昨天在编程之前并没有仔细思考,是从测试代码和题目要求分别从输出函数和基础类两方面推进,最后并没有汇合,代码微妙的错开了。导致两边的接口完全对不上,一边请求的是函数,而另一边提供的是类型。没有仔细思考会遇到的问题导致错误的接口。
0.3 并不理解Traits的本质
现在也仍然弄不清楚Traits到底是什么,一开始的感觉就是利用泛化和特化来获得指定的struct数值。但是现在感觉并不是这样。如果没有充分理解Traits到底是什么,那就没有办法灵活的运用。这次的混乱大都产生于此。
0.4 并不扎实的基本功
虽然老师说“勿在浮沙筑高台”,但是短时间没有办法弥补巨大的差距。
典型的问题出现在对基类与子类的关系,为此专门拿出书本仔细阅读,发现缺少大量的相关知识。
对于private中数值的继承、对于构造函数的继承、对于基类函数的继承,虽然有所了解,但是完全不知道是怎么回事,以及如何使用。
class Value{
public:
Value(double m = 0):mvalue(m){}
double key() const {
return mvalue;
}
protected:
double mvalue;
};
class kilometer:public Value {
public:
using Value::Value;
};
这段代码就是以前从来没有见过的,如果没有看书也不会想到还可以这么写。由于对OOP认识并不清楚,所以只能写继承关系,但是感觉其他的可能会更好。
0.5 缺少实践经验以及理解不足
对于模板的使用完全没有概念,仅仅是照猫画虎。所以对于引用传递的内容非常模糊,就会出现下面这种疑问:“为什么传引用会失效?”如果写成print(T& x)
,传递过来的类型T就会变成Value,导致Traits失效。之前还有很多类似的问题,所以不仅要知道reference传递的内容是什么,也要知道传递的类型是什么。
// 此处传引用会失效??为什么?
template
string print(T x){
string str;
int ts=x.key()*dimension::scale+0.5;
str= to_string(ts); //Clion不支持to_string,为什么??
// str.push_back(to_string(x.key()*dimension::scale));
str.push_back(dimension::unit);
return str;
}
之前还出现过这样的问题,现在看来非常愚蠢,但是因为第一次遇到,所以就毫无意识。
下面这段代码直接重载了所有的<<
,导致这个操作符废了。如何避免这种情况,避免过度重载?这些还要再回顾一下特化等知识。
//过度重载
template
inline
ostream& operator<<(ostream& os, const T& x)
{
return os << x.key()*dimension::scale << dimension::unit;
}
算法的形式
C++标准库的算法,是什么东西?
迭代器必须可以回答算法提出的所有问题。
类型+() 直接生成临时对象
30. 算法源代码剖析(11个例子)
先前示例中出现的算法
算法 accumulate
可以传函数,也可以传像函数的东西
struct myclass {
int operator()(int x, int y){return x+3*y;}
} myobj;
算法 for_each
算法 replace, replace_if, replace_copy
Predicate 判断式
算法count,count_if
算法find,find_if
算法sort
算法 rbegin rend
reverse_iterator
算法 binary_search
仿函数 functors
最简单的能够写出来融入STL的
- 算术类
- 逻辑运算类
- 相对关系类
要仿函数,就必须要重载()
因为要把+-操作传给算法,所以要用仿函数。
仿函数functors的可适配条件
没有继承,就说明没有融入STL
继承不继承有什么差别
继承的是binary_function
一个没有数据的类,占用大小是0或者1,被继承时,占用大小是0。
子类会 继承typedef
存在多种 Adapters
adapters就是换个衣服
会出现在三个地方:
- 迭代器适配器
- 仿函数适配器
- 容器适配器
容器适配器:stack,queue
set,multiset?
函数适配器:binder2nd
注意bind2nd是辅助函数,binder2nd是对象
函数适配器:binder2nd
没看懂,一个函数适配器需要回答那几个问题?
typename 通知编译器,后面是一个类型,可以编译通过。
既要能提出问题,又能回答问题
既可以适配,又能被适配
所以要继承unary
函数适配器:not1
用compose把一大堆adapter组合在一起?
新型适配器,bind Since C++11
..\include\c++\backward\backward_warning.h
binder2nd过时了,要用bind取代
std::bind 可以绑定:
- functions
- function objects
- member functions _1 必须是某个object地址
- data members _1 必须是某个object地址
_1 占位符号
using namespace std::placeholders; //add visibility _1,_2,_3,...
bind
member function 其实有个参数 this
可以返回函数值,也可以返回data值
迭代器适配器 reverse_iterator
rbegin() rend()
解引用时先--、】 【【
迭代器适配器:inserter
普通的copy不检查空间是否越界
所以给iterator增加适配器
inserter 对象被赋值时调用赋值的操作符重载,从而在不更改copy代码的前提下更改流程
x适配器:ostream_iterator
不知道该算什么适配器
delimiter 分隔符
x适配器:istream_iterator
std::istream_iterator eos; // 没有参数,空的,是一个end-of-stream iterator
为什么一创建就要读取呢?
第二个例子相当于文本框?
copy不止能把确定的序列复制到目标中去,也可以把可++的Iterator指向的对象。