侯捷C++(STL和泛型编程)
Remember Understand Practice Use Understand Master
一、STL和泛型编程
C++标准库
C++标准模板库
STL六大部件:
容器(Containers)
分配器(Allocators)
算法(Algorithms)
迭代器(Iterators)
适配器(Adapters)
仿函式(Functors)
#include <iostream>
using namespace std;
int main()
{
for(int i: {2,3,5,7,9,13,17,19})
{
cout<<i<<' ';
}
return 0;
}
1.容器
Sequence containers:
Array
Vector
heap
priority——queue
优先队列是一种容器适配器,采用了堆这样的数据结构,保证了第一个元素总是整个优先队列中最大的(或最小的)元素。优先队列默认使用vector作为底层存储数据的容器
Deque
Stack
Queue
List
Slist
Forward-List
Associative containers:
Set/Multiset
Map/Multimap
Unordered Set/Multiset
Unordered Map/Multimap
2.分配器
面向对象编程VS泛型编程
Operator Overloading操作符重载
Templates 模板
ClassTemplates 类模板
Function Templates 函数模板
Member Templates 成员模板
检查数据类型
typeid() typeid 用于在编译时获取类型的 Type
3.算法
4.迭代器的分类
二、C++标准11-14
C++ Primer回顾:
1.可以用sizeof测量数据类型的大小,以字节为单位
1.类定义
类成员
一般情况下,数据成员为private
没写访问标号,默认private
构造函数
使用初始化列表初始化数据成员
Person(const string &nm,const string &addr):name(nm),address(addr){
//name = nm;
//address = addr;
}
成员函数
访问标号实施抽象和封装
public
private
protected
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class Sales_item
{
public:
Sales_item(string &book,unsigned units,double amount):
isbn(book),units_sold(units),revenue(amount)
{
}
double avg_price() const
{
if(units_sold)
return revenue / units_sold;
else
return 0;
}
bool same_isbn(const Sales_item &rhs) const
{
return isbn == rhs.isbn;
}
void add(const Sales_item &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
}
private:
string isbn;
unsigned units_sold;
double revenue;
};
class Person{
public:
Person(const string &nm,const string &addr):name(nm),address(addr){
//name = nm;
//address = addr;
}
string getName() const
{
return name;
}
string getAddress() const
{
return address;
}
private:
string name;
string address;
};
int main()
{
//Person a("bill","street1");
//a.name;
//cout<<a.getName();
//a.getAddress();
string s("0-399-82477-1");
Sales_item x(s,2,20.00);
Sales_item y(s,6,48.00);
if(x.same_isbn(y))
x.add(y);
cout<<x.avg_price()<<endl;
cout<<y.avg_price();
return 0;
}
2.
同一类型的多个数据成员
使用类型别名来简化类
成员函数可被重载 - 定义重载成员函数
显法指定inline成员函数
写在类内部的函数都是内联函数。
函数定义写在外部则不是内联函数,可在定义或声明前增加inline
#include <iostream>
#include <string>
using namespace std;
class Screen
{
public:
typedef string::size_type index;
Screen(index ht = 0,index wd = 0):contents(ht*wd,'A'),cursor(0),height(ht),width(wd)
{
}
Screen(index ht,index wd,const string &conts);
char get() const;
inline char get(string::size_type r,string::size_type c) const;
private:
string contents;
string::size_type cursor;
string::size_type height,width;
};
inline char Screen::get() const
{
return contents[cursor];
}
char Screen::get(string::size_type r,string::size_type c) const
{
string::size_type row = r*width;
return contents[row+c];
}
Screen::Screen(index ht,index wd,const string &conts):contents(conts),
cursor(0),height(ht),width(wd)
{
}
int main()
{
Screen a(10,100);
cout<<a.get()<<endl;
cout<<a.get(2,8)<<endl;
Screen b(3,6,"hello screen class");
cout<<b.get()<<endl;
cout<<b.get(0,4)<<endl;
cout<<b.get(1,2);
return 0;
}
3.隐含的this指针
this指向当前的对象
何时使用this指针
返回*this
从const成员函数返回*this
基于const的重载
可变数据成员
4.类作用域
1.使用类的成员
2.作用域与成员定义
3.形参表和函数体处于类作用域中
4.函数返回类型不一定在类作用域中
类作用域中的名字查找
1.类成员声明的名字查找
2.类成员定义中的名字查找
3.类成员遵循常规的块作用域名字查找
4.函数作用域之后,在类作用域中查找
5.类作用域之后,在外围作用域中查找
5.构造函数
作用保证每个对象的数据成员具有合适的初始值
构造函数初始化式(初始化列表)
默认实参与构造函数
默认构造函数
对string进行初始化为空,其他类型没有默认初始化
const成员、引用类型、没有默认构造函数的类类型必须使用初始化列表
隐式类类型转换
类成员的显示初始化
#include<iostream>
#include <string>
using namespace std;
class Person
{
public:
Person(const string &nm,int a):name(nm),age(a)
{
}
public:
string name;
int age;
};
class Dog
{
public:
Dog()
{
this->legs = 4;
}
private:
string name;
int legs;
};
class Sales_item
{
public:
Sales_item(const string &book,int units,double price):isbn(book),units_sold(units),revenue(units*price)
{
}
//默认的实参,不给参数按照默认的
Sales_item(const string &book=""):isbn(book),units_sold(0),revenue(0.0){}
Sales_item(istream &is) {is >> *this;}
//Sales_item():units_sold(0),revenue(0.0){}
Sales_item(int units,double price)
{
this->units_sold = units;
this->revenue = units*price;
}
friend istream& operator >> (istream&,Sales_item&);
private:
string isbn;
unsigned units_sold;
double revenue;
};
inline istream& operator>>(istream& in,Sales_item& s)
{
double price;
in>>s.isbn>>s.units_sold>>price;
if(in)
s.revenue = s.units_sold * price;
else
s = Sales_item();
return in;
}
class Cat{
public:
Cat():age(0){}
string getName(){
return this->name;
}
int getAge()
{
return this->age;
}
private:
string name;
int age;
};
int main()
{
Person a("zhangfei",22);
cout<<a.name<<endl;
cout<<a.age;
Sales_item item1;
Sales_item item2("0-201-82470-1");
Sales_item *p = new Sales_item();
delete [] p;
return 0;
}
6.友元-友元函数、友元类
友元关系
三种友元
1.普通函数(非成员函数)
2.类
3.类的成员函数
#include <iostream>
#include <string>
using namespace std;
class Screen;
class Dog
{
public:
int foo(Screen& screen);
int koo(Screen& screen);
};
class Screen
{
public:
typedef string::size_type index;
Screen(int ht=0,int wd=0):contents(ht*wd,' '),cursor(0),height(ht),width(wd)
{
}
int area() const
{
return height*width;
}
friend int calcArea(Screen &);
friend class Window_Mgr;
//friend class Dog;
friend int Dog::foo(Screen&);
private:
string contents;
index cursor;
int height,width;
};
class Window_Mgr
{
public:
void relocate(int r,int c,Screen& s)
{
s.height += r;
s.width += c;
}
};
// 这个函数不是类的成员函数
int calcArea(Screen &screen)
{
return screen.height * screen.width;
}
int Dog::foo(Screen& screen)
{
return screen.height * screen.width;
}
int main()
{
Screen a(60,100);
cout<<a.area()<<endl;
Window_Mgr wm;
wm.relocate(20,100,a);
cout<<calcArea(a)<<endl;
Dog dog;
cout<<dog.foo(a)<<endl;
// cout<<dog.koo(a)<<endl;
cout<<"OK"<<endl;
return 0;
}
7.static类成员
使用类的static成员的优点
公用
定义static成员
使用类的static成员
static成员函数
static数据成员
#include <iostream>
#include <string>
using namespace std;
class Account
{
public:
Account(string name,double money):
owner(name),amount(money)
{
}
double getAmount() const
{
return this->amount;
}
void applyint()
{
amount+=amount*interestRate;
}
void deposit(double money)
{
this->amount += money;
}
static double rate()
{
return interestRate;
}
static void rate(double newRate){interestRate = newRate;}
private:
string owner;
double amount;
static double interestRate;
static const int period = 30;//例外
};
double Account::interestRate = 0.015;
int main()
{
Account::rate(0.026);
Account a("zhangsan",1000);
a.deposit(500);
Account b("lisi",2000);
b.deposit(600);
cout<<a.getAmount()<<endl;
cout<<b.getAmount()<<endl;
cout<<a.rate()<<endl;
a.rate(0.018);
cout<<b.rate()<<endl;
Account::rate(0.02);
a.applyint();
b.applyint();
cout<<a.getAmount()<<endl;
cout<<b.getAmount()<<endl;
return 0;
}
8.复制构造函数和赋值操作符
复制构造函数的适用情况
1.对象的定义形式 - 复制初始化
2.形参与返回值
3.初始化容器元素
4.构造函数与数组元素
赋值操作符
1.重载赋值操作符
2.复制和赋值常一起使用
合成的复制构造函数和赋值操作符
定义自己的复制构造函数和赋值操作符
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Sales_item
{
public:
//普通构造函数
Sales_item():units_sold(0),revenue(0.0){
cout<<"This 1"<<endl;
}
Sales_item(const string &book):isbn(book),units_sold(0),revenue(0.0)
{
cout<<"This 2"<<endl;
}
//复制构造函数
Sales_item(const Sales_item &orig):isbn(orig.isbn),
units_sold(orig.units_sold),revenue(orig.revenue)
{
cout<<"DYL"<<endl;
}
//赋值操作符 当类中动态分配内存时,必须重载赋值操作符
Sales_item& operator=(const Sales_item &rhs)
{
cout<<"DYLLLLLL"<<endl;
isbn = rhs.isbn;
units_sold = rhs.units_sold;
revenue = rhs.revenue;
return *this;
}
private:
string isbn;
unsigned units_sold;
double revenue;
};
Sales_item foo(Sales_item &item)
{
Sales_item temp;
temp = item;
return temp;
}
class noName
{
public:
noName():pstring(new string),
i(0),d(0.0)
{
}
noName(const noName& other):pstring(new string(*(other.pstring))),
i(other.i),d(other.d)
{
}
noName& operator=(const noName &rhs)
{
pstring = new string;
*pstring = *(rhs.pstring);
i=rhs.i;
d=rhs.d;
return *this;
}
private:
string *pstring;
int i;
double d;
};
int main()
{
noName x,y;
noName z(x);
x = y;
Sales_item a;
Sales_item b("0-201-78345-X");
Sales_item c(b);
a = b;
Sales_item item = string("9-999-99999-9");
cout<<"try foo()"<<endl;
Sales_item ret;
ret = foo(item);
cout<<"try vector"<<endl;
vector<Sales_item> vec(5);
cout<<"try array"<<endl;
Sales_item primer_eds[] = {
string("0-201-16487-6"),
string("0-201-16487-7"),
string("0-201-16487-7"),
Sales_item()
};
return 0;
}
9.析构函数
析造函数:获取资源
析构函数:释放资源
合成的析构函数
三法则:如果写了析构函数,一定要写复制构造函数和赋值操作符重载。
#include <iostream>
using namespace std;
class NoName
{
public:
NoName():pstring(new string),i(0),d(0.0)
{
cout<<"构造函数被调用了"<<endl;
}
~NoName();
NoName(const NoName& other);
NoName& operator=(const NoName &rhs);
private:
string *pstring;
int i;
double d;
};
NoName::~NoName()
{
//关闭文件
//关闭数据库链接
//回收动态分配的内存
cout<<"析构函数被调用了"<<endl;
delete pstring;
}
NoName::NoName(const NoName& other)
{
pstring = new string();
*pstring = *(other.pstring);
i = other.i;
d = other.d;
}
NoName& NoName::operator=(const NoName &rhs)
{
pstring = new string;
*pstring = *(rhs.pstring);
i = rhs.i;
d = rhs.d;
return *this;
}
int main()
{
NoName a;
NoName *p = new NoName;
delete p;
return 0;
}
10.深复制、浅复制
复制构造函数/拷贝构造函数
浅复制/浅拷贝/位拷贝
深复制/深拷贝
#include <iostream>
#include <cstring>
using namespace std;
class CDemo
{
//默认的复制构造函数是浅复制
public:
CDemo(int pa,char *cstr)
{
this->a = pa;
this->str = new char[104];
strcpy(this->str,cstr);
}
CDemo(CDemo &obj)
{
this->a = obj.a;
this->str = new char[1024];
if(str!=0)
strcpy(this->str,obj.str);
}
~CDemo()
{
delete str;
}
int a;
char *str;
};
int main()
{
CDemo A(10,"hello");
CDemo B = A;
cout<<A.a<<" "<<A.str<<endl;
cout<<B.a<<" "<<B.str<<endl;
B.a = 8;
B.str[0]='k';
cout<<A.a<<" "<<A.str<<endl;
cout<<B.a<<" "<<B.str<<endl;
return 0;
}
11.管理指针成员
三种方法
1.常规指针类(浅复制)
严重缺点:野指针(悬垂指针)
class AHasPtr
{
public:
AHasPtr(int *p,int i):ptr(p),val(i)
{
}
int *get_ptr() const {return ptr;}
int get_int() const {return val;}
void set_ptr(int *p) {ptr=p;}
void set_int(int i){val=i;}
int get_ptr_val() const {return *ptr;}
void set_ptr_val(int val) {*ptr = val;}
private:
int val;
int *ptr;
};
2.智能指针类(计数类)
避免野指针
class CHasPtr
{
public:
CHasPtr(const int &p,int i):ptr(new int(p)),val(i)
{
}
CHasPtr(const CHasPtr &orig):ptr(new int(*orig.ptr)),
val(orig.val){}
CHasPtr& operator=(const CHasPtr&);
~CHasPtr()
{
delete ptr;
}
int *get_ptr() const {return ptr;}
int get_int() const {return val;}
void set_ptr(int *p) {ptr=p;}
void set_int(int i){val=i;}
int get_ptr_val() const {return *ptr;}
void set_ptr_val(int val) {*ptr = val;}
private:
int val;
int *ptr;
};
CHasPtr& CHasPtr::operator=(const CHasPtr &rhs)
{
*ptr = *rhs.ptr;
val = rhs.val;
return *this;
}
3.值型类(深复制)
class U_Ptr
{
friend class BHasPtr;
private:
int *ip;
size_t use;//计数
U_Ptr(int *p):ip(p),use(1){}
~U_Ptr(){delete ip;}
};
class BHasPtr
{
public:
BHasPtr(int *p,int i):ptr(new U_Ptr(p)),val(i)
{
}
BHasPtr(const BHasPtr& orig):ptr(orig.ptr),val(orig.val){
++ptr->use;
}
BHasPtr& operator=(const BHasPtr&);
~BHasPtr()
{
//此处似乎有问题
//if(--ptr->use == 0)
delete ptr;
}
int *get_ptr() const {return ptr->ip;}
int get_int() const {return val;}
void set_ptr(int *p) {ptr->ip=p;}
void set_int(int i){val=i;}
int get_ptr_val() const {return *ptr->ip;}
void set_ptr_val(int val) {*ptr->ip = val;}
private:
int val;
U_Ptr *ptr;
};
BHasPtr& BHasPtr::operator=(const BHasPtr &rhs)
{
++rhs.ptr->use;
if(--ptr->use == 0) delete ptr;
ptr = rhs.ptr;
val = rhs.val;
return *this;
}
#include <iostream>
#include "plain-ptr.h"
#include "value-ptr.h"
#include "smart-ptr.h"
using namespace std;
void test_AHasPtr()
{
int i=42;
AHasPtr p1(&i,42);
AHasPtr p2 = p1;
cout<<p2.get_ptr_val()<<endl;
p1.set_ptr_val(0);
cout<<p2.get_ptr_val()<<endl;
int *ip = new int(42);
AHasPtr ptr(ip,10);
cout<<ptr.get_ptr_val()<<endl;
delete ip;
cout<<ptr.get_ptr_val()<<endl;
}
void test_CHasPtr()
{
int obj = 0;
CHasPtr ptr1(obj,42);
CHasPtr ptr2(ptr1);
cout<<ptr1.get_ptr_val()<<endl;
cout<<ptr1.get_int()<<endl;
cout<<ptr2.get_ptr_val()<<endl;
cout<<ptr2.get_int()<<endl;
ptr2.set_ptr_val(10);
cout<<ptr1.get_ptr_val()<<endl;
cout<<ptr1.get_int()<<endl;
cout<<ptr2.get_ptr_val()<<endl;
cout<<ptr2.get_int()<<endl;
}
void test_BhasPtr()
{
int obj=0;
BHasPtr ptr1(&obj,42);
BHasPtr ptr2(ptr1);
cout<<ptr1.get_ptr_val()<<","<<ptr1.get_int()<<endl;
cout<<ptr2.get_ptr_val()<<","<<ptr2.get_int()<<endl;
ptr2.set_ptr_val(39);
ptr1.set_int(23);
cout<<ptr1.get_ptr_val()<<","<<ptr1.get_int()<<endl;
cout<<ptr2.get_ptr_val()<<","<<ptr2.get_int()<<endl;
}
int main()
{
cout<<"常规指针"<<endl;
test_AHasPtr();
cout<<"值型类"<<endl;
test_CHasPtr();
cout<<"智能指针"<<endl;
test_BhasPtr();
return 0;
}
12.重载操作符的定义
不能重载的操作符(四个)
:: .*
. ?:
重载操作符的注意事项
操作符重载
输出操作符 >> 重载
非成员函数 ->友元函数
少做格式化
输入操作符 >>重载
处理输入操作的错误
#include <iostream>
#include <string>
using namespace std;
class Dog
{
};
class Sales_item
{
friend ostream& operator<<(ostream& out,const Sales_item& s);
friend istream& operator>>(istream& in,Sales_item& s);
public:
Sales_item(const string &book,unsigned units,double price):
isbn(book),units_sold(units),revenue(price*units)
{
}
Sales_item():units_sold(0),revenue(0.0)
{
}
private:
string isbn;
unsigned units_sold;
double revenue;
};
ostream& operator<<(ostream& out,const Sales_item& s)
{
out<<s.isbn<<"\t"<<s.units_sold<<"\t"<<s.revenue;
return out;
}
istream& operator>>(istream& in,Sales_item& s)
{
double price;
in>>s.isbn>>s.units_sold>>price;
s.revenue = s.units_sold*price;
if(in)
s.revenue = s.units_sold*price;
else
s = Sales_item();
return in;
}
int main()
{
//Dog a;
Sales_item item("0-201-78345-X",2,25.00);
cout<<"hello"<<endl;
cout<<item<<endl;
cin>>item;
cout<<item<<endl;
cin>>item;
cout<<item<<endl;
return 0;
}
为了与内置操作符保持一致,算术操作符通常产生一个新值。
一般应使用复合赋值实现算术操作符。例如:用+=来实现+
#include <iostream>
#include <string>
using namespace std;
class Dog
{
};
class Cat
{
};
class Sales_item
{
public:
Sales_item(const string&book,const unsigned units,const double amount):
isbn(book),units_sold(units),revenue(amount)
{
}
Sales_item& operator+=(const Sales_item&);
Sales_item& operator-=(const Sales_item&);
friend ostream& operator<<(ostream&,const Sales_item&);
private:
string isbn;
unsigned units_sold;
double revenue;
};
Sales_item operator+(const Sales_item&,const Sales_item&);
Sales_item operator-(const Sales_item&,const Sales_item&);
Sales_item& Sales_item::operator+=(const Sales_item &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
Sales_item& Sales_item::operator-=(const Sales_item& rhs)
{
this->units_sold -= rhs.units_sold;
this->revenue -= rhs.revenue;
return *this;
}
Sales_item operator+(const Sales_item& lhs,const Sales_item& rhs)
{
Sales_item ret(lhs);
ret += rhs;
return ret;
}
Sales_item operator-(const Sales_item& lhs,const Sales_item& rhs)
{
Sales_item ret(lhs);
ret -= rhs;
return ret;
}
ostream& operator<<(ostream& out, const Sales_item& s)
{
out<<s.isbn<<"\t"<<s.units_sold<<"\t"<<s.revenue;
return out;
}
int main()
{
//Dog dog;
//Cat cat;
Sales_item item1("0-201-12345-X",10,120.0);
Sales_item item2("0-201-12345-X",20,200.0);
Sales_item result = item1 + item2;
cout<<result<<endl;
Sales_item item3("0-201-12345-X",5,70.00);
result += item3;
cout<<result<<endl;
result -= item2;
cout<<result<<endl;
return 0;
}
重载关系操作符(大于小于等于)
13.函数对象
重载函数调用操作符
函数对象:定义了调用操作符的类,其对象称为“函数对象”
一元函数对象
一元谓词
二元函数对象
二元谓词
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
struct absInt{
int operator()(int val)
{
return val<0?-val:val;
}
};
template<typename elementType>
void FuncDisplayElement(const elementType& element)
{
cout<<element<<' ';
}
template<typename elementType>
struct DisplayElement
{
//存储状态
int m_nCount;
DisplayElement()
{
m_nCount = 0;
}
void operator() (const elementType& element)
{
++m_nCount;
cout<<element<<' ';
}
};
int main()
{
int i = -42;
absInt absObj;
unsigned int ui = absObj(i);
cout<<ui<<endl;
vector<int> a;
for(int n=0;n<10;++n)
a.push_back(n);
list<char> b;
for(char c='a';c<'k';++c)
b.push_back(c);
//STL算法
DisplayElement<int> mResult;
mResult = for_each(a.begin(),a.end(),mResult);
cout<<endl;
cout<<"数量:"<<mResult.m_nCount<<endl;
for_each(b.begin(),b.end(),DisplayElement<char>());
cout<<endl;
cout<<"Hello 函数对象"<<endl;
return 0;
}
一元函数谓词
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<typename numberType>
struct IsMutiple
{
numberType m_Divisor;
IsMutiple(const numberType& divisor)
{
m_Divisor = divisor;
}
bool operator() (const numberType& element) const
{
return ((element % m_Divisor)==0);
}
};
int main()
{
vector<int> vecIntegers;
for(int i=33;i<=100;++i)
vecIntegers.push_back(i);
IsMutiple<int> a(4);
vector<int>::iterator iElement;
iElement = find_if(vecIntegers.begin(),vecIntegers.end(),IsMutiple<int>(4));
if(iElement != vecIntegers.end())
{
cout<<"第一个4的整数倍的数是: "<<*iElement<<endl;
}
return 0;
}
二元函数谓词
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<typename elementType>
class CMultiply
{
public:
elementType operator() (const elementType& elem1,
const elementType& elem2)
{
return elem1*elem2;
}
};
int main()
{
vector<int> a,b;
for(int i=0;i<10;++i)
a.push_back(i);
for(int j=100;j<110;++j)
b.push_back(j);
vector<int> vecResult;
vecResult.resize(10);
transform(a.begin(),a.end(),b.begin(),vecResult.begin(),CMultiply<int>());
for(size_t nIndex = 0;nIndex<vecResult.size();++nIndex)
cout<<vecResult[nIndex]<<' ';
cout<<endl;
return 0;
}
#include <iostream>
#include <set>
#include <string>
#include <algorithm>
using namespace std;
class CCompareStringNoCase
{
public:
bool operator()(const string& str1,const string& str2) const
{
string str1LowerCase;
str1LowerCase.resize(str1.size());
transform(str1.begin(),str1.end(),str1LowerCase.begin(),::tolower);
string str2LowerCase;
str2LowerCase.resize(str2.size());
transform(str2.begin(),str2.end(),str2LowerCase.begin(),::tolower);
return (str1LowerCase<str2LowerCase);
}
};
int main()
{
set<string,CCompareStringNoCase> name;
name.insert("Tina");
name.insert("jim");
name.insert("Jack");
name.insert("Sam");
name.insert("hello");
set<string,CCompareStringNoCase>::iterator iNameFound = name.find("Jim");
if(iNameFound != name.end())
{
cout<<"找到了"<<*iNameFound<<endl;
}
else
{
cout<<"没找到"<<endl;
}
return 0;
}
三、C++内存管理
四、C++面向对象高级开发

浙公网安备 33010602011771号