C++全总结
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了C++全总结,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含43280字,纯文字阅读大概需要62分钟。
内容图文
1 // CPPTEST.cpp : 定义控制台应用程序的入口点。 2 // 3 4 #include "stdafx.h" 5 #include<iostream> 6 #include <map> 7 #include<fstream> 8 #include<cassert> 9 #include <sstream> 10 #include"TMyNumOperator.h" 11 #include"abc.h" 12 #include <list> 13 #include<thread> 14 #include <vector> 15 #include <algorithm> 16usingnamespace std; 17using std::cin; 18using std::cout; 19 20//using namespace std; 21// 22//class CBase{ 23//protected://注意,可以使用C#风格的定义时初始化 24// std::string name = "NoOne"; 25// int age = -20; 26// int sex = 1; 27//public: 28// float *pData = new float[20]{1, 2, 3, 4, 5}; 29//public: 30// virtual ~CBase(){//虚析构函数,防止内存泄漏:对基类指针调用delete时,会从子类一直析构到基类 31// cout << "~cbase" << endl; 32// } 33//}; 34// 35////基类的私有成员不会被继承,这和C#完全一样 36//class CStudent : public CBase{ 37//public: 38// std::map<int, std::string> _projs; 39// CStudent(){ 40// pData = new float[20]{1, 2, 3, 4, 5}; 41// } 42//public: 43// void SetName(const std::string& name){ 44// CBase::name = name;//如果CBase.name定义为私有,这里就不可访问 45// this->name = name; //等价于上一行 46// } 47// 48// const string& GetName(){ 49// return this->name; 50// } 51// 52// ~CStudent(){//若采用浅拷贝,析构函数被调用多次,pData被删除多次,程序崩溃 53////规避方式:判断pData是否为空,非空才delete[] pData 54////但在不知情的情况下使用pData仍然会出问题,因此浅拷贝导致的问题不可规避 55// cout << "~cstudent" << endl; 56// delete[] pData; 57// pData = NULL; 58// } 59//}; 60// 61//void TestSTL(){ 62// 63// auto mp = new std::map<int, std::string>();//c++11新风格 auto 64// 65// mp->insert({ 10, ("h你好") });//c++11新风格,不用再使用std::pair()或std::make_pair() 66// mp->insert({ 20, "el" }); 67// for (auto var : *mp)//c++11新风格for 68// { 69// std::cout << var.first << "," << var.second << "," << std::endl; 70// } 71//} 72// 73//void TestClass(){ 74// CBase* pbase = new CStudent(); 75// auto pst = (CStudent*)pbase; 76// pst->SetName("xxxx"); 77// auto name = pst->GetName(); 78// delete pbase; 79//} 80// 81//int TestAdd(int a, int b){ 82// return a + b; 83//} 84//void TestStdFunc(std::function<int(int,int)> fun, int a, int b){ 85// auto ret = fun(a, b); 86//} 87// 88//typedef int(*TestAddPtr)(int, int); 89// 90//void TestPCall(TestAddPtr func, int a, int b){ 91// auto ret = func(a, b); 92//} 93// 94//struct Vertex{ 95// bool isgood; 96// float x, y, z; 97// double dx; 98// bool bx; 99// int ix; 100// bool by; 101//}; 102//void TestFile(){ 103// int szChar = sizeof(char); 104// ofstream ofs; 105// ofs.open("f:/test.txt"); 106// ofs << "hello " << 10 << " world " << 20 << endl; 107// 108// ofs.flush(); 109// ofs.close(); 110// 111// ifstream ifs; 112// ifs.open("f:/test.txt"); 113// string str1, str2; 114// int num1, num2; 115// 116// ifs >> str1 >> num1 >> str2 >> num2; 117// 118////错误示例:二进制读写,使用std::<<或>>进行的还是ASCII码的读写 119// ofstream ofsb; 120// ofsb.open("f:/testb", ios::binary); 121// ofsb << "hellob" << 1022; 122// 123// ofsb.flush(); 124// ofsb.close(); 125// ifstream ifsb; 126// 127// string sx; 128// int nx; 129// ifsb.open("f:/testb", ios::binary); 130// ifsb >> sx >> nx; 131// ifsb.close(); 132// 133////正确做法 134// sx = "binary"; 135// nx = 978; 136// ofsb.open("f:/testbx", ios::binary); 137// ofsb.write(sx.c_str(), sx.length()*sizeof(char)+1); 138// ofsb.write((const char*)&(nx), sizeof(int)); 139// ofsb.flush(); 140// ofsb.close(); 141// 142// char sxr[32]; 143// int nxr; 144// ifsb.open("f:///testbx", ios::binary);//注意这里的"///"不管有多少个/都等同于一个 145// ifsb.read(sxr, sx.length()+1); 146// ifsb.read((char*)&nxr, 4); 147// 148////数据转换的更通用方式 149// Vertex vt; 150// vt.bx = true; 151// vt.isgood = false; 152// vt.x = 12; 153// vt.y = 13; 154// vt.z = 14; 155// vt.dx = 3.9; 156// vt.by = 0; 157// 158// ofstream ofsbx; 159// ofsbx.clear(); 160// ofsbx.open("f:/testbyx2", ios::binary); 161// ofsbx.write((const char*)&(vt), sizeof(Vertex)); 162// ofsbx.flush(); 163// ofsbx.close(); 164// 165// ifstream ifsbx; 166// Vertex vrt; 167// ifsbx.clear(); 168// ifsbx.open("f:/testbyx2", ios::binary); 169// ifsbx.read((char*)&vrt, sizeof(Vertex)); 170// 171// string s1 = "hello"; 172// string s2 = "wrold"; 173// s1 = s1 + s2; 174// auto s3 = s1.substr(1, 2); 175//} 176// 177////实现较为高效的字符串分割,限制是分割符只能是一个字符,不能是一个串 178//std::list<string> TestStrSplit(string s, char sep){ 179// std::list<string> lst; 180// for (int i = 0, j = 0; i < s.length(); ++i){ 181// if (s[i] == sep){ 182// lst.push_back(s.substr(j, i - j)); 183// j = i + 1; 184// } 185// } 186// 187////注意临时对象作为返回值了,一般情况下这是错误的用法,栈上的临时对象出了函数域后会被释放 188////但这里STL容器内部重载了=运算符,作了值拷贝就没问题了 189// return lst; 190//} 191//void TestString(){ 192// 193////g正则表达式实现字符串分割 194// string s1 = "a;b;c;dddd;ef;"; 195// string s2 = "a123b2673cdd4444a"; 196// std::regex re("(\d+)"); 197// std::smatch mtch; 198// 199////这个做法效率挺低且浪费内存,产生了很多中间字符串 200// while (std::regex_search(s2, mtch, re, std::regex_constants::match_default)){ 201// cout << mtch.str() << endl; 202// s2 = mtch.suffix(); 203// } 204// 205////这个函数效率要高多了 206// auto lst = TestStrSplit(s1, ‘;‘); 207// 208//} 209// 210////返回栈上的临时对象测试 211//CStudent TestTempObjRet(){ 212// CStudent ost; //临时对象 213// return ost; //调用对象的拷贝构造函数 214//}//出了栈后ost被释放,析构函数调用,同时成员对象被析构CStudent.name="",但内置类型仍保持原值 215// 216////通过测试可知,将栈上对象作为函数返回值使用一般是没有问题的,但浅COPY时两个对象中的指针指向同一份 217////内存,当一个对象被删除时,另一个对象中的指针就指向非法位置了,成了野指针 218//void TestObjConstructorAndDestructor(){ 219// CStudent ostx; 220// ostx = TestTempObjRet(); //调用拷贝构造函数(与上面对应) 221// auto name = ostx.GetName(); 222// auto px = ostx.pData; 223//} 224// 225//void TestRRef(){ 226// 227//} 228// 229////可以使用随机访问(数组下标)说明vector在内存中是连续存放的 230////这样,vector在需要扩充容量时就需要将原来内存删除,再申请一块新内存 231////但这并不一定,因为内存申请时若用realloc则有可能会在原内存后面增加(原理) 232//void TestVector(){ 233// std::vector<string> sv{ "hello", "world" }; 234// sv[0]; 235// sv[1]; 236// 237// sv.reserve(20); //旧的内容被清除 238// int n = sv.capacity(); //20 239// sv.push_back("a"); 240// sv.push_back("b"); 241// sv.clear(); //旧的内容被清除 242// n = sv.capacity(); //20 243// 244// sv.shrink_to_fit(); //内存释放 245// n = sv.capacity(); //0 246// 247//} 248// 249//struct CTA{ 250//private: 251// virtual void Test(){ 252// cout << "cta" << endl; 253// } 254// 255//}; 256// 257//class CCTA : CTA{//类和结构体可以相互继承 258//public: 259// int _id; 260// void Test() const{ 261// cout << "ccta-test" << endl; 262// } 263//}; 264// 265////C++中字符串有常量和变量之分,字符串遇到\0则结束 266////C#中只有常量字符串,字符串遇到\0不结束,视其为正常字符 267//void TestStr(){ 268// char* ps = "hello";//字符串常量,不可修改其内容 269// ps[0] = ‘d‘; //运行出错 270// 271// char arr[] = "hello"; //字符串变量 272// char* par = arr; 273// arr[0] = ‘d‘; //ok 274//} 275// 276////C++中指针字符串与数组字符串都是自动以0结尾的 277//void TestMemcpy(){ 278// 279// char dest[18]; 280// char src[] = "hell"; //以0结尾,长度为5,若强制声明为 char src[4] = "hell"则编译报错 281// char* psrc = "hell"; //以0结尾,长度为5,但测试长度strlen(psrc)为4,因为它没算尾0 282// 283// for (int i = 0; i < 10; ++i){ 284// 285// } 286// for (int i = 0, ch; (ch = psrc[i++]) != 0;){ 287////这里发现字符串尾0后有许多个0,不知道原因 288// 289// } 290// auto len = strlen(psrc); //4,测试长度,并没字符串的真实长度(内存中真实串),因为它有尾0 291// int len2 = strlen(src); //5,字符串实际长度(内存中存储的字符串) 292// int st = sizeof(src); //5,数组大小 293// memcpy(dest, psrc, strlen(psrc)+1); 294//} 295//template<typename T1, class T2> class MyVector{ 296// std::vector<int> _lst; 297// 298//public: 299// 300// void Test2(); 301//}; 302// 303//template<class T1, class T2> void MyVector<T1, T2>::Test2(){ 304// 305//} 306 307#pragma region 2018.7.7 308 [module(name = "mytestx")]; 309void TestIOStream() { 310 std::fstream fs; 311 fs.open("test.txt", ios_base::in | ios_base::out); 312 fs << 12 << "hello"; 313 314 fs.seekp(0); 315int ix1; 316string sx1; 317char chs[6]; 318 fs >> ix1; 319 fs >> chs; 320 chs[5] = 0; 321 sx1 = chs; 322 323 cout << ix1 << sx1.c_str() << endl; 324 325} 326void TestMacro() { 327#define hfunc(x) cout << x << endl; //自定义处起,全局可见 328 hfunc(124); 329#undef hfunc 330 331//typedf, using等价使用 332 typedef void(*PFUN)(int); 333using PFUNC = void(*)(int); 334 335using Int = int; 336using MyType = Int; 337} 338//数组和指针 339void TestArrayAndPointer() { 340//1,char* p : char类型指针,指向char数组, p++移动一个char 341//2,int* p : int型指针,指向int数组,p++移动一个int 342//3,char(*p)[2] : char[2]类型指针,指向char[2]类型数组,即char[][2]数组,p++移动一个char[2] 343//总结:X类型的指针指向X类型的数组, p++移动一个数组元素 344//如何看指针类型:去除*p剩下的就是类型,如char*p去掉*p为char,char(*p)[2]去掉*p为char[2] 345 346//======================================================== 347//指针总是指向数组的,如下,可认为是指向只有一个元素的数组 348//======================================================== 349int ix = 20; 350int*pix = &ix; 351 cout << pix[0] << "," << *pix << endl; 352 353//======================================================================================== 354//堆和栈上数组的初始化列表写法 355//======================================================================================== 356char arr[43] = { ‘a‘,‘b‘,‘c‘ }; 357char arr2[10] = { "hello" }; 358int iarr[] = { 1, 2, 3, 4 }; 359char*ps = newchar[30]{ 0 }; 360int* ips = newint[30]{}; 361int* ips2 = newint[30]; 362 363//cout << arr << "," << (void*)arr << (void*) ps << endl; 364char* px; 365 px = arr; //可以赋值,说明数组名与指针等价 366constchar* cp;//可以cp++; 367char* const cpx = arr; //不可以 cpx++,不能移动的指针,数组名其实就是这种指针 368 369//这里以arr与ps作对比,数组名与指针本质上都是指针,只是数组名是不能移动,不能赋值的常指针 370//在二维情形时也是如此 371 372 373 stringstream ss; 374//======================================================================================== 375//1,栈上二维数组,【内存连续】 376//======================================================================================== 377char a[][3] = {//二维数组初始化列表 378 { 98, 99, 100 }, 379 { 101, 102, 103 }, 380 }; 381for (int i = 0; i < 6; ++i) {//验证 382 ss << *(*a + i) << ","; 383 } 384 cout << ss.str() << endl; 385 386//============================================================================= 387//2,数组指针(也称行指针),【内存连续】 388//============================================================================= 389int(*pax)[4] = newint[3][4]; 390for (int i = 0; i < 3; ++i) { 391for (int j = 0; j < 4; ++j) { 392 pax[i][j] = i * 4 + j + 1; 393 } 394 } 395 396 ss.str(""); 397for (int i = 0; i < 12; ++i) {//验证 398 ss << *(*pax + i) << ","; 399 } 400 cout << ss.str() << endl; 401 402//============================================================================= 403//3,指针数组,【内存不连续】 404//============================================================================= 405//因为它是一个数组,所以不能用new来给它分配内存,new出来的东西只能赋值给指针 406char* arr_p[2]; 407 arr_p[0] = newchar[30]{ ‘h‘,‘e‘,‘o‘,‘l‘,‘l‘ }; 408 arr_p[1] = newchar[10]{ ‘a‘,‘b‘,‘c‘ }; 409 410 411//============================================================================= 412//4,多级指针用来分配二维数组,有【连续内存分配法】和【不连续内存分配法】 413//这个非常重要,若用一个不连续的二维数组指针进行memcpy操作,则会发生严重问题: 414//(1)数据拷越界,覆盖了其它变量甚至程序的内存 415//(2)dest变量中数据只填充了一部分,其余部分还是旧数据,导致程序出现莫名其妙的问题 416//(3)这种数据拷越界并无任何提示,隐蔽性极高,非常难以查找 417//============================================================================= 418int**pi = newint*[3]; 419int* ptemp = newint[12]; 420for (auto i = 0; i < 3; ++i) { 421//------------------------------------------------ 422//(1)【不连续内存分配法】 423//pi[i] = new int[2]; 424 425//------------------------------------------------ 426//(2)【连续内存分配法】 427 pi[i] = &((ptemp + i * 2)[0]); 428for (int j = 0; j < 2; ++j) { 429 pi[i][j] = i * 2 + j; 430 } 431 } 432for (int i = 0; i < 3; ++i) {//验证 433for (int j = 0; j < 2; ++j) 434 { 435 ss << pi[i][j] << ","; 436 } 437 } 438 cout << ss.str() << endl; 439 440} 441void TestInitialist() { 442class CIn { 443public: 444float x, y, z; 445string name; 446 447 }; 448 449//初始化列表的使用条件: 450//无自定义构造函数,成员公有,无基类,无虚函数 451//这么多限制,可以说很鸡肋 452 CIn oin = { 1, 2, 3, "hello" }; //方式1 453 CIn oin2 { 1, 2 ,3, "world" }; //方式2 454} 455#pragma endregion 456 457#pragma region 2018.7.9 458class CComplex { 459float real, image; 460public: 461 CComplex(float real, float image) { 462 cout << "constructor: " << real << "," << image << endl; 463this->real = real; 464this->image = image; 465 } 466 467 CComplex(const CComplex& other) { 468 cout << "copy constructor: " << other.real << "," << other.image << endl; 469if (this != &other) 470 { 471 real = other.real; 472 image = other.image; 473 } 474 } 475 ~CComplex() { 476 cout << "~ccomplex" << "(" << real <<"," <<image << ")" << endl; 477// real = 0; 478// image = 0; 479 480 } 481 482void PrintInfo() { 483 cout <<"Complex: " << real << "," << image<< endl; 484 } 485 486public: 487 488//------------------------------------------- 489//运算符重载 490//------------------------------------------- 491//1,重载为成员函数 492 CComplex operator+(const CComplex& other) { 493 cout << "operator+" << endl; 494return CComplex(real+other.real, image + other.image); 495 } 496 497 CComplex& operator++() {//前向++ 498 cout << "forward ++ " << endl; 499 real++; image++; 500return *this; 501 } 502 CComplex& operator++(int) {//后向++ 503 cout << "backward ++ " << endl; 504 505 real++; image++; 506return *this; 507 } 508const CComplex& operator=(const CComplex& other) { 509this->real = other.real; 510this->image = other.image; 511return *this; 512 } 513//2,重载为友元函数 514 friend CComplex operator+(float fx, const CComplex& cp); 515 516//3,【运算符重载函数不能定义为静态函数】 517//这与C#不同,C#中所有运算符重载都必须是public和static的 518//static CComplex operator+(float fx, const CComplex& cp); 519 520//4,类型转换运算符重载 521operatorbool() {//使用情景:CComplex oc; if(oc){}或if(oc != NULL){}或 float/int/bool x = oc 522return real != 0 && image != 0; 523 } 524operatorfloat() {//使用情景:CComplex oc; if(oc){}或if(oc != NULL){}或 float/int/bool x = oc 525return real; 526 } 527 528// CComplex operator=(const CComplex& other) { 529// if (this == &other) 530// return other; 531// return CComplex(other.real, other.image); 532// } 533 534void Testx() { 535 CComplex* pNewCom = new CComplex(2, 2); 536 pNewCom->real = 20;//可以访问私有成员?? 537 } 538}; 539// CComplex CComplex::operator+(float fx, const CComplex& cp) { 540// return CComplex(fx + cp.real, cp.image); 541// } 542 CComplex operator+(float fx, const CComplex& cp) { 543return CComplex(fx + cp.real, cp.image); 544} 545 546void TestCComplexOper() { 547int i = 10; 548 CComplex cpx(1, 2); 549 ++cpx++++; 550 cpx.PrintInfo(); 551} 552CComplex TestReturnStackObj() { 553//----------------------------------------------------------------- 554//返回栈上的对象 stackObj 555//返回栈上的对象会导致拷贝构造函数的调用,生成一个 556 CComplex stackObj(1, 2); 557return stackObj; 558 559return CComplex(1, 2); //这种方式直接调用构造函数,而不调用拷贝构造函数 560//----------------------------------------------------------------- 561} 562 563#pragma endregion 564 565#pragma region 2018.7.10 566void TestRealloc() { 567 cout << "---------------test-realloc---------------" << endl; 568 569int szch = sizeof(char); 570char*pstr = "this is a test str"; 571int strLen = strlen(pstr); 572 573char* pdesc = (char*) malloc((1+strLen)* sizeof(char)); 574for (int i = 0; i < strLen; ++i) { 575 cout << "," << hex<< (int)pdesc[i]; 576 } 577 cout << endl; 578 579 cout << strlen(pstr) << endl; 580 581 strcpy_s(pdesc, strLen+1, pstr); 582 583for (int i = 0; i < strLen; ++i) { 584if(pdesc[i] > 0) 585 cout << (char)pdesc[i]; 586else cout << "," << (int)pdesc[i] ; 587 } 588 589 cout << endl; 590 591 pdesc = (char*)realloc(pdesc, 40); 592for (int i = 0; i < 40; ++i) { 593 pdesc[strLen + i] = ‘a‘ + i; 594 } 595 596for (int i = 0; i < 40 + strLen; ++i) { 597if (i < strLen) 598 cout << pdesc[i] << ","; 599else 600 cout << (unsigned short)pdesc[i] << ","; 601 } 602 cout << endl; 603 604 cout << "---------------test-realloc---------------" << endl; 605} 606 607 template<typename T> class CMyNumOperator { 608 T a, b; 609public: 610static T Add(T x, T y) { 611return x + y; 612 } 613}; 614#pragma endregion 615 616#pragma region 2018.7.11 617#pragma region 继承相关 618class A { 619public: 620 A(int x) { 621 fProtected = x; 622 } 623float GetFProtected() { 624return fProtected; 625 } 626 627public: 628float fpublic = 2.3f; //c++11支持了初始化,但不能使用auto 629string sname = "liqi"; 630 CMyNumOperator<int>* on = new CMyNumOperator<int>(); //对象也可以 631 632void TestFunc() { 633 cout << "TestFunc" << endl; 634 } 635 636staticvoid StaticTestFunc() { 637 cout << "Static-TestFunc" << endl; 638 } 639virtualvoid ToString() { 640 cout << "A::ToString" << endl; 641 } 642protected: 643float fProtected; 644void ProtectedFunc() { 645 cout << "PRotectedFunc" << endl; 646 } 647private: 648void PrivateFunc() { 649 cout << "PrivateFunc" << endl; 650 651 } 652 653}; 654 655//只管公有继承,不管保护继承和私有继承,意义不大,也太复杂 656class B : public A { 657public: 658 friend void TestProtectedDerive(); 659 B() :A(1) {} 660void TestForDerive() { 661//公有继承下 662//1,子类可以访问父类的保护成员,不能访问父类的私有成员 663 B ob; 664//PrivateFunc(); //error,子类不能访问基类的私有成员 665 ProtectedFunc(); //right 666 fProtected = 10; //right 667 ob.fProtected = 20; //right 668 } 669 670//1,c++中只要基类有相同签名虚函数,则默认为此基类函数也是虚函数[与C#不同],如下情形都成立 671// (1) 函数不声明 virtual 672// (2) 函数声明了 virtual 673// (3) 函数声明了 override 674// (4) 函数声明了 virtual 和 override 675//2,c++中两个关键词作用不同,可以同时存在 676// virtual仅表明函数是虚函数,override是C++11中出现的,明确说明是对基类的重写 677// 它的好处是当函数声明不符合规则时,编译器会报错 678voidvirtual ToString() override{ 679 cout << "B::ToString" << endl; 680 } 681}; 682 683void TestProtectedDerive() { 684 B ob; 685 ob.ProtectedFunc(); 686} 687 688#pragma endregion 689#pragma endregion 690#pragma region 2018.7.18 691#pragma region 标准输入流 692void TestCinCout() { 693float fx; 694 std::string str; 695while (true) { 696bool errorNum = false; 697 cin >> str; //1,试读,看是不是"exit"串 698if (str == "exit")//2,若是,结束循环 699break; 700for (int i = str.length() - 1; i >= 0; --i) {//3,若不是,将串放回到流中,注意是反向放回的 701 cin.putback(str[i]); 702 } 703 704 cin >> fx; 705if (cin.fail()) {//4,如果格式错误 706 cout << "格式错误:请输入一个数值" << endl; 707 cin.clear(); //5,清除错误标识 708while (cin.get() != ‘\n‘); //6,读掉后面出错的所有字符,直到回车 709 errorNum = true; 710 } 711 712if (!errorNum) {//7,若前面输入(数字)是正确的,则继续后面的解析 713 cin >> str; 714if (cin.fail()) { 715 cout << "格式错误:请输入一个字符串" << endl; 716 cin.clear(); 717 } 718 cout << ">>数值= " << fx << ", 描述= " << str << endl; 719 } 720 721 } 722 723} 724#pragma endregion 725#pragma region 计算机数据存储 726void TestComputeDataStorage() { 727//数据转换:C++,C# 通用 728//1,整形数据:短数据类型转长数据类型时,正数高位补0,负数高位补1 729//2,浮点形数据转整形时,得到整数部分,舍去了小数部分 730 731 cout << hex; 732 cout << (int)(short)1 << endl; //1,即 0x00000001 733 cout << (int)(short)-1 << endl; //0xffffffff,即负数高位补1 734 cout << -1 << endl; //0xffffffff,负数表示法,符号位1,真值(1)求补码 735 736 auto sz = sizeof(long);//64位系统,X64编译器下VS2017测试值为4 737float fx = 83.7f; 738 auto lfx = (long unsigned int)fx; //浮点转整形, 739longlong x; //8位整形 740long unsigned int lui; //8位无符号整形 741 742//浮点数据字节察看 743//125.5f = 0x42fb0000 744//-125.5f = 0xc2fb0000 745//83.7f = 0x42a76666 746//浮点数存储按IEEE754标准: 747//以float为例:共4个字节,从高位到低位依次是31,30,...2,1,0 748//最高位存放数据符号,接下来8位存放阶码(包括阶码符号位),接下来23位存放尾数 749int ifx = *(int*)(&fx); 750//等价于 751int* pfx = (int*)&fx; 752int ipfx = *pfx; 753 754int sz2 = sizeof(x); 755} 756 757#pragma endregion 758#pragma region 地址与指针 759void TestAddrAndPointer() { 760//------------------------------------------------------------- 761//1,&p, p, *p的区别: &p是p的地址,p是一个地址,*p是地址中的内容 762//2,地址与指针完全等价,有两种操作:*地址,地址-> 763//3,地址就是一个数值,指针也是个地址 764int x = 10; 765 *(&x) = 0x100; 766 *((char*)&x) = 1; //小端模式下[低字节存低地址处,高字节存高地址处]:0x101 767int* pxt = (int*)10; //直接指向内存地址0x0000000a处 768int*px = &x; //px与 &x完全等价 769int adr = (int)(&x); //地址就是个数值,指针也是个地址值 770 px = (int*)adr; 771 772 cout << hex; //输出为16进制 773 cout << adr << "," << &x << "," << (int*)&x << "," << px << endl; //四者等价,输出相同值 774 cout << dec; //输出为10进制 775 776 A oa(0); 777 (&oa)->fpublic = 30; //地址与指针等价 778 (*(&oa)).fpublic = 111; //地址与指针等价 779 780} 781#pragma endregion 782#pragma region 函数指针 783void TestFuncPtr() { 784 cout << "TestFuncPtr" << endl; 785} 786void TestFuncPtrParam(int, int, int) {//注意函数参数可以不写变量名 787void(*pf)(int, int, int) = TestFuncPtrParam; 788int*p = (int*)pf; 789 790//试图找出函数实参,失败,对函数汇编原理不清楚,有时间再查 791 cout << *(p) << "," << *(p-1) << endl; 792} 793void TestFuncPointer() { 794 A oa(0); 795//1,函数指针与普通指针不兼容,不能相互强转 796//2,函数指针赋值方式有二:pf = func或 pf = &func 797//3,函数指针pf使用方式有二:pf()或 (*pf)(),因为pf和 *pf的值相同,调试模式下可以看到 798 799//1,普通成员函数指针 800 typedef void(A::* PFUNC)(void); //函数指针声明方式一 801using PFunc = void(A::*)(void); //函数指针声明方式二,C++11新方式 802 803 PFunc pf = &(A::TestFunc); 804int pfsz = sizeof(pf); 805 (oa.*pf)(); 806 807//2,全局函数指针 808void(*pfg)() = TestFuncPtr; 809 pfg(); 810 (*pfg)(); 811 812//3,静态函数指针 813void(*sptf)() = A::StaticTestFunc; 814 sptf(); 815 (*sptf)(); 816} 817#pragma endregion 818#pragma region 虚函数表原理 819void TestVirtualFunctionTable() { 820 cout << hex; 821 typedef void(*PFUNC)(); 822 823 offsetof(A, fpublic); //利用此函数可以算函数布局 824 825 A oa(0); 826 B ob; 827 828//一,通过内存地址修改不可访问的保护变量 829 *(float*)((int*)&oa + 1) = 123.4f; //类的第一个变量fpublic赋值,(int*)&oa + 1是跳过虚函数指针 830float fpublic = oa.fpublic; 831 832//二,通过内存地址调用虚函数 833//A和B的虚函数表地址不一样,也就是说父类和子类各有一张虚函数表 834int* pvptr = (int*)(*((int*)(&oa))); 835 cout << "A的虚函数表地址:" << pvptr << endl; //000DB0D4 836 ((void(*)())(*pvptr))(); //A::ToString 837 838 pvptr = (int*)(*((int*)(&ob))); 839 cout << "B的虚函数表地址:" << pvptr << endl; //000DB128 840 ((void(*)())(*pvptr))(); //B::ToString 841 842 843 cout << "--------------------------" << endl; 844//最简写法 845 ((void(*)())(*((int*)*(int*)&oa)))(); 846 ((void(*)())(*((int*)*(int*)&ob)))(); 847 848} 849#pragma endregion 850#pragma region 函数对象,友元函数模板运算符重载 851 template<class T> 852class AddTwoNumber { 853public: 854 T x; 855 856 AddTwoNumber(T x) { 857this->x = x; 858 } 859public: 860//【通过重载()运算符,实现函数对象】 861 T operator()(T a, T b) { 862return a + b; 863 } 864 865//一,使用模板类型的友元模板函数 866//1, <>表示该友元是一个模板函数,且使用本模板类的类型 867// 若不加<>说明符,则找不到模板函数定义,运行时出错 868//2,这里的T是模板类传来的类型,因此,这里不能实现与T不同的类型操作 869//比如若T为int,则 2.1f + new AddTwoNumber<int>()不合法 870//3,【注意这里第二个参数是个引用类型,若是AddTwoNumber<T>对象类型则会出错,不能在类中定义本类对象】 871 friend voidoperator+ <>(T os, AddTwoNumber<T>& n); 872 873//二,使用模板函数自带类型的友元模板函数 874//这里的T是一个新的类型,与此模板类的T没关系,因此没有上面的限制 875 template<class T> 876 friend voidoperator+(T os, A oa); 877 878 template<class T> 879 T Add(T a, T b); 880}; 881 882 template<class T> 883voidoperator+ <>(T os, AddTwoNumber<T>& n) { 884 cout << "operator+: n + AddTwoNumber: " << os << endl; 885} 886 887 template<class T> 888voidoperator+(T n, A o) { 889 cout << "operator+: n + A : " << n << endl; 890} 891 892//================================================== 893//※※※※※※注意这种多层的模板前置声明※※※※※※※ 894 template<typename T> //类模板的前置声明 895 template<typename T1> //函数模板的前置声明 896 T1 AddTwoNumber<T>::Add(T1 a, T1 b) { 897return a + b; 898} 899 900void TestAdd2Num() { 901 AddTwoNumber<double> NumAdd(1); 902 auto nadd = NumAdd(1, 2); 903 A oa(1); 9042.1f + oa; //左操作数任意数值类型,因为使用的是模板函数自带类型 9052.0 + NumAdd;//左操作数必须为double, 906 907 AddTwoNumber<string> add2("str"); 908 add2.Add(1, 1); 909 cout << "x: " << add2.x << endl; 910} 911#pragma endregion 912#pragma endregion 913#pragma region 2018.7.19 914#pragma region 智能指针 915 916//---------------------------------------------------------------------------------------------- 917 918 template<typename T> 919class SmartPointerx { 920private: 921 T * _ptr; 922 size_t* _count; 923public: 924 SmartPointerx(T* ptr = nullptr) : 925 _ptr(ptr) { 926if (_ptr) { 927 _count = new size_t(1); 928 } 929else { 930 _count = new size_t(0); 931 } 932 } 933 934 SmartPointerx(const SmartPointerx& ptr) { 935if (this != &ptr) {//永远成立 936this->_ptr = ptr._ptr; 937this->_count = ptr._count; 938 (*this->_count)++; 939 } 940 } 941 942 SmartPointerx& operator=(const SmartPointerx& ptr) { 943if (this->_ptr == ptr._ptr) { 944return *this; 945 } 946 947if (this->_ptr) { 948 (*this->_count)--; 949if (this->_count == 0) { 950deletethis->_ptr; 951deletethis->_count; 952 } 953 } 954 955this->_ptr = ptr._ptr; 956this->_count = ptr._count; 957 (*this->_count)++; 958return *this; 959 } 960 961 T& operator*() { 962 assert(this->_ptr == nullptr); 963return *(this->_ptr); 964 965 } 966 967 T* operator->() { 968 assert(this->_ptr == nullptr); 969returnthis->_ptr; 970 } 971 972 ~SmartPointerx() { 973 (*this->_count)--; 974if (*this->_count == 0) { 975deletethis->_ptr; //数组内存泄漏 int*p = new int[10] 976deletethis->_count; 977 } 978 } 979 980 size_t use_count() { 981return *this->_count; 982 } 983}; 984 985void TestSmartPtr() { 986 { 987 SmartPointerx<int> sp(newint(10)); 988 SmartPointerx<int> sp2(sp); 989 SmartPointerx<int> sp3(newint(20)); 990 sp2 = sp3; 991 std::cout << sp.use_count() << std::endl; 992 std::cout << sp3.use_count() << std::endl; 993 } 994//delete operator 995} 996//---------------------------------------------------------------------------------------------- 997 998//下面是一个简单智能指针的demo。智能指针类将一个计数器与类指向的对象相关联, 999//引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时,初始化指针并将引用计数置为1; 1000//当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数; 1001//对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象), 1002//并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。 1003//智能指针就是模拟指针动作的类。所有的智能指针都会重载->和 * 操作符。 1004//智能指针还有许多其他功能,比较有用的是自动销毁。 1005//这主要是利用栈对象的有限作用域以及临时对象(有限作用域实现)析构函数释放内存1006 template<class T> 1007class SmartPointer final{ //final1008 T* pobj = NULL; 1009 __int64* refCnt = 0; 1010public: 1011 SmartPointer(T* pobj) {//这里可能会传一个栈对象地址1012if (pobj) { 1013if (pobj != this->pobj) { 1014if (!this->pobj) 1015this->pobj = new __int64; 1016 (*refCnt)++; 1017this->pobj = pobj; 1018 } 1019 } 1020 } 10211022 SmartPointer(const SmartPointer<T>& rhs) { 1023operator=(rsh); 1024 } 10251026 SmartPointer<T> operator=(const SmartPointer<T>& rhs) { 1027if (this == &rhs || pobj == rhs.pobj) 1028return rhs; 1029 (*refCnt)--; 1030 (*rhs.refCnt)++; 1031 pobj = rhs.pobj; 1032return *this; 1033 } 10341035 ~SmartPointer() 1036 { 1037 refCnt--; 1038if(refCnt == 0) 1039 ReleaseRes(); 1040 } 10411042 T* GetPtr() const { 1043return pobj; 1044 } 10451046private: 1047void ReleaseRes() { 1048if (pobj) { 1049try1050 { 1051delete[] pobj; 1052 pobj = NULL; 1053 } 1054catch (const std::exception&) 1055 { 1056 cout << "智能指针指向的不是一个堆对象" << endl; 1057 } 1058 } 1059 } 1060}; 1061#pragma endregion 1062#pragma endregion 10631064#pragma region 2018.7.23 1065#pragma region 数组传参方式 10661067//方式一,数组引用传递1068 template<int N> 1069void ArrayRefAsParam(char(&_dest)[N]) {//数组引用的写法1070char chs[] = "hello"; 1071char* pstr = "hello"; 1072 cout << sizeof(chs) << endl; 1073 cout << strlen(chs) << ", " << strlen(pstr) << endl; 10741075 strcpy_s(chs, "world"); 1076 cout << chs << endl; 1077} 10781079//方式二,指针传递1080void PointerAsParam(constchar* pArr, int elemCount) { 1081} 10821083void TestAstrPstr() { 1084char chs[] = "world"; //6个字符,自动加了一个尾0 10851086//1,数组引用传参,以下两种方式等价1087 ArrayRefAsParam(chs); //模板不仅可以推导类型,也可以推导出数组的大小1088 ArrayRefAsParam<6>(chs); //说明了模板的工作原理,可以不写6,模板自动推导出数组大小 10891090//2,指针传递1091int sz = sizeof(chs); //61092int slen = strlen(chs); //51093 PointerAsParam(chs, 1 + strlen(chs)); 1094} 1095#pragma endregion 1096#pragma region 静态(变量与函数)与常量(常引用,常指针,常函数) 1097class CWithConstStatic { 1098private: 1099staticint _privateId; 1100public: 1101string _str = "CWithStatic";//C++11,可以这样初始化1102staticstring _sstr; //静态变量不允许在类内初始化,这与旧C++一致1103int _id = 1010; 1104public: 1105staticvoid StaticMethod(){ 1106//1,静态函数本质上是一个全局函数 1107//2,静态函数不能访问非静态变量和非静态函数,包括常函数及常量,因为它不属于对象,没有this指针,编译器翻译时出错 1108// _id = 10; //不访问非静态变量,因为没有this指针,不翻译为this->_id 1109//ConstMethod();//不能访问非静态函数,因为没有this指针,不翻译为 this->ConstMethod()1110 } 1111void ConstMethod() const {//11112 auto id = this->_id; 1113 StaticMethod(); //可以访问静态函数,因为静态函数不可能更改对象 1114//NormalMethod(); //不能访问普通函数,因为普通函数可能会更改对象1115 } 11161117void ConstMethod() { 1118//注意1和2的两个ConstMethod函数是重载关系1119 } 11201121void NormalMethod() {//若函数从【调用1】处进入,则有:1122 cout << "normal method begin" << endl; //输出,没问题 1123//cout << _id << endl; //出错,因为这里等价于 this->_id,而this指针为NULL1124 } 1125}; 11261127string CWithConstStatic::_sstr; //静态变量在类外的CPP中声明1128void NormalMethod(CWithConstStatic* _this) { 11291130} 11311132void TestCWithStatic() { 11331134//1,常对象1135const CWithConstStatic ow; 1136//ow._id = 1001; //error, 常对象不能被修改 1137//ow._str = "dd"; //error, 常对象不能被修改1138 ow._sstr = "dd"; //ok, 静态变量不属于对象 11391140//2,常引用1141const CWithConstStatic& owRef = ow; 1142//owRef._str = "hhh"; //error, 常引用不能被修改对象1143 owRef._sstr = "dd"; //ok, 静态变量不属于对象 11441145//3,常量指针,指向常量的指针,指向的内容不可修改1146const CWithConstStatic* pcwcs = new CWithConstStatic(); 1147//pcwcs->_id = 20; //error,不可通过常指针更改其指向的内容 11481149//4,指针常量,指针是一个常量,不可被再次赋值1150 CWithConstStatic* const cpcwcs = new CWithConstStatic(); 1151 cpcwcs->_id = 20; //ok 11521153//5,类函数原理,this指针 1154//c++类的成员函数被编译器翻译为了C语言编译器可以识别的全局函数,然后用C语言编译器来处理它 11551156//以下两条调用等价1157 CWithConstStatic* pwcs = NULL; 1158 pwcs->NormalMethod(); //【调用1】C++的样子1159 NormalMethod(pwcs); //【调用2】C语言翻译出来的结果11601161} 1162#pragma endregion 1163#pragma region 线程 1164void ThreadFunc() { 1165 cout << "thread func 1 : " << _threadid<< endl; 1166//Sleep(1000);1167} 1168void TestThread() { 1169 std::thread t(ThreadFunc); 1170 cout << _threadid << endl; 1171 t.join(); 1172} 1173#pragma endregion 1174#pragma region 深入模板 1175#pragma region 可变参数模板 1176void TestVarTemp() {//【无参的重载函数】 1177//这个函数必须定义,否则编译器报错,因为函数参数展开时,最终(可变参数个数为0时)要调用此函数1178} 11791180 template<typename First, 1181 typename ... Args 1182 > 1183void TestVarTemp(First first, Args... args) { 1184//sizeof...是可变参数模板专用的获取参数个数的函数1185 cout << sizeof...(args) << "-" << first << ""; 11861187//可变参数展开的唯一方式是递归调用,一层层剥离参数,当参数个数为0时调用无参的重载函数,见【无参的重载函数】1188 TestVarTemp(args...); 1189} 1190void TestVarTemplate() { 1191 TestVarTemp(1, 2, 3, 4); 1192} 1193#pragma endregion 1194#pragma endregion 1195#pragma region 构造和拷贝构造 1196class CNormclass { 1197public: 1198 CNormclass() { 1199 cout << "constructor" << endl; 1200 } 1201 CNormclass(const CNormclass& rhs) {//有了复制构造函数后,系统不再为类生成无参构造函数1202 cout << "copy-constructor" << endl; 1203 *this = rhs; 1204 } 1205}; 12061207CNormclass TestConstructorAndCopyCon1() { 1208return CNormclass();//不调用COPY构造函数1209} 1210CNormclass TestConstructorAndCopyCon2() { 1211//对象定义:两种不同的定义方式 1212//方式一,会调用两次构造函数1213 CNormclass r0; //constructor1214 r0 = CNormclass(); //constructor,注意不是COPY构造函数 12151216//方式二,只调用一次构造函数1217 CNormclass rr = CNormclass(); //constructor 12181219//COPY构造函数仅在两种情况下调用: 1220//1,将一个已存在的对象生成另外一个对象1221 CNormclass r1 = r0; //拷贝构造 1222//2,将一个已存在的对象作为参数传递给构造函数时1223 CNormclass r2(r0); //拷贝构造 12241225//不调用构造函数,也不调用拷贝构造函数,也不调用=运算符(因为是同类型),只是进行按位copy1226 r1 = r0; 12271228 cout << "before return " << endl; 1229return rr; //调用COPY构造函数1230} 1231#pragma endregion 1232#pragma region 函数指针复杂嵌套 1233 typedef int(*PF2)(int); 1234 typedef PF2(*PF1)(int, int); 1235 typedef PF1(*PF)(int); 1236int func2(int) { 1237 cout << "func2" << endl; 1238return0; 1239} 1240 PF2 func1(int, int) { 1241 cout << "func1" << endl; 1242return func2; 1243} 1244 PF1 funcx(int) { 1245 cout << "funcx" << endl; 1246return func1; 1247} 12481249void TestNestingFuncPtrs() { 1250//1,一次嵌套1251 PF1 pf1 = func1; 1252 pf1(1, 2)(1); 12531254//等价方式的直接声明1255int(*(*ptr)(int, int))(int) = func1; 1256 ptr(2, 3)(4); 12571258 cout << "--------------------" << endl; 12591260//2,二次嵌套1261 PF pf = funcx; 1262 pf(1)(2, 3)(2); 12631264//等价方式的直接声明1265int(*((*((*ptr2)(int)))(int, int)))(int) = funcx; 1266 ptr2(1)(2, 3)(2); 1267} 1268#pragma endregion 1269#pragma region 类型转换构造函数 1270class CTypeCast { 1271public: 1272int _id; 1273string _name; 1274 CTypeCast(int i) {//整形转换构造函数:将一个整形转为对象1275 _id = i; 1276 cout << "integer cast " << i << endl; 1277 } 1278 CTypeCast(string str) {//字符串转换构造函数:将一个字符串转为对象1279 _name = str; 1280 } 12811282//注意,显示声明,转换必须显式进行1283explicit CTypeCast(float fx) {//浮点转换构造函数:将一个字符串转为对象1284 cout << "float cast " << fx << endl; 1285 } 1286}; 12871288void TestTypecastContructor() { 1289//CTypeCast otc = 1; //整形转换构造函数 1290//CTypeCast otc2 = "otc2"; //字符串转换构造函数 1291//otc = 3; 12921293//注意,当加了explicit后,类型转换必须显示进行,因此下面这个语句不会使用浮点转换构造函数 1294//但是,它却可以使用整形转换构造函数,这会造成数据精度丢失1295 CTypeCast otc3 = 3.2f; //隐式转换:整形转换构造函数1296 CTypeCast otc4(3.2f); //显示转换:浮点转换构造函数12971298} 1299#pragma endregion 13001301#pragma region 2018.7.24 1302#pragma region 类型转换运算符及()[]重载 1303class CTypeCastOper{ 1304float fx = 0.2f; 1305int arr[3]{ 1,2,3 }; 1306public: 1307//1,类型转换运算符1308explicitoperatorfloat() { 1309return fx; 1310 } 1311operatorstring() { 1312 } 13131314//2,()重载 1315//()运算符并不是用来做类型转换的,它是当函数用的,即仿函数,或函数对象1316booloperator()() { 1317returntrue; 1318 } 13191320//3,[]重载 1321//[]运算符与()差多的用法,都是用于对象之后1322intoperator[](int idx) { 1323return arr[idx]; 1324 } 1325}; 13261327void TestTypecastOper() { 1328 CTypeCastOper oper; 1329float fx = (float)oper; 1330 cout << fx << endl; 13311332//1,()运算符1333bool b = oper(); 1334//2,[]运算符1335 cout << oper[0] << "," << oper[1] <<"," << oper[2] << endl; 1336} 1337#pragma endregion 1338#pragma region 模板特化 1339 template<typename T> 1340class CTehuaTemp { 1341public: 1342 T px = "abc";//2,被特化为了一个char*类型指针,故可以这样用1343}; 1344 template<typename T> 1345class CDThhuaTemp : public CTehuaTemp<T*> {//1,将基类模板参数特化为一个指针类型1346public: 1347 T ch = ‘c‘; 1348}; 13491350void TestTehuaTemp() { 1351 CDThhuaTemp<char> otp; 1352 cout << otp.px << endl; 1353 cout << otp.ch << endl; 1354} 1355#pragma endregion 1356#pragma region 同类型赋值,常引用修改 1357class CSimpleclass { 1358public: 1359 CSimpleclass() { 1360 cout << "cons" << endl; 1361 } 13621363 CSimpleclass(const CSimpleclass& rhs) { 1364 cout << "copy cons" << endl; 1365 } 1366public: 1367float fx = 0; //默认未初始化,给它来个初始化1368}; 1369void TestSameTypeAssign() { 13701371 CSimpleclass oc, oc1; 1372const CSimpleclass& oc2 = oc; 1373const CSimpleclass& oc3 = oc; 13741375 cout << "-------------------------" << endl; 1376//【同类型赋值,不调用=运算符,也不调用任何构造函数】1377 oc1 = oc; 13781379//oc2 = oc3; //常引用本身是个常量,也不能被修改 1380//oc2 = oc1; //常引用本身是个常量,也不能被修改 1381//oc2.fx = 30; //常引用不能更改引用的对象内容13821383const std::string ss; 1384//ss = "abc"; //wrong 1385//ss.clear(); //wrong1386} 1387#pragma endregion 1388#pragma region 堆指针栈指针判断 1389class CTestPointerType { 1390public: 1391 CTestPointerType(float fx=0) { 1392this->fx = fx; 1393 } 1394float fx; 1395}; 13961397 template<class T, int N> 1398class CHeapDebugger { 1399public: 1400staticvoid Print(const T* p){ 1401int sz = N * sizeof(T); 14021403int* ip = (int*)p; 1404int headFlag = *(ip - 1); 1405int endFlag = *(int*)((char*)ip + sz); 1406int orderFlag = *(ip - 2); 1407int szFlag = *(ip - 3); 14081409bool isHeapPtr = headFlag == endFlag && headFlag == 0xfdfdfdfd && sz == szFlag; 1410 cout << "----------------------------------------------" << endl; 1411if (isHeapPtr) { 1412 cout << hex << "堆大小:" << szFlag << endl; 1413 cout << "堆编号: " << orderFlag << endl; 1414 cout << "堆首界: " << headFlag << endl; 1415 cout << "堆尾界: " << endFlag << endl; 1416 } 1417else { 1418 cout << "栈指针" << endl; 1419 } 1420 cout << "----------------------------------------------" << endl; 14211422 } 1423}; 1424void TestPointerType() { 1425// 1426constint N = 4; 1427int*p = newint[N]; 1428for (int i = 0; i < N; i++) 1429 { 1430 p[i] = i; 1431 } 14321433 CNormclass* pn = new CNormclass[N]; 1434 CTestPointerType*po = new CTestPointerType[N]; 14351436constint*pc = &N; 1437 CHeapDebugger<CNormclass, N>::Print(pn); 14381439delete po; 14401441} 1442#pragma endregion 1443#pragma endregion 14441445#pragma region 右值引用和MOVE 1446void TestRef(){ 1447int a = 0, b = 1; 1448int& ra = a; 1449 cout << ra << endl; //01450 ra = b; //此时ra不是a的引用也不是b的引用,而是一个普通变量1451 b = 300; 1452 cout << ra << endl; //1145314541455} 1456#pragma endregion 1457#pragma region C11智能指针 14581459#pragma endregion 1460#pragma region 正则表达式 14611462#pragma endregion 1463#pragma region lambda表达式 14641465#pragma endregion 1466#pragma region unorder_map及hashtable实现 1467//有没有无冲突哈希算法14681469#pragma endregion 1470#pragma region DIJKASTRA最短路径算法 14711472class Obj { 1473public: 1474 Obj(float fx) { 1475 x = fx; 1476 } 1477float x; 1478}; 1479bool cmpfunc(Obj a, Obj b) { 1480return a.x < b.x; 1481} 14821483void TestStlSortFunc() { 1484 std::vector<Obj> vec; 1485 vec.push_back(Obj(1)); 1486 vec.push_back(Obj(12)); 1487 vec.push_back(Obj(1.3f)); 1488 vec.push_back(Obj(2.31)); 1489 vec.push_back(Obj(31)); 1490 vec.push_back(Obj(4)); 1491 vec.push_back(Obj(0)); 14921493int ax = 123; 1494 auto iter = max_element(vec.begin(), vec.end(), [ax](Obj obj1, Obj obj2){ 1495 cout << "cap addr of ax : " << ax << endl; 1496return obj1.x < obj2.x; 1497 }); 1498 cout << (*iter).x << endl; 1499} 15001501void RemoveVecElem(std::vector<int>& v, int e) { 1502for (auto it = v.begin(); it != v.end();) { 1503if (*it == e) 1504 { 1505 it = v.erase(it); 1506break; 1507 } 1508else1509 it++; 1510 } 1511} 1512void Dijkastra() { 1513constint m = 99999; 1514constint n = m; 1515constint nodeCount = 7; 15161517int paths[][nodeCount] = { 1518 { n, 50, 12, m, 45, m, m }, 1519 { m, n, m, m, 2 , m, m }, 1520 { m, 10, n, 99, m , m, m }, 1521 { m, m, m, n, m , m, m }, 1522 { m, m, m, 10, n , m, m }, 1523 { m, m, m, m, 0 , n, 1 }, 1524 { m, 1, m, m, m , m, n }, 1525 }; 15261527 std::vector<string> sel; 1528 std::vector<int> left{ 0, 1, 2, 23, 4, 15, 6 }; 1529 sel.reserve(8); 1530 left.reserve(8); 15311532int startIdx; 1533 cout << ">> 选择一个起点 " << endl; 1534 cin >> startIdx; 1535 cout << ">> v" << startIdx << endl; 15361537if (startIdx >= nodeCount) 1538return; 15391540 RemoveVecElem(left, startIdx); 1541 cout << "after erase : " << left.capacity() << endl; 1542for (auto e:left) 1543 { 1544 cout << e << ","; 1545 } 1546 cout << endl; 15471548 cout << ">> calculating ..." << endl; 1549int tmp[nodeCount]; 1550for (int i = 0; i < nodeCount; ++i) { 1551 tmp[i] = paths[startIdx][i]; 1552 } 155315541555 std::stringstream ss; 1556//ss >> "v" >> startIdx;15571558 auto iter = min_element(tmp, tmp + nodeCount); 1559 cout << *iter << "," << iter - tmp << endl; 15601561int curMinNode = iter - tmp; 1562int curMinPathLen = *iter; 1563// ss >> "->v" >> curMinNode; 1564//sel.push_back(ss.str()); 1565//ss.clear();1566 RemoveVecElem(left, curMinNode); 15671568while (left.size() > 0) { 1569bool isfind = false; 1570for (int i = 0; i < nodeCount; ++i) { 1571int p1 = paths[startIdx][i]; 1572for (int j = 0; j < nodeCount; ++j) { 1573bool isold = false; 1574for (int i = 0; i < left.size(); ++i) { 1575if (left[i] == j) 1576 isold = true; 1577 } 1578if (!isold) { 1579int p2 = paths[curMinNode][j]; 1580if (j != curMinNode) { //j != curMinNode1581if ((curMinPathLen + p2) < p1) { 1582 isfind = true; 1583 paths[startIdx][i] = (curMinPathLen + p2); 1584 } 1585 } 1586 } 1587 } 1588 } 15891590if (left.size() == 0)break; 15911592 auto p = paths[startIdx]; 1593 auto iter2 = std::min_element(left.begin(), left.end()); 1594 curMinPathLen = *iter2; 1595//curMinNode = iter2 - left.be;1596 RemoveVecElem(left, curMinNode); 1597 cout << "left: " << left.size() << endl; 1598 } 15991600// sel.push_back(0); 1601// sel.erase(sel.begin()); 1602// sel.shrink_to_fit(); 1603// cout << "cap: " << sel.capacity() << endl; 1604// for (int d : sel) 1605// { 1606// cout << d << endl; 1607// } 1608// cout << sel.size() << endl;1609} 1610#pragma endregion 1611#pragma region EffectiveC++ 1612namespace EffectiveCpp { 1613#pragma endregion x 1614#pragma region 02-以const,enum,inline替代define 1615class CStaticConst { 1616public: 1617//【1】,static const 可以同时存在,这在C#中是不允许的 1618//在C#中,常量也是属于类而不属于对象,这就等价于C++的 static cosnt 合体了1619staticconstfloat fx; //【声明式】 16201621//【2】,浮点类型,不能在定义时初始化 1622//static float fx2 = 3; //【错误】 16231624//【3】,整数类型(整形,char,枚举),可以在定义时初始化,且不需要在类外写定义式1625staticconstint ix = 3; //声明并初始化,注意,这不是定义,也就是说声明时可以赋值16261627enum {NumTurns = 5}; 1628int scores[NumTurns]; //enum hack 16291630//【不安全宏的替代品】,既有宏的高效率和函数的安全性1631 template<typename T> 1632 inline T safe_max(const T& a, const T& b) { 1633return a > b ? a : b; 1634 } 1635 }; 1636constfloat CStaticConst::fx = 1; //【定义式】:不能写static 1637//const int CStaticConst::ix = 3; //【错误】,已经初始化过了,不能重复1638constint CStaticConst::ix; //定义式,声明时已初始化了。因为是整数类型,这个定义式可以不写 16391640//1,【宏是不安全的】任何时候都不要忘了给宏的实参加上() 1641//2 替代方法:使用 template inline1642#define unsave_max(a, b) (a) > (b) ? (a) : (b) 16431644void Test02() { 1645 CStaticConst oc; 1646 cout << oc.fx << endl; 1647int a(10), b(20); 16481649//不安全的宏,下面这样的导致b被加两次1650 max(++a, b++); 1651 cout << "a=" << a << ", b=" << b << endl; 1652 } 1653#pragma endregion 165416551656} 16571658#pragma endregion 16591660#pragma endregion 1661constint* TestConstarr() { 1662int* iarr = newint[3]{ 1, 2, 3 }; 1663return iarr; 1664} 1665int _tmain(int argc, _TCHAR* argv[]) 1666{ 1667 EffectiveCpp::Test02(); 1668//TestStlSortFunc(); 1669//Dijkastra(); 1670//TestPointerType(); 1671//TestSameTypeAssign(); 1672//TestRef(); 1673//TestTehuaTemp(); 1674//TestCComplexOper(); 1675//TestTypecastOper(); 1676//TestTypecastContructor(); 1677//TestNestingFuncPtrs(); 1678//TestArrayAndPointer();1679///TestRealloc();1680//TestComputeDataStorage(); 1681//TestVirtualFunctionTable(); 1682//TestAdd2Num(); 1683//TestAstrPstr(); 1684//TestCWithStatic(); 1685//TestThread(); 1686//TestVarTemplate();16871688constint arr[] = { 1, 23, 4 }; 1689int a1[3], a2[3]; 1690 TestConstarr(); 1691return0; 1692 }
原文:https://www.cnblogs.com/timeObjserver/p/9391510.html
内容总结
以上是互联网集市为您收集整理的C++全总结全部内容,希望文章能够帮你解决C++全总结所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。