总结:
另有一篇文章 A*算法和代码:http://blog.csdn.net/lmnxjf/article/details/8917679
A*算法,寻找最优路线的高效方法。
目录
1 STL
2 二维数组动态分配内存
3 带模板参数的模板类
4 类型转换
5 小知识点
6 函数指针
7 逗号表达式
8 运行时类型转换
9 类里面的小知识点
10 建立动态链接库
个人笔记,记录一些基础,但是又经常用到的C++方法。 不断整理ing
1、 STL
(1) vector 迭代器的使用
vector<string> title(10);// 申请一个十个string的vector容器
vector<string>::iterator p;// 声明一个迭代器
p= title.begin();
// 这是就可以对p取值, 累加
cout<<*p++<<endl<<*p<<endl;//输出 title[0],title[1]
title.push_back() 它将元素添加到矢量末尾,此时title的容积增了1个元素。
验证代码:
int main()
{
vector<int > pp(100);
vector<int>::iterator p;
int i=0;
for(p= pp.begin(); p!=pp.end(); p++)
{
pp[i]=i;
i++;
}
cout<<(pp.end()-pp.begin())<<endl;
pp.push_back(12);
pp.push_back(12);
cout<<(pp.end()-pp.begin())<<endl;
}
输出:
title.erase(title.begin(), tetle.begin()+2);// 擦除开始的两个元素(删除的元素为 [参数1, 参数2)即不删除参数2所指向的元素) 如果第一个参数 大于第二个参数,将不做删除。
vector 中自定义排序问题,random_shuffle 函数随机排列区间的元素, sort 按规则排序,通过自己定义函数返回bool量决定。代码中实现降序排序。
#include<iostream>
#include <string>
#include<vector>
#include<algorithm>
#include<iterator>
using namespace std;
void Dispaly(int p)
{
cout<<p<<endl;
}
bool NewSort(int p,int q)
{
if (p>q)
return true;
else
return false;
}
void AddData(int& a)
{
static int i=0;
a=i;
++i;
}
int main()
{
vector<int > pp(20);
vector<int>::iterator p;
//for(p= pp.begin(); p!=pp.end(); p++)
//{
// pp[i]=i;
// i++;
//}
ostream_iterator<int, char> out_iter(cout,"\n");// \n为没输出一个元素后的分隔符
for_each(pp.begin(), pp.end(),AddData);
random_shuffle(pp.begin(), pp.end());
sort(pp.begin(), pp.end(), NewSort);
//for_each(pp.begin(), pp.end(),Dispaly);
copy(pp.begin(), pp.end(), out_iter);
}
(2)
copy此处的作用是将数据复制到到显示器中, 模板ostream_iterator是输出迭代器概念的一个模型。需要包含头文件 iterator,out_iter迭代器现在是一个接口让你可以使用cout来显示信息。 模板中第一个参数(这里为int)指出了输出的数据类型,第二个参数(char)指出了输出使用字符类型。
通样输入也可以使用输入输出迭代器。 copy(istream_iterator<int, char>(cin), istream_iterator<int,char>(), pp.begin())// 作用从输入流中读取,知道文件结尾、类型不匹配或者出现错误为止。
reverse_iterator反向迭代器(目的是代码重用),例如 rbegin() 返回一个指向超尾的反向迭代器,rend()返回一个指向第一个元素的反向迭代器。copy(pp.rbegin, pp.rend(), out_iter);可以反向显示内容。 对rbegin()递增就是将导致它递减。
vector<int>::reverse_iterater reverp;
for(reverp=pp.rbegin; reberp!= pp.rend;++ reverp)
cout<<*reverp<<" ";
reverp= pp.rbegin(),指向超尾,rend()返回第一个元素的位置因此不能对其进行解除引用,反向指针通过先递减,再解除引用解决了这两个问题。
*注意:rbegin(), 和end() 返回一样的超尾值,但是类型不同。
int main()
{
string str[4]={"1","2","3","4"};
string str1[2]={"one","two"};
string str2[2]={"three","four"};
vector<string> word(4);
copy(str, str+4, word.begin());
ostream_iterator<string, char>out(cout, " ");
copy(word.begin(), word.end(), out);
//back_inser_iterator
cout<<endl;
copy(str1, str1+2, back_insert_iterator<vector<string>>(word));//在word 的尾部加
copy(word.begin(), word.end(), out);
cout<<endl;
// insert_iterator
copy(str2, str2+2,insert_iterator<vector<string>>(word, word.begin()+2));
copy(word.begin(), word.end(), out);
cout<<endl<<"down!"<<endl;
}
输出:
小结: 迭代器就像指针,遍历整个容器可以使用 for(p=title.begin(); p!=title.end(); ++p。vector可以说是数据的类的表示,它提供自动内存管理功能,可以动态改变vector对象长度,并随着元素的添加和删除而增大和减小。在尾部添加和删除元素时间是固定的,但在头部或中间插入和删除元素时间复杂度为线性的。
2、 二维数组动态分配内存
int** erwei= (int**) new int[SIZE1];
for(int i=0; i<SIZE1; i++)
{
erwei[i]= new int[SIZE2];
//*(erwei+1)= new int[SIZE2]
}
//释放内存
for(int i=0; i<SIZE1;i++)
{
delete []erwei[i];
}
delete []erwei;
3 带模板参数的模板类
#include<iostream>
using namespace std;
template <class T>
class Array
{
public:
Array(){};
Array( T i ):data_a( i ){}
void Display(){cout<<"Arry display "<<endl;}
private:
T data_a;
};
//template<class T, template<class>class A>其中
//class T 是模板B的第一个参数, 而template<class> class A
//说明第二个参数是一个模板参数 也说明了类模板A是一个又一个参数的模板参数
// 同样也可以写成 template<class T, template<class Q>class A>
template<class T, template<class>class A>
class B
{
public:
B(){cout<<"construction of b: "<<endl;}
void Display(){ a.Display(); cout<<"B display: "<<endl;}
private:
T data_b;
A<T> a;
};
int main()
{
Array<int> mya(3);
B<int, Array> b;
b.Display();
}
假设要将一个int类型转换为double。在c标准中可以这样
int num1, num2;
double num3= ((bouble)num1)/ num2;
如果采用新的c++转换法:
double num3=static_cast<double>(num1)/num2;
而将一个const常量转换为一个变量应用const_cast.即可用const_cast去点对象的常量性。
# dynamic_cast,可以将base class objects的pointers或references转换为 指向derived class objects的pointers 或 references.
Widget *pw;
...
update(dynamic_cast<SpecialWidget*>pw); 将pw指向的widget转换为派生类的specialwidget。
int* p = new int(0);
auto_ptr<int> ap1(p);
auto_ptr<int> ap2(p);
//因为ap1与ap2都认为指针p是归它管的,在析构时都试图删除p, 两次删除同一个对象的行为在C++标准中是未定义的。所以我们必须防止这样使用au//to_ptr.
~A
{
try
{
// 可能依法异常的操作
}
catch(...)//catch中什么也不做 就是不让异常跑出到析构函数的外面
{}
}
异常跑出的都是参数的副本,以为在函数中异常跑出时,这个函数已经失去了控制权,所以这个函数中的变量也就没有存在的意义了,因此必须使用参数的副本。
catch(Widget& w)
{
...
throw;
}
catch(Widget& w)
{
...
throw w;
}
这两个catch的唯一区别就是,前者抛出的是当前的exception, 后者跑出的是当前exception的副本。 一般使用throw抛出当前异常原因之一就是没有复制行为,速度更快。
# 异常捕捉中部存在隐式转换, 这和函数调用时有区别的。
try
{
int value;
if(fountion())
throw value;
}
catch(double b)
{
...
}
#include<iostream>
using namespace std;
typedef void (*CallBackPtr)(int x, int y,int data);
void display(int x, int y,int data)
{
cout<<"x "<<x<<" y "<<y<<" data "<<data<<endl;
}
int main()
{
CallBackPtr pcall;
pcall=display;//f好乐迪封建礼教
pcall(2,4, 5);
}
逗号表达式的形式如下:
表达式1,表达式2,表达式3,...... ,表达式n
逗号表达式的要领:
(1) 逗号表达式的运算过程为:从左往右逐个计算表达式。
(2) 逗号表达式作为一个整体,它的值为最后一个表达式(也即表达式n)的值。
(3) 逗号运算符的优先级别在所有运算符中最低。
#include<iostream>
#include<vector>
using namespace std;
class Security
{
protected:
enum{ BASEID = 0};
public:
virtual ~Security(){};
virtual bool IsA(int id) {return id == BASEID;}
};
class Stock: public Security
{
typedef Security Super;
protected:
enum {OFFSET =1,TYPEID = OFFSET + BASEID};
public:
virtual bool IsA(int id) {return id == TYPEID || Super::IsA(id);}
static Stock* dynacast(Super* s)
{
return (s->IsA(TYPEID))? static_cast<Stock*>(s) : 0;
}
};
class Bond: public Security
{
typedef Security Super;
protected:
enum {OFFSET =2,TYPEID = OFFSET + BASEID};
public:
virtual bool IsA(int id) {return id == TYPEID || Super::IsA(id);}
static Bond* dynacast(Super* s)
{
return (s->IsA(TYPEID))? static_cast<Bond*>(s) : 0;
}
};
class Investment: public Security
{
typedef Security Super;
protected:
enum {OFFSET =3,TYPEID = OFFSET + BASEID};
public:
virtual bool IsA(int id) {return id == TYPEID || Super::IsA(id);}
static Investment* dynacast(Super* s)
{
return (s->IsA(TYPEID))? static_cast<Investment*>(s) : 0;
}
void Special()
{
cout<<"special investment function"<<endl;
}
};
class Metal: public Investment
{
typedef Security Super;
protected:
enum {OFFSET =4,TYPEID = OFFSET + BASEID};
public:
virtual bool IsA(int id) {return id == TYPEID || Super::IsA(id);}
static Metal* dynacast(Super* s)
{
return (s->IsA(TYPEID))? static_cast<Metal*>(s) : 0;
}
};
int main()
{
vector<Security*> portfolio;
portfolio.push_back(new Metal);
portfolio.push_back(new Investment);
portfolio.push_back(new Bond);
portfolio.push_back(new Stock);
portfolio.push_back(new Security);
for (vector<Security*>::iterator it = portfolio.begin(); it!= portfolio.end(); ++it)
{
Investment* cm = Investment::dynacast(*it);
if (cm)
{
cm->Special();
}
else
cout<<"not an Investment"<<endl;
}
cout<<"cast from intermediate pointer:"<<endl;
Security* sp =new Metal;
Investment* cp = Investment::dynacast(sp);
if (cp)
{
cout<<"it is Investment"<<endl;
}
Metal* mp = Metal::dynacast(sp);
if (mp)
{
cout<<"is is Metal"<<endl;
}
cout<<typeid(sp).name()<<endl;
cout<<typeid(cp).name()<<endl;
cout<<typeid(*sp).name()<<endl;
}
查看动态链接库中导出的函数, 可以在命令行中先到工程目录, 使用vc提供的,dumpbin XX.dll 来查看
//extern int add(int a, int b);
//extern int substract(int a, int b);
_declspec(dllimport) int add(int a , int b);
_declspec(dllimport) int substract(int a, int b);
用extern声明表明其是在外部定义的函数, 而利用_declspec(dllimport) 表明其在动态链接库中, 这时编译器可以生产更加高效的代码,所以一般使用_declspec(dllimport)来导入函数。
_declspec(dllimport) int add(int a, int b);
_declspec(dllimport) int substract(int a, int b);
import表明函数是从动态链接库中导入的。
//mydll.h
#ifdef MYDLL_API
#else
#define MYDLL_API _declspec(dllimport)
#endif
MYDLL_API int add(int a, int b);
MYDLL_API int substract(int a, int b);
//其中 若将注释去掉,则说明导出的是整个类
class /*MYDLL_API*/ Point
{
private:
int m_a;
int m_b;
public:
Point(int a=0, int b=0):m_a(a), m_b(b){};
MYDLL_API void OutPut() const;
};
.cpp
#define MYDLL_API _declspec(dllexport)
#include"mydll.h"
#include<iostream>
int add(int a, int b)
{
return a+b;
}
int substract(int a, int b)
{
return a-b;
}
void Point::OutPut()const
{
using std::cout;
using std::endl;
cout<<"m_a "<< m_a<<",m_b "<<m_b<<endl;
}
extern "C" _declspec(dllexport) 加入 extern“C”后是一C标准导出函数,即函数名不发生改变。 add导出的函数名还是 add,但是这个方法只能用于导出全局函数,不能用于导出类的成员函数。
#自定义导出函数的格式,可以在工程中新建一个txt文档,将后缀改为.def,文件名改成工程文件名(不是必需的)。在.def文件中添加要导出函数的名字
EXPORTS
add @1
substract @2
display @3
#include<iostream>
#include<Windows.h>
//#include"..\..\MyDll\MyDll\mydll.h"
//#pragma comment( lib, "..\\debug\\libTest.lib" ) //指定与静态库一起连接
using namespace std;
//extern int add(int a, int b);
//extern int substract(int a, int b);
//_declspec(dllimport) int add(int a , int b);
//_declspec(dllimport) int substract(int a, int b);
int main()
{
HINSTANCE hInst;
hInst = LoadLibrary("MyDll2.dll");
typedef int (*ADDPROC)(int a, int b);
ADDPROC Add = (ADDPROC)GetProcAddress(hInst, MAKEINTRESOURCE(1));
ADDPROC Substract = (ADDPROC)GetProcAddress(hInst, "substract");
int sum= Add(2,4);
int sub = Substract( 4, 3);
cout<<sum<<endl<<sub<<endl;
FreeLibrary(hInst);
}