第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);
|