这篇东西叫作笔记,实在是有点名不副实。我并没有摘抄树上的很多话,也不打算写很多感悟之类的东西。因为我觉得第三章——标准库概览,里面并没有什么太多的理论或原则,只是让大家“试一下”标准库的一些功能。因此,这次我就只好调试几个例子,来概括学习本章得到的收获。
1、string的简单使用,没什么可看的。只是想试一下
//Liukai @ HUST
//2006-7-17
/**********************************************************************************
测试标准库中string的简单用法
***********************************************************************************/
#include <iostream>
#include <string>
using namespace std;
int main( void )
{
//string的声明和拼接
string str1 = "Hello";
string str2 = "guys";
string str3 = str1 + ", " + str2 + "!/n";
cout << str3;
//append
str2.append( str1 );
str2.append( 1, '!' );
//和append等价的是
str2 += '/n';
cout << "str2 after append str1: " << str2;
//== and != etc.
string str4(str1);
cout << str1 << ( str1==str2 ? " == ": " != ") << str2 << endl;
cout << str4 << ( str4==str1 ? " == ": " != ") << str1 << endl;
cout << str1 << ( str1>=str2 ? " >= ": " < ") << str2 << endl;
//substr and replace
string name = "Tom King";
cout << "My name is " << name << endl;
cout << "So my family name is " << name.substr(4,4) << endl;
cout << "In fact, my full name is " << name.replace(0,3,"Thomas") << endl;
cout << "Or, " << name.replace(6,1," S. ") << endl;
//Standard input for string
string yourName;
cout << "Do you mind input you name? Input Now..." << endl;
cin >> yourName;
cout << "Hi, " << yourName << endl;
cout << "Something Wrong? Try again:" << endl;
//getline
getline(cin,yourName); //吃掉前面的输入
getline(cin,yourName);
cout << "Hello, " << yourName << endl;
return 0;
}
/***********************************************************************************************
在vc6下编译通过
主要用来试验string的一些简单功能
另外的功能如迭代器等将会和其他例子一起使用
***********************************************************************************************/
2、vector的使用,详见注释
//Liukai @ HUST
//2006-7-17
/*********************************************************************************************
vector使用:一个简单的例子,电话号码簿。由TC++PL上的例子而来
使用vector的用户派生类,带有下标检查的Vec
主要目的是熟悉vector的各种用法及注意事项,这个程序实际作用不大
顺便把异常处理的简单应用也加上去
**********************************************************************************************/
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
using namespace std;
//struct Entry ---- a pair of (name,number)
struct Entry
{
string name;
int number;
};
//从标准库派生而来的Vec
template<class T> class Vec : public vector<T>
{
public:
Vec()
: vector<T>()
{}
Vec(int s)
: vector<T>(s)
{}
T& operator[](int loc)
{
return at(loc);
}
const T& operator[](int loc) const
{
return at(loc);
}
};
void RangeCheck( const Vec<Entry>& );
void RangeCheck( const vector<Entry>& );
int main( void )
{
try
{
//首先注意:两种意义完全不同的声明
vector<Entry> book(100); //正是我们想要的电话簿,初始大小100
vector<Entry> books[100]; //内部数组,100个空的电话簿
//vector可以简单赋值:代价可能很高!
books[23] = book;
cout << "Check vector:" << endl;
RangeCheck( book );
cout << endl << "Check Vec" << endl;
Vec<Entry> superbook(100);
RangeCheck( superbook );
return 0;
}
catch(...)
{
return 1;
}
}
void RangeCheck( const Vec<Entry>& bookToCheck )
{
try
{
for( int i=0; i<1000; i++ )
cout << hex << (bookToCheck)[i].number;
}
catch(out_of_range)
{
cerr << "Bad Range" << endl;
}
catch(...)
{
cerr << "Unknown Error" << endl;
}
}
void RangeCheck( const vector<Entry>& bookToCheck )
{
try
{
for( int i=0; i<1000; i++ )
cout << hex << (bookToCheck)[i].number;
}
catch(out_of_range)
{
cerr << "Bad Range" << endl;
}
catch(...)
{
cerr << "Unknown Error" << endl;
}
}
/*******************************************************************************************
由于时间紧,就只写了这个无用的东西
注意同样是越界,vector是Unknown Error, 而Vec是Bad range。
vc6编译通过
ps:
Dev-C++允许以下的写法:
int main()
try
{......}
catch(...)
{.....}
但vc就不行,只能老老实实的写:
int main()
{
try
{......}
catch(...)
{.....}
}
虽然就是一个大括号的问题,但有时候就是能急死人。看来括号还是不省为好
********************************************************************************************/
3、map的使用,详见注释
//Liukai @ HUST
//2006-7-17
/****************************************************************************************
标准库中map的简单使用
定义一个(姓名,号码)对,并进行查询
没什么特别之处,速战速决
*****************************************************************************************/
#pragma warning(disable:4786)
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef map<string, int> STRING2INT;
int main( void )
{
STRING2INT nameages;
nameages.insert( STRING2INT::value_type("Tom",23) );
nameages.insert( STRING2INT::value_type("Jim",22) );
nameages.insert( STRING2INT::value_type("Jerry",21) );
nameages.insert( STRING2INT::value_type("Tony",25) );
nameages.insert( STRING2INT::value_type("Mike",13) );
nameages.insert( STRING2INT::value_type("Tom",33) );
nameages.insert( STRING2INT::value_type("Tom",23) );
string request;
cout << "Enter a name:";
cin >> request;
while( request != "quit" )
{
if( int i = nameages[request] )
{
cout << i << endl;
}
else
{
cout << "Can't find such person!" << endl;
}
cout << "Enter a name:";
cin >> request;
}
return 0;
}
/********************************************************************************************
map的插入方式很奇怪,需要慢慢适应
vc6.0编译通过
*********************************************************************************************/
4、有了以上的那些准备,我就打算做一些东西了。花了不少时间,做的小玩意还是很差劲。不过,我想已经起到了作用。在Debug的过程中,我确实熟悉了这些标准容器、迭代器的基本使用。详见注释
//Liukai @ HUST
//2006-7-17
/********************************************************************************************
文字绘图程序:
由于没有可用的绘图库,将用文字描述替代
可接受命令文字
存储图元对象
必要时展示
使用标准库编程
********************************************************************************************/
#pragma warning(disable:4786)
#include <iostream>
#include <map>
#include <vector>
#include <string>
#include <cstring>
#include <list>
#include <iterator>
#include <algorithm>
#include <cmath>
#include <fstream>
using namespace std;
//全局函数
void ToLow(char&);
/*********************************************************************************************
Shape Classes
**********************************************************************************************/
struct Point
{
double X;
double Y;
};
class Shape
{
private:
Point center;
static unsigned long number;
public:
Shape( double x, double y )
:id(++number)
{
center.X = x;
center.Y = y;
}
Point where()
{
return center;
}
virtual int draw() = 0;
virtual void output(ostream&) = 0;
const int id;
};
//static
unsigned long Shape::number = 0;
/
class Circle : public Shape
{
private:
double Radius;
public:
int draw();
Circle( double x, double y, double r )
:Shape(x,y)
{
Radius = r;
}
double getRadius()
{
return Radius;
}
friend ostream& operator<<( ostream&, Circle );
void output(ostream&);
};
int Circle::draw()
{
cout << endl << "There is a Cicle at ( " << where().X << ", "<< where().Y << " )";
cout << "its radius is " << Radius << endl;
cout << "id=" << id << endl;
return 0;
}
ostream& operator<< ( ostream& ostr, Circle thisCircle )
{
string icon = "circle";
ostr << icon << ' ' << thisCircle.where().X << ' ' << thisCircle.where().Y << ' '<< thisCircle.getRadius() << '/n';
return ostr;
}
void Circle::output(ostream& ostr)
{
string icon = "circle";
ostr << icon << ' ' << where().X << ' ' << where().Y << ' '<< getRadius() << ' ' << 0.0 << '/n';
}
/
class Rect : public Shape
{
private:
double Height;
double Width;
public:
int draw();
void output(ostream&);
Rect( double x, double y, double h, double w )
:Shape( x, y )
{
Height = h;
Width = w;
}
double getHeight()
{
return Height;
}
double getWidth()
{
return Width;
}
friend ostream& operator<<( ostream&, Rect );
};
int Rect::draw()
{
cout << endl << "There is a Rectangle at ( " << where().X << ", "<< where().Y << " )";
cout << "its Height is " << Height << ", and its Width is " << Width << endl;
cout << "id=" << id << endl;
return 0;
}
void Rect::output(ostream& ostr)
{
string icon = "rect";
ostr << icon << ' ' << where().X << ' ' << where().Y << ' ' << getHeight() << ' ' << getWidth() << '/n';
}
//为什么不能访问私有成员?
ostream& operator<<( ostream& ostr, Rect thisRect )
{
string icon = "rect";
ostr << icon << ' ' << thisRect.where().X << ' ' << thisRect.where().Y << ' ' << thisRect.getHeight() << ' ' << thisRect.getWidth() << '/n';
return ostr;
}
///
class Line : public Shape
{
private:
double X2;
double Y2;
public:
int draw();
void output(ostream&);
Line( double x1, double y1, double x2, double y2 )
:Shape( x1, y1 )
{
X2 = x2;
Y2 = y2;
}
double getX2()
{
return X2;
}
double getY2()
{
return Y2;
}
friend ostream& operator<<( ostream&, Line );
};
int Line::draw()
{
cout << endl << "There is a Line form ( " << where().X << ", "<< where().Y << " )";
cout << " to ( " << X2 << ", " << Y2 << " )" << endl;
cout << "id=" << id << endl;
return 0;
}
ostream& operator<<( ostream& ostr, Line thisLine )
{
string icon = "line";
ostr << icon << ' ' << thisLine.where().X << ' ' << thisLine.where().Y << ' ' << thisLine.getX2() << ' ' << thisLine.getY2() << '/n';
return ostr;
}
void Line::output( ostream& ostr )
{
string icon = "line";
ostr << icon << ' ' << where().X << ' ' << where().Y << ' ' << getX2() << ' ' << getY2() << '/n';
}
//
class Arc : public Shape
{
private:
double FromDegree;
double ToDegree;
public:
int draw();
void output(ostream&);
Arc( double cx, double cy, double fd, double td )
:Shape(cx,cy)
{
FromDegree = fmod(fd,360);
ToDegree = fmod(td,360);
}
double getFrom()
{
return FromDegree;
}
double getTo()
{
return ToDegree;
}
friend ostream& operator<<( ostream&, Arc );
};
int Arc::draw()
{
cout << endl << "There is a Arc, its center is ( " << where().X << ", "<< where().Y << " )";
cout << " it is from " << FromDegree << " degree, to " << ToDegree << " degree" << endl;
cout << "id=" << id << endl;
return 0;
}
ostream& operator<<( ostream& ostr, Arc thisArc )
{
string icon = "arc";
ostr << icon << ' ' << thisArc.where().X << ' ' << thisArc.where().Y << ' ' << thisArc.getFrom() << ' ' << thisArc.getTo() << '/n';
return ostr;
}
void Arc::output( ostream& ostr )
{
string icon = "arc";
ostr << icon << ' ' << where().X << ' ' << where().Y << ' ' << getFrom() << ' ' << getTo() << '/n';
}
//
//存放shape的list
typedef list<Shape*> ShapeList;
//Add 函数集
namespace Add_Funcs
{
void Add_Circle( ShapeList& );
void Add_Rect( ShapeList& );
void Add_Line( ShapeList& );
void Add_Arc( ShapeList& );
void Add_Circle( ShapeList& theList )
{
double x;
double y;
double r;
cout << "The Center of the Circle:/nx=";
cin >> x;
cout << "y=";
cin >> y;
cout << "The Radius of the Circle:/nr=";
cin >> r;
Circle* newcircle = new Circle( x, y, r );
theList.push_back(newcircle);
}
void Add_Rect( ShapeList& theList )
{
double x;
double y;
double h;
double w;
cout << "The Center of the Rectangle:/nx=";
cin >> x;
cout << "y=";
cin >> y;
cout << "The Height and Width of the Rectangle:/nHeight=";
cin >> h;
cout << "Width=";
cin >> w;
Rect* newrect = new Rect( x, y, h, w );
theList.push_back( newrect );
}
void Add_Line( ShapeList& theList )
{
double x1,y1;
double x2,y2;
cout << "The Fist Point of the Line:/nx1=";
cin >> x1;
cout << "y1=";
cin >> y1;
cout << "The Second Point of the Line:/nx2=";
cin >> x2;
cout << "y2=";
cin >> y2;
Line* newline = new Line( x1, y1, x2, y2 );
theList.push_back( newline );
}
void Add_Arc( ShapeList& theList )
{
double x;
double y;
double fd; //从哪里开始
double td; //到哪里结束
cout << "The Center of the Arc:/nx=";
cin >> x;
cout << "y=";
cin >> y;
cout << "The Head Degree of the Arc:";
cin >> fd;
cout << "The Tail Degree of the Arc:";
cin >> td;
Arc* newarc = new Arc( x, y, fd, td );
theList.push_back( newarc );
}
}//End namespace Add_Funcs
namespace Dels
{
bool checkId( const Shape* ); //删除用的谓词
unsigned long IdToDel; //要删除的id
bool checkId( const Shape* thisShape )
{
return thisShape->id == IdToDel;
}
}//End namespace Dels
//与文件i/o有关的函数集
namespace FileIo
{
void SaveToFile( ShapeList&, string fileName );
void LoadFile( ShapeList&, string );
void FileNameProcess( string& ); //使其成为合法的文件名
void WriteRecordToFile( Shape* );
void ReadRecord( ShapeList& , string, vector<double>& );
string curFileName = "Untitled.shp";
string FileAppendix = ".shp";
ofstream os;
ifstream eof;
class CannotWrite{};
class CannotRead{};
void SaveToFile( ShapeList& theList, string fileName )
{
os.open(fileName.c_str(),'/n');
for_each( theList.begin(), theList.end(), WriteRecordToFile );
os.close();
}
void WriteRecordToFile( Shape* thisShape )
{
if( os.is_open() )
{
thisShape->output(os);
}
else
{
throw CannotWrite();
}
}
void LoadFile( ShapeList& theList, string fileName )
{
try
{
ifstream is;
is.open( fileName.c_str() );
if( !is.is_open() )
throw CannotRead();
//将一条条的记录分离出来
string icon;
vector<double> data(10);
while( is != eof )
{
is >> icon;
if( !is )
break;
for( int i =0; i<4; i++ )
is >> data[i];
ReadRecord(theList,icon,data);
}
is.close();
}
catch(...)
{
throw CannotRead();
}
}
void ReadRecord( ShapeList& theList, string icon, vector<double>& data)
{
Shape* newShape;
if( icon == "circle" )
{
newShape = new Circle( data[0], data[1], data[2] );
}
else if( icon == "rect" )
{
newShape = new Rect( data[0], data[1], data[2], data[3] );
}
else if( icon == "line" )
{
newShape = new Line( data[0], data[1], data[2], data[3] );
}
else if( icon == "arc" )
{
newShape = new Arc( data[0], data[1], data[2], data[3] );
}
else
{
throw CannotRead();
}
theList.push_back( newShape );
}
void FileNameProcess( string& FName )
{
if( FName.find(".") >= FName.length() )
{
FName += FileAppendix;
}
}
}//End namespace FileIo
//直接由命令控制的函数集
namespace Control
{
void CtrlAdd( ShapeList& ); //增加一个图形的处理
void CtrlDel( ShapeList& ); //删除一个图形的处理
void CtrlShow( ShapeList& ); //画出所有图形,即刷新
void CtrlLoad( ShapeList& ); //从文件读出图形
void CtrlSave( ShapeList& ); //保存图形到文件
void CtrlHelp( ShapeList& ); //帮助
//这里要声明形状命令与生成该类型函数的映射
typedef void (*AddFunc)( ShapeList& );
typedef map<string,AddFunc> AddMap;
void CtrlAdd( ShapeList& theList )
{
try
{
cout << "Now Add!" << endl;
//建立命令与具体add函数的映射
AddMap theAddMap;
theAddMap.insert( AddMap::value_type("circle",&Add_Funcs::Add_Circle) );
theAddMap.insert( AddMap::value_type("rectangle",&Add_Funcs::Add_Rect) );
theAddMap.insert( AddMap::value_type("line",&Add_Funcs::Add_Line) );
theAddMap.insert( AddMap::value_type("arc",&Add_Funcs::Add_Arc) );
string which;
AddFunc ToDo;
do
{
cout << "Which Shape to add?" << endl;
cin >> which;
for_each( which.begin(), which.end(), ToLow );
ToDo = theAddMap[which];
if(!ToDo)
cout << "No Such Shape." << endl;
}while(!ToDo);
//调用所选
ToDo( theList );
cout << "Add complete." << endl;
}
catch(...)
{
cerr << "Add failed." <<endl;
}
}
void CtrlDel( ShapeList& theList )
{
cout << "Now Del" << endl;
CtrlShow( theList );
unsigned long idToDel;
cout << "Enter the id number to delete:";
cin >> idToDel;
Dels::IdToDel = idToDel;
ShapeList::iterator iterToDel;
iterToDel = find_if( theList.begin(), theList.end(), Dels::checkId );
if( iterToDel == theList.end() )
{
cout << "No such id!" << endl;
}
else
{
delete *iterToDel;
theList.remove(*iterToDel);
}
}
void CtrlShow( ShapeList& theList )
{
for_each( theList.begin(), theList.end(), mem_fun(&Shape::draw) );
}
void CtrlLoad( ShapeList& theList )
{
try
{
string FileNameToLoad;
cout << "Now Load from a file, please input the name of the file." << endl;
cin >> FileNameToLoad;
FileIo::FileNameProcess( FileNameToLoad );
FileIo::LoadFile( theList, FileNameToLoad );
FileIo::curFileName = FileNameToLoad;
cout << FileIo::curFileName << " has been successfully read./n";
}
catch( FileIo::CannotRead )
{
cerr << "Can't Read Data from the file!" << endl;
}
catch(...)
{
cerr << "Unknown File Error." << endl;
}
}
void CtrlSave( ShapeList& theList )
{
try
{
string FileNameToSave;
cout << "Now save to a file, please input the name of the file." << endl;
cin >> FileNameToSave;
FileIo::FileNameProcess(FileNameToSave);
FileIo::SaveToFile(theList,FileNameToSave);
FileIo::curFileName = FileNameToSave;
}
catch( FileIo::CannotWrite )
{
cerr << "Can't Write Data to the file!" << endl;
}
catch( ... )
{
cerr << "Unknow File Error." << endl;
}
}
void CtrlHelp( ShapeList& theList )
{
cout << "Here is the help:" << endl;
}
}//End namespace Control
//map:从全局命令字符串到相应的函数指针
///
typedef void (*CtrlFunc)( ShapeList& );
typedef map<string, CtrlFunc > CtrlMap;
///
//转化大小写的函数
inline void ToLow( char& from )
{
if( isalpha(from) )
from = tolower(from);
}
//驱动程序
int main( void )
{
ShapeList theShapeList;
//建立起命令到函数的映射
CtrlMap theCtrlMap;
theCtrlMap.insert( CtrlMap::value_type("add", &Control::CtrlAdd) );
theCtrlMap.insert( CtrlMap::value_type("delete", &Control::CtrlDel) );
theCtrlMap.insert( CtrlMap::value_type("show", &Control::CtrlShow) );
theCtrlMap.insert( CtrlMap::value_type("load", &Control::CtrlLoad) );
theCtrlMap.insert( CtrlMap::value_type("save", &Control::CtrlSave) );
theCtrlMap.insert( CtrlMap::value_type("help", &Control::CtrlHelp) );
string command;
cout << "Command--->";
cin >> command;
//将大写字母全部转化为小写,使得命令对大小写不敏感
for_each( command.begin(), command.end(), &ToLow );
while( command != "quit" )
{
CtrlFunc ChosnFunc = theCtrlMap[command];
if(!ChosnFunc)
{
cout << "Unkown Command" << endl;
}
else
{
ChosnFunc( theShapeList );
}
cout << "Command--->";
cin >> command;
for_each( command.begin(), command.end(), &ToLow );
}
return 0;
}
/*********************************************************************************************
六百多行的程序仍然什么都做不了,况且这个程序还相当的不完美,尤其在文件流和异常处理方面
但它已经能基本模拟一个绘图程序——增加新的图元,删除一个图元,刷新当前图形,保存到文件,
从文件读入等等
花了一个下午家一个晚上,这个时间还是值得的。从这个程序中我确实学到了很多东西,比如第一次
真正使用map来简化代码——我建立了很多命令字符串到函数指针的映射
关于多态,我除了应用到最经典的draw()以外,还“自创”了一套多态流函数:virtual output(ostream&)
用来使每个具体类型知道自己如何写入文件——但麻烦出现在读文件的时候。
我们使用多态,就我所知,都是有了那么一集各种具体类型的对象,然后用基类的指针或引用去访问它们
各自的成员函数,这个很简单,“写入文件”的函数就是这种简单情况。然而,我根本不知道如何从读出
的文件流中识别各种类型——即使用一种标识符识别了——也无法“多态地”建立这些对象。为了实现这
读文件的功能,我被迫使用丑陋的if else连环组合,从而放弃了可扩充性。
中间我走了一次弯路,这却使我有所发现。我开始用friend ostream& operator<<(ostream&,Circle)
时候,发现这个友元函数根本不能访问私有成员,搞得我很困惑。而且在我用一种笨方法解决了这个问题
以后,才发现这东西根本不能多态——只有成员函数才能是virtual
还有文件输入流,也是很头疼的。namespace FileIo里我本来是声明了一个istream is的,但发现这东西
在读过一次文件以后,读第二次就不行了——不知道为什么,但可以把它改为局部变量来避免这个问题
**********************************************************************************************/
5、关于编译环境。我使用的IDE是vc6,配合使用Dev-c++。下面的例子是书上的原例,但在vc下就是不能通过,只能用Dev-c++。而上面的那个600多行的程序却只能在vc下通过。真是的……,头疼的环境……
//Liukai @ HUST
//2006-7-16
/*******************************************************************************
这是《C++ Prgramming Language》上的一个例子,为了说明输入流迭代器的用途
本例中,将用一个文件输入流的迭代器生成一个vector<string>
********************************************************************************/
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;
void print( const string& str )
{
cout << str << endl;
}
int main( void )
{
string from, to;
cin >> from >> to; //Input File Name
ifstream is( from.c_str() );
istream_iterator<string> ii(is);
istream_iterator<string> eos;
vector<string> b(ii,eos);
sort(b.begin(),b.end());
// string s;
// while( ii != eos ) //注释掉的是我在vc下的替代方案
// {
// s=*ii;
// b.push_back(s);
// ii++;
// }
// copy(ii,eos,back_inserter(b));
for_each( b.begin(), b.end(), print );
ofstream os( to.c_str() );
ostream_iterator<string> oo(os,"/n");
unique_copy( b.begin(), b.end(), oo );
return !is.eof() || !os;
}
/***********************************************************************************************
注:本例在Dev-C++ 4.9.9.2下调试通过,在vc中通不过。
可能vc6.0对流迭代器构造vector不支持
************************************************************************************************/