第8-1章 Container
8.1 STL
8.1.1 STL定义
(1)STL = Standard Template Library
(2)是ISO Standard C++ Library的一部分
(3)包含C++实现的数据结构、算法
8.1.2 STL的三个部分
(1)Containsers:容器
(2)Algorithms:算法
(3)Iterators:迭代器
8.2 顺序访问的容器
(1)vecotor:可变长数组
(2)deque:双向队列
(3)list:双向链表
(4)forward_list
(5)array
(6)string:字符数组
8.2.1 vector
| #include <vector>using namespace std;
 
 
 vector<Elem> c;
 vector<Elem> c1(c2);
 vector<int> v(100);
 
 
 v.size();
 v.empty();
 ==,!=,>,<,<=,>-;
 v.swap(v2);
 
 
 v.begin();
 v.end();
 vector<int>::iterator p;
 for(p=v.begin();p<x.end();p++)
 cout << *p << endl;
 
 
 v.at(index);
 v[index];
 v.front();
 v.back();
 
 
 v.push_back(e);
 v.pop_back();
 v.insert(pos,e);
 v.erase(pos);
 v.clear();
 v.find(first,last,item);
 
 | 
8.2.2 list
| #include <list>#include <string>
 using namespace std;
 
 
 list<string> s;
 list<string> s1(s2);
 
 
 s.begin();
 s.end();
 list<string>::iterator p;
 for(p=s.begin();p!=s.end();p++)
 cout << *p << endl;
 
 
 s.front();
 s.back();
 
 
 s.push_back("hello");
 s.push_front("world");
 s.pop_back();
 s.pop_front();
 s.insert(pos,item);
 s.remove(item);
 s.erase(pos);
 
 | 
8.3 Map
Map是一个pair的集合,包含key和value
查找:需要一个key,返回一个value
| #include <map>#include <string>
 using namespace std;
 
 
 map<string,double> price;
 
 
 price["snapple"] = 0.75;
 price["coke"] = 0.50;
 
 
 string item;
 double item_price;
 item_price = price[item];
 
 
 price.count(item);
 
 | 
8.4 Iterator 迭代器
| list<int>::iteator it;
 
 
 L.begin();
 
 
 L.end();
 
 
 ++it;
 
 
 *it = 10;
 
 | 
8.5 标准方法
8.5.1 copy
| copy(L.begin(), L.end(), ostream_iterator<int>(cout,","));
 
 
 copy(L.begin(),L.end(),V.begin());
 
 | 
8.6 typedef
| map<Name, list<PhoneNum> > phonebook;
 map<Name, list<PhoneNum> >::iterator finger;
 
 
 typedef PB map<Name,list<PhoneNum> >;
 PB phonebook;
 PB::iterator finger;
 
 | 
8.7 将自己的class放入STL容器
(1)需要:赋值操作operator = (),缺省构造函数
(2)对于排序类型:需要operator < ()
第8-2章 Overload Operator
8.1 操作符重载
8.1.1 可以重载

8.1.2 不能重载

8.1.3 注意
(1)不能重载不存在的操作符
(2)操作符的顺序不能改变
8.2 重载的语法
8.2.1 作为成员函数
可以作为类的成员函数,隐藏调用的对象
- 返回值必须是该类的类型
- 必须能够得到类的定义
| class Integer{private:
 int i;
 public:
 Integer(int n=0):i(n){};
 const Integer operator+(const Integer& n)const{
 return Integer(i + n.i);
 }
 const Integer operator-()const{
 return Integer(-i);
 }
 }
 Integer x(1),y(5),z;
 z = x + y;
 z = x + 3;
 z = 3 + y;
 
 | 
8.2.2 作为global函数
也可以是一个global函数,此时必须写出两个对象
- 不需要特殊的访问class
- 可能需要定义为friend函数,使其能够访问private变量
- 两个参数都可以进行类型转换
| class Integer{friend const Integer operator+(const Integer& rhs,const Integer& lhs);
 }
 const Integer operator+(const Integer& rhs,const Integer& lhs){
 return Integer(lhs.i + rhs.i);
 }
 Integer x(1),y(5),z;
 z = x + y;
 z = 3 + y;
 
 | 
8.2.3 必须是成员函数的重载
- 单目运算符
- =、()、[]、->、*
8.3 作为global函数的operator
- 如果是一个read-only的传递,必须声明为const
&
- 如果成员函数定义为const,则不能修改成员变量的值
- 对于global函数左边的参数需要会作为引用传递
- 返回值,要根据操作符本身的意思来定,并且要定义为const
- 如果不定义成const,可能会出现:x+y=z的情况
- 逻辑运算的返回值要定义成bool
 
| const T operator X (const T &l, const T &r)const{
 
 }
 
 bool operator X (const T &l, const T &r)const{
 
 }
 
 
 | 
8.4 作为成员函数的operator
8.4.1 下标
| E& T::operator[](int index){
 
 }
 
 | 
8.4.2 ++和--操作
| class Integer{public:
 const Integer& operator++(){
 *this += 1;
 return *this;
 }
 const Integer operator++(int){
 Integer old( *this );
 ++(*this);
 return old;
 }
 const Integer& operator--();
 const Integer operator--(int);
 };
 
 Integer x(5);
 ++x;
 x++;
 --x;
 x--;
 
 | 
8.4.3 bool操作
| class Integer { public:
 bool operator==(const Integer& rhs) const;
 bool operator!=(const Integer& rhs) const;
 bool operator< (const Integer& rhs) const;
 bool operator> (const Integer& rhs) const;
 bool operator<=(const Integer& rhs) const;
 bool operator>=(const Integer& rhs) const;
 }
 
 | 
- 使用 == 实现 !=
- 使用 < 实现
>,>=,<=
| bool Integer::operator==( const Integer& rhs ) const { return i == rhs.i;
 }
 
 bool Integer::operator!=( const Integer& rhs ) const {
 return !(*this == rhs);
 }
 bool Integer::operator<( const Integer& rhs ) const {
 return i < rhs.i;
 }
 
 bool Integer::operator>( const Integer& rhs ) const {
 return rhs < *this;
 }
 
 bool Integer::operator<=( const Integer& rhs ) const {
 return !(rhs < *this);
 }
 
 bool Integer::operator>=( const Integer& rhs ) const {
 return !(*this < rhs);
 }
 
 | 
8.4.5 赋值
- 要返回引用类型,因为可能会存在A=B=C=D
- 当A与this的地址相同时,说明是A=A,可以不用执行赋值操作
- 对于具有动态分配内存的类,系统的默认赋值只能进行浅拷贝,也就是说,会出现后面的实例中指针指向了前面的示例的指针指向的地址。因此要写赋值操作
- 如果不想出现赋值操作,可以将operator=声明为private
| class T{public:
 T& operator=(const T& A){
 if(&A != this){
 
 }
 return *this;
 }
 }
 
 | 
8.5 copy vs initialization
| MyType b;MyType a = b;
 a = b;
 
 | 
initialization:
- 会调用MyType的构造函数
- 如果没有对应类型的构造函数,则会进行类型转换
copy:
- 会调用MyType的operator=
- 如果没有写operator=,系统会有一个缺省构造函数,默认调用所有成员变量的operator=
- 返回&,因为输入/输出obj后,输入/输出流会变化
| istream& operator>>(istream& is, T& obj){
 return is;
 }
 cin >> a >> b >> c;
 ((cin >> a) >> b) >> c;
 
 ostream& operator<<(ostream& os, const T& obj) {
 
 return os;
 }
 cout << a << b << c;
 ((cout << a) << b) << c;
 
 | 
8.6.1 定义 manipulators
| ostream& manip(ostream& out) {
 ...
 return out;
 }
 ostream& tab (ostream& out) {
 return out << '\t';
 }
 cout << "Hello" << tab << "World!" << endl;
 
 | 
8.7 类型转换
- 类型转换操作符,可以将一个类的对象转化为
- 另一个类的对象
- 内置类型built-in type
 
| class Rational { public:
 operator double() const{
 return numerator_/(double)denominator_;
 }
 }
 Rational r(1,3);
 double d = 1.3 * r;
 
 | 
- 编译器可以自动执行的类型转换
- 单参数的类型转换single argument
- 隐式类型转换implicit
type:如子类→父类,在构造函数中定义的类型转换
 
| class PathName{string name;
 public:
 PathName(const string&);
 }
 string abc("abc");
 PathName xyz(abc);
 xyz = abc;
 
 | 
- 防止implicit conversion
- 添加关键字explicit,显式调用
 
| class PathName { string name;
 public:
 explicit PathName(const string&);
 };
 ...
 string abc("abc");
 PathName xyz(abc);
 xyz = abc;
 
 
 | 
内置类型转换:
- 原始类型 - char → short → int → float → double -  → int → long 
- 隐式类型转换 - 
- T → T&
- T& → T
- T* → void*
- T[] → T*
- T* → T[]
- T → const T[]
 
用户定义的类型转换:T→C
- 判断C的构造函数中是否存在C(T)
- 判断T的重载中是否存在operator
C()
8.8 casting operator
出错信息:bad cast
8.8.1 static_cast
显式类型转换,为了保证操作符转换的安全性
不允许const 指针/引用 → 非const
| char a = 'a';int b = static_cast<char>(a);
 
 double *c = new double;
 void *d = static_cast<void*>(c);
 
 int e = 10;
 const int f = static_cast<const int>(e);
 
 const int g = 20;
 int *h = static_cast<int*>(&g);
 
 | 
但是当用来转化class指针的时候,static_cast不是安全的,因为它不会检查两个class的继承关系
| Class A {public: virtual test() {…}}
 Class B: public A {public: virtual test() {…}}
 
 A *pA1 = new B();
 B *pB = static_cast<B*>(pA1);
 
 | 
8.8.2 dynamic_cast
会检查向下转换 downcast 是否为安全的
| Class A {public: virtual test() {…}}
 Class B: public A {public: virtual test() {…}}
 
 Class C: {public: virtual test() {…}}
 
 A *pA1 = new B();
 B *pB = dynamic_cast<B*>(pA1);
 
 C *pC = dynamic_cast<B*>(pA1);
 
 | 
8.8.3 const_cast
const 指针/引用 → 为非const
| const int g = 20;int *h = const_cast<int*>(&g);
 
 const int g = 20;
 int &h = const_cast<int &>(g);
 
 const char *g = "hello";
 char *h = const_cast<char *>(g);
 
 | 
8.8.4 reinterperet_cast
指针 → int,int → 指针
| int a, b;int *pA = &b;
 a = reinterpret_cast<int>(pA);
 pA = reinterpret_cast<int*>(a);
 
 b = reinterpret_cast<int>(a);
 
 |