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>
16 using namespace std;
17 using std::cin;
18 using 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")];
309 void 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);
315 int ix1;
316 string sx1;
317 char 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 }
326 void TestMacro() {
327 #define hfunc(x) cout << x << endl; //自定义处起,全局可见
328 hfunc(124);
329 #undef hfunc
330
331 //typedf, using等价使用
332 typedef void(*PFUN)(int);
333 using PFUNC = void(*)(int);
334
335 using Int = int;
336 using MyType = Int;
337 }
338 //数组和指针
339 void 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 //========================================================
349 int ix = 20;
350 int*pix = &ix;
351 cout << pix[0] << "," << *pix << endl;
352
353 //========================================================================================
354 //堆和栈上数组的初始化列表写法
355 //========================================================================================
356 char arr[43] = { 'a','b','c' };
357 char arr2[10] = { "hello" };
358 int iarr[] = { 1, 2, 3, 4 };
359 char*ps = new char[30]{ 0 };
360 int* ips = new int[30]{};
361 int* ips2 = new int[30];
362
363 //cout << arr << "," << (void*)arr << (void*) ps << endl;
364 char* px;
365 px = arr; //可以赋值,说明数组名与指针等价
366 const char* cp;//可以cp++;
367 char* const cpx = arr; //不可以 cpx++,不能移动的指针,数组名其实就是这种指针
368
369 //这里以arr与ps作对比,数组名与指针本质上都是指针,只是数组名是不能移动,不能赋值的常指针
370 //在二维情形时也是如此
371
372
373 stringstream ss;
374 //========================================================================================
375 //1,栈上二维数组,【内存连续】
376 //========================================================================================
377 char a[][3] = {//二维数组初始化列表
378 { 98, 99, 100 },
379 { 101, 102, 103 },
380 };
381 for (int i = 0; i < 6; ++i) {//验证
382 ss << *(*a + i) << ",";
383 }
384 cout << ss.str() << endl;
385
386 //=============================================================================
387 //2,数组指针(也称行指针),【内存连续】
388 //=============================================================================
389 int(*pax)[4] = new int[3][4];
390 for (int i = 0; i < 3; ++i) {
391 for (int j = 0; j < 4; ++j) {
392 pax[i][j] = i * 4 + j + 1;
393 }
394 }
395
396 ss.str("");
397 for (int i = 0; i < 12; ++i) {//验证
398 ss << *(*pax + i) << ",";
399 }
400 cout << ss.str() << endl;
401
402 //=============================================================================
403 //3,指针数组,【内存不连续】
404 //=============================================================================
405 //因为它是一个数组,所以不能用new来给它分配内存,new出来的东西只能赋值给指针
406 char* arr_p[2];
407 arr_p[0] = new char[30]{ 'h','e','o','l','l' };
408 arr_p[1] = new char[10]{ 'a','b','c' };
409
410
411 //=============================================================================
412 //4,多级指针用来分配二维数组,有【连续内存分配法】和【不连续内存分配法】
413 //这个非常重要,若用一个不连续的二维数组指针进行memcpy操作,则会发生严重问题:
414 //(1)数据拷越界,覆盖了其它变量甚至程序的内存
415 //(2)dest变量中数据只填充了一部分,其余部分还是旧数据,导致程序出现莫名其妙的问题
416 //(3)这种数据拷越界并无任何提示,隐蔽性极高,非常难以查找
417 //=============================================================================
418 int**pi = new int*[3];
419 int* ptemp = new int[12];
420 for (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]);
428 for (int j = 0; j < 2; ++j) {
429 pi[i][j] = i * 2 + j;
430 }
431 }
432 for (int i = 0; i < 3; ++i) {//验证
433 for (int j = 0; j < 2; ++j)
434 {
435 ss << pi[i][j] << ",";
436 }
437 }
438 cout << ss.str() << endl;
439
440 }
441 void TestInitialist() {
442 class CIn {
443 public:
444 float x, y, z;
445 string 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
458 class CComplex {
459 float real, image;
460 public:
461 CComplex(float real, float image) {
462 cout << "constructor: " << real << "," << image << endl;
463 this->real = real;
464 this->image = image;
465 }
466
467 CComplex(const CComplex& other) {
468 cout << "copy constructor: " << other.real << "," << other.image << endl;
469 if (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
482 void PrintInfo() {
483 cout <<"Complex: " << real << "," << image<< endl;
484 }
485
486 public:
487
488 //-------------------------------------------
489 //运算符重载
490 //-------------------------------------------
491 //1,重载为成员函数
492 CComplex operator+(const CComplex& other) {
493 cout << "operator+" << endl;
494 return CComplex(real+other.real, image + other.image);
495 }
496
497 CComplex& operator++() {//前向++
498 cout << "forward ++ " << endl;
499 real++; image++;
500 return *this;
501 }
502 CComplex& operator++(int) {//后向++
503 cout << "backward ++ " << endl;
504
505 real++; image++;
506 return *this;
507 }
508 const CComplex& operator=(const CComplex& other) {
509 this->real = other.real;
510 this->image = other.image;
511 return *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,类型转换运算符重载
521 operator bool() {//使用情景:CComplex oc; if(oc){}或if(oc != NULL){}或 float/int/bool x = oc
522 return real != 0 && image != 0;
523 }
524 operator float() {//使用情景:CComplex oc; if(oc){}或if(oc != NULL){}或 float/int/bool x = oc
525 return 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
534 void 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) {
543 return CComplex(fx + cp.real, cp.image);
544 }
545
546 void TestCComplexOper() {
547 int i = 10;
548 CComplex cpx(1, 2);
549 ++cpx++++;
550 cpx.PrintInfo();
551 }
552 CComplex TestReturnStackObj() {
553 //-----------------------------------------------------------------
554 //返回栈上的对象 stackObj
555 //返回栈上的对象会导致拷贝构造函数的调用,生成一个
556 CComplex stackObj(1, 2);
557 return stackObj;
558
559 return CComplex(1, 2); //这种方式直接调用构造函数,而不调用拷贝构造函数
560 //-----------------------------------------------------------------
561 }
562
563 #pragma endregion
564
565 #pragma region 2018.7.10
566 void TestRealloc() {
567 cout << "---------------test-realloc---------------" << endl;
568
569 int szch = sizeof(char);
570 char*pstr = "this is a test str";
571 int strLen = strlen(pstr);
572
573 char* pdesc = (char*) malloc((1+strLen)* sizeof(char));
574 for (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
583 for (int i = 0; i < strLen; ++i) {
584 if(pdesc[i] > 0)
585 cout << (char)pdesc[i];
586 else cout << "," << (int)pdesc[i] ;
587 }
588
589 cout << endl;
590
591 pdesc = (char*)realloc(pdesc, 40);
592 for (int i = 0; i < 40; ++i) {
593 pdesc[strLen + i] = 'a' + i;
594 }
595
596 for (int i = 0; i < 40 + strLen; ++i) {
597 if (i < strLen)
598 cout << pdesc[i] << ",";
599 else
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;
609 public:
610 static T Add(T x, T y) {
611 return x + y;
612 }
613 };
614 #pragma endregion
615
616 #pragma region 2018.7.11
617 #pragma region 继承相关
618 class A {
619 public:
620 A(int x) {
621 fProtected = x;
622 }
623 float GetFProtected() {
624 return fProtected;
625 }
626
627 public:
628 float fpublic = 2.3f; //c++11支持了初始化,但不能使用auto
629 string sname = "liqi";
630 CMyNumOperator<int>* on = new CMyNumOperator<int>(); //对象也可以
631
632 void TestFunc() {
633 cout << "TestFunc" << endl;
634 }
635
636 static void StaticTestFunc() {
637 cout << "Static-TestFunc" << endl;
638 }
639 virtual void ToString() {
640 cout << "A::ToString" << endl;
641 }
642 protected:
643 float fProtected;
644 void ProtectedFunc() {
645 cout << "PRotectedFunc" << endl;
646 }
647 private:
648 void PrivateFunc() {
649 cout << "PrivateFunc" << endl;
650
651 }
652
653 };
654
655 //只管公有继承,不管保护继承和私有继承,意义不大,也太复杂
656 class B : public A {
657 public:
658 friend void TestProtectedDerive();
659 B() :A(1) {}
660 void 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 // 它的好处是当函数声明不符合规则时,编译器会报错
678 void virtual ToString() override{
679 cout << "B::ToString" << endl;
680 }
681 };
682
683 void TestProtectedDerive() {
684 B ob;
685 ob.ProtectedFunc();
686 }
687
688 #pragma endregion
689 #pragma endregion
690 #pragma region 2018.7.18
691 #pragma region 标准输入流
692 void TestCinCout() {
693 float fx;
694 std::string str;
695 while (true) {
696 bool errorNum = false;
697 cin >> str; //1,试读,看是不是"exit"串
698 if (str == "exit")//2,若是,结束循环
699 break;
700 for (int i = str.length() - 1; i >= 0; --i) {//3,若不是,将串放回到流中,注意是反向放回的
701 cin.putback(str[i]);
702 }
703
704 cin >> fx;
705 if (cin.fail()) {//4,如果格式错误
706 cout << "格式错误:请输入一个数值" << endl;
707 cin.clear(); //5,清除错误标识
708 while (cin.get() != '\n'); //6,读掉后面出错的所有字符,直到回车
709 errorNum = true;
710 }
711
712 if (!errorNum) {//7,若前面输入(数字)是正确的,则继续后面的解析
713 cin >> str;
714 if (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 计算机数据存储
726 void 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
737 float fx = 83.7f;
738 auto lfx = (long unsigned int)fx; //浮点转整形,
739 long long x; //8位整形
740 long 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位存放尾数
749 int ifx = *(int*)(&fx);
750 //等价于
751 int* pfx = (int*)&fx;
752 int ipfx = *pfx;
753
754 int sz2 = sizeof(x);
755 }
756
757 #pragma endregion
758 #pragma region 地址与指针
759 void TestAddrAndPointer() {
760 //-------------------------------------------------------------
761 //1,&p, p, *p的区别: &p是p的地址,p是一个地址,*p是地址中的内容
762 //2,地址与指针完全等价,有两种操作:*地址,地址->
763 //3,地址就是一个数值,指针也是个地址
764 int x = 10;
765 *(&x) = 0x100;
766 *((char*)&x) = 1; //小端模式下[低字节存低地址处,高字节存高地址处]:0x101
767 int* pxt = (int*)10; //直接指向内存地址0x0000000a处
768 int*px = &x; //px与 &x完全等价
769 int 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 函数指针
783 void TestFuncPtr() {
784 cout << "TestFuncPtr" << endl;
785 }
786 void TestFuncPtrParam(int, int, int) {//注意函数参数可以不写变量名
787 void(*pf)(int, int, int) = TestFuncPtrParam;
788 int*p = (int*)pf;
789
790 //试图找出函数实参,失败,对函数汇编原理不清楚,有时间再查
791 cout << *(p) << "," << *(p-1) << endl;
792 }
793 void 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); //函数指针声明方式一
801 using PFunc = void(A::*)(void); //函数指针声明方式二,C++11新方式
802
803 PFunc pf = &(A::TestFunc);
804 int pfsz = sizeof(pf);
805 (oa.*pf)();
806
807 //2,全局函数指针
808 void(*pfg)() = TestFuncPtr;
809 pfg();
810 (*pfg)();
811
812 //3,静态函数指针
813 void(*sptf)() = A::StaticTestFunc;
814 sptf();
815 (*sptf)();
816 }
817 #pragma endregion
818 #pragma region 虚函数表原理
819 void 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是跳过虚函数指针
830 float fpublic = oa.fpublic;
831
832 //二,通过内存地址调用虚函数
833 //A和B的虚函数表地址不一样,也就是说父类和子类各有一张虚函数表
834 int* 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>
852 class AddTwoNumber {
853 public:
854 T x;
855
856 AddTwoNumber(T x) {
857 this->x = x;
858 }
859 public:
860 //【通过重载()运算符,实现函数对象】
861 T operator()(T a, T b) {
862 return 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 void operator+ <>(T os, AddTwoNumber<T>& n);
872
873 //二,使用模板函数自带类型的友元模板函数
874 //这里的T是一个新的类型,与此模板类的T没关系,因此没有上面的限制
875 template<class T>
876 friend void operator+(T os, A oa);
877
878 template<class T>
879 T Add(T a, T b);
880 };
881
882 template<class T>
883 void operator+ <>(T os, AddTwoNumber<T>& n) {
884 cout << "operator+: n + AddTwoNumber: " << os << endl;
885 }
886
887 template<class T>
888 void operator+(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) {
897 return a + b;
898 }
899
900 void TestAdd2Num() {
901 AddTwoNumber<double> NumAdd(1);
902 auto nadd = NumAdd(1, 2);
903 A oa(1);
904 2.1f + oa; //左操作数任意数值类型,因为使用的是模板函数自带类型
905 2.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>
919 class SmartPointerx {
920 private:
921 T * _ptr;
922 size_t* _count;
923 public:
924 SmartPointerx(T* ptr = nullptr) :
925 _ptr(ptr) {
926 if (_ptr) {
927 _count = new size_t(1);
928 }
929 else {
930 _count = new size_t(0);
931 }
932 }
933
934 SmartPointerx(const SmartPointerx& ptr) {
935 if (this != &ptr) {//永远成立
936 this->_ptr = ptr._ptr;
937 this->_count = ptr._count;
938 (*this->_count)++;
939 }
940 }
941
942 SmartPointerx& operator=(const SmartPointerx& ptr) {
943 if (this->_ptr == ptr._ptr) {
944 return *this;
945 }
946
947 if (this->_ptr) {
948 (*this->_count)--;
949 if (this->_count == 0) {
950 delete this->_ptr;
951 delete this->_count;
952 }
953 }
954
955 this->_ptr = ptr._ptr;
956 this->_count = ptr._count;
957 (*this->_count)++;
958 return *this;
959 }
960
961 T& operator*() {
962 assert(this->_ptr == nullptr);
963 return *(this->_ptr);
964
965 }
966
967 T* operator->() {
968 assert(this->_ptr == nullptr);
969 return this->_ptr;
970 }
971
972 ~SmartPointerx() {
973 (*this->_count)--;
974 if (*this->_count == 0) {
975 delete this->_ptr; //数组内存泄漏 int*p = new int[10]
976 delete this->_count;
977 }
978 }
979
980 size_t use_count() {
981 return *this->_count;
982 }
983 };
984
985 void TestSmartPtr() {
986 {
987 SmartPointerx<int> sp(new int(10));
988 SmartPointerx<int> sp2(sp);
989 SmartPointerx<int> sp3(new int(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>
1007 class SmartPointer final{ //final
1008 T* pobj = NULL;
1009 __int64* refCnt = 0;
1010 public:
1011 SmartPointer(T* pobj) {//这里可能会传一个栈对象地址
1012 if (pobj) {
1013 if (pobj != this->pobj) {
1014 if (!this->pobj)
1015 this->pobj = new __int64;
1016 (*refCnt)++;
1017 this->pobj = pobj;
1018 }
1019 }
1020 }
1021
1022 SmartPointer(const SmartPointer<T>& rhs) {
1023 operator=(rsh);
1024 }
1025
1026 SmartPointer<T> operator=(const SmartPointer<T>& rhs) {
1027 if (this == &rhs || pobj == rhs.pobj)
1028 return rhs;
1029 (*refCnt)--;
1030 (*rhs.refCnt)++;
1031 pobj = rhs.pobj;
1032 return *this;
1033 }
1034
1035 ~SmartPointer()
1036 {
1037 refCnt--;
1038 if(refCnt == 0)
1039 ReleaseRes();
1040 }
1041
1042 T* GetPtr() const {
1043 return pobj;
1044 }
1045
1046 private:
1047 void ReleaseRes() {
1048 if (pobj) {
1049 try
1050 {
1051 delete[] pobj;
1052 pobj = NULL;
1053 }
1054 catch (const std::exception&)
1055 {
1056 cout << "智能指针指向的不是一个堆对象" << endl;
1057 }
1058 }
1059 }
1060 };
1061 #pragma endregion
1062 #pragma endregion
1063
1064 #pragma region 2018.7.23
1065 #pragma region 数组传参方式
1066
1067 //方式一,数组引用传递
1068 template<int N>
1069 void ArrayRefAsParam(char(&_dest)[N]) {//数组引用的写法
1070 char chs[] = "hello";
1071 char* pstr = "hello";
1072 cout << sizeof(chs) << endl;
1073 cout << strlen(chs) << ", " << strlen(pstr) << endl;
1074
1075 strcpy_s(chs, "world");
1076 cout << chs << endl;
1077 }
1078
1079 //方式二,指针传递
1080 void PointerAsParam(const char* pArr, int elemCount) {
1081 }
1082
1083 void TestAstrPstr() {
1084 char chs[] = "world"; //6个字符,自动加了一个尾0
1085
1086 //1,数组引用传参,以下两种方式等价
1087 ArrayRefAsParam(chs); //模板不仅可以推导类型,也可以推导出数组的大小
1088 ArrayRefAsParam<6>(chs); //说明了模板的工作原理,可以不写6,模板自动推导出数组大小
1089
1090 //2,指针传递
1091 int sz = sizeof(chs); //6
1092 int slen = strlen(chs); //5
1093 PointerAsParam(chs, 1 + strlen(chs));
1094 }
1095 #pragma endregion
1096 #pragma region 静态(变量与函数)与常量(常引用,常指针,常函数)
1097 class CWithConstStatic {
1098 private:
1099 static int _privateId;
1100 public:
1101 string _str = "CWithStatic";//C++11,可以这样初始化
1102 static string _sstr; //静态变量不允许在类内初始化,这与旧C++一致
1103 int _id = 1010;
1104 public:
1105 static void StaticMethod(){
1106 //1,静态函数本质上是一个全局函数
1107 //2,静态函数不能访问非静态变量和非静态函数,包括常函数及常量,因为它不属于对象,没有this指针,编译器翻译时出错
1108 // _id = 10; //不访问非静态变量,因为没有this指针,不翻译为this->_id
1109 //ConstMethod();//不能访问非静态函数,因为没有this指针,不翻译为 this->ConstMethod()
1110 }
1111 void ConstMethod() const {//1
1112 auto id = this->_id;
1113 StaticMethod(); //可以访问静态函数,因为静态函数不可能更改对象
1114 //NormalMethod(); //不能访问普通函数,因为普通函数可能会更改对象
1115 }
1116
1117 void ConstMethod() {
1118 //注意1和2的两个ConstMethod函数是重载关系
1119 }
1120
1121 void NormalMethod() {//若函数从【调用1】处进入,则有:
1122 cout << "normal method begin" << endl; //输出,没问题
1123 //cout << _id << endl; //出错,因为这里等价于 this->_id,而this指针为NULL
1124 }
1125 };
1126
1127 string CWithConstStatic::_sstr; //静态变量在类外的CPP中声明
1128 void NormalMethod(CWithConstStatic* _this) {
1129
1130 }
1131
1132 void TestCWithStatic() {
1133
1134 //1,常对象
1135 const CWithConstStatic ow;
1136 //ow._id = 1001; //error, 常对象不能被修改
1137 //ow._str = "dd"; //error, 常对象不能被修改
1138 ow._sstr = "dd"; //ok, 静态变量不属于对象
1139
1140 //2,常引用
1141 const CWithConstStatic& owRef = ow;
1142 //owRef._str = "hhh"; //error, 常引用不能被修改对象
1143 owRef._sstr = "dd"; //ok, 静态变量不属于对象
1144
1145 //3,常量指针,指向常量的指针,指向的内容不可修改
1146 const CWithConstStatic* pcwcs = new CWithConstStatic();
1147 //pcwcs->_id = 20; //error,不可通过常指针更改其指向的内容
1148
1149 //4,指针常量,指针是一个常量,不可被再次赋值
1150 CWithConstStatic* const cpcwcs = new CWithConstStatic();
1151 cpcwcs->_id = 20; //ok
1152
1153 //5,类函数原理,this指针
1154 //c++类的成员函数被编译器翻译为了C语言编译器可以识别的全局函数,然后用C语言编译器来处理它
1155
1156 //以下两条调用等价
1157 CWithConstStatic* pwcs = NULL;
1158 pwcs->NormalMethod(); //【调用1】C++的样子
1159 NormalMethod(pwcs); //【调用2】C语言翻译出来的结果
1160
1161 }
1162 #pragma endregion
1163 #pragma region 线程
1164 void ThreadFunc() {
1165 cout << "thread func 1 : " << _threadid<< endl;
1166 //Sleep(1000);
1167 }
1168 void TestThread() {
1169 std::thread t(ThreadFunc);
1170 cout << _threadid << endl;
1171 t.join();
1172 }
1173 #pragma endregion
1174 #pragma region 深入模板
1175 #pragma region 可变参数模板
1176 void TestVarTemp() {//【无参的重载函数】
1177 //这个函数必须定义,否则编译器报错,因为函数参数展开时,最终(可变参数个数为0时)要调用此函数
1178 }
1179
1180 template<typename First,
1181 typename ... Args
1182 >
1183 void TestVarTemp(First first, Args... args) {
1184 //sizeof...是可变参数模板专用的获取参数个数的函数
1185 cout << sizeof...(args) << "-" << first << " ";
1186
1187 //可变参数展开的唯一方式是递归调用,一层层剥离参数,当参数个数为0时调用无参的重载函数,见【无参的重载函数】
1188 TestVarTemp(args...);
1189 }
1190 void TestVarTemplate() {
1191 TestVarTemp(1, 2, 3, 4);
1192 }
1193 #pragma endregion
1194 #pragma endregion
1195 #pragma region 构造和拷贝构造
1196 class CNormclass {
1197 public:
1198 CNormclass() {
1199 cout << "constructor" << endl;
1200 }
1201 CNormclass(const CNormclass& rhs) {//有了复制构造函数后,系统不再为类生成无参构造函数
1202 cout << "copy-constructor" << endl;
1203 *this = rhs;
1204 }
1205 };
1206
1207 CNormclass TestConstructorAndCopyCon1() {
1208 return CNormclass();//不调用COPY构造函数
1209 }
1210 CNormclass TestConstructorAndCopyCon2() {
1211 //对象定义:两种不同的定义方式
1212 //方式一,会调用两次构造函数
1213 CNormclass r0; //constructor
1214 r0 = CNormclass(); //constructor,注意不是COPY构造函数
1215
1216 //方式二,只调用一次构造函数
1217 CNormclass rr = CNormclass(); //constructor
1218
1219 //COPY构造函数仅在两种情况下调用:
1220 //1,将一个已存在的对象生成另外一个对象
1221 CNormclass r1 = r0; //拷贝构造
1222 //2,将一个已存在的对象作为参数传递给构造函数时
1223 CNormclass r2(r0); //拷贝构造
1224
1225 //不调用构造函数,也不调用拷贝构造函数,也不调用=运算符(因为是同类型),只是进行按位copy
1226 r1 = r0;
1227
1228 cout << "before return " << endl;
1229 return 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);
1236 int func2(int) {
1237 cout << "func2" << endl;
1238 return 0;
1239 }
1240 PF2 func1(int, int) {
1241 cout << "func1" << endl;
1242 return func2;
1243 }
1244 PF1 funcx(int) {
1245 cout << "funcx" << endl;
1246 return func1;
1247 }
1248
1249 void TestNestingFuncPtrs() {
1250 //1,一次嵌套
1251 PF1 pf1 = func1;
1252 pf1(1, 2)(1);
1253
1254 //等价方式的直接声明
1255 int(*(*ptr)(int, int))(int) = func1;
1256 ptr(2, 3)(4);
1257
1258 cout << "--------------------" << endl;
1259
1260 //2,二次嵌套
1261 PF pf = funcx;
1262 pf(1)(2, 3)(2);
1263
1264 //等价方式的直接声明
1265 int(*((*((*ptr2)(int)))(int, int)))(int) = funcx;
1266 ptr2(1)(2, 3)(2);
1267 }
1268 #pragma endregion
1269 #pragma region 类型转换构造函数
1270 class CTypeCast {
1271 public:
1272 int _id;
1273 string _name;
1274 CTypeCast(int i) {//整形转换构造函数:将一个整形转为对象
1275 _id = i;
1276 cout << "integer cast " << i << endl;
1277 }
1278 CTypeCast(string str) {//字符串转换构造函数:将一个字符串转为对象
1279 _name = str;
1280 }
1281
1282 //注意,显示声明,转换必须显式进行
1283 explicit CTypeCast(float fx) {//浮点转换构造函数:将一个字符串转为对象
1284 cout << "float cast " << fx << endl;
1285 }
1286 };
1287
1288 void TestTypecastContructor() {
1289 //CTypeCast otc = 1; //整形转换构造函数
1290 //CTypeCast otc2 = "otc2"; //字符串转换构造函数
1291 //otc = 3;
1292
1293 //注意,当加了explicit后,类型转换必须显示进行,因此下面这个语句不会使用浮点转换构造函数
1294 //但是,它却可以使用整形转换构造函数,这会造成数据精度丢失
1295 CTypeCast otc3 = 3.2f; //隐式转换:整形转换构造函数
1296 CTypeCast otc4(3.2f); //显示转换:浮点转换构造函数
1297
1298 }
1299 #pragma endregion
1300
1301 #pragma region 2018.7.24
1302 #pragma region 类型转换运算符及()[]重载
1303 class CTypeCastOper{
1304 float fx = 0.2f;
1305 int arr[3]{ 1,2,3 };
1306 public:
1307 //1,类型转换运算符
1308 explicit operator float() {
1309 return fx;
1310 }
1311 operator string() {
1312 }
1313
1314 //2,()重载
1315 //()运算符并不是用来做类型转换的,它是当函数用的,即仿函数,或函数对象
1316 bool operator()() {
1317 return true;
1318 }
1319
1320 //3,[]重载
1321 //[]运算符与()差多的用法,都是用于对象之后
1322 int operator[](int idx) {
1323 return arr[idx];
1324 }
1325 };
1326
1327 void TestTypecastOper() {
1328 CTypeCastOper oper;
1329 float fx = (float)oper;
1330 cout << fx << endl;
1331
1332 //1,()运算符
1333 bool b = oper();
1334 //2,[]运算符
1335 cout << oper[0] << "," << oper[1] <<"," << oper[2] << endl;
1336 }
1337 #pragma endregion
1338 #pragma region 模板特化
1339 template<typename T>
1340 class CTehuaTemp {
1341 public:
1342 T px = "abc";//2,被特化为了一个char*类型指针,故可以这样用
1343 };
1344 template<typename T>
1345 class CDThhuaTemp : public CTehuaTemp<T*> {//1,将基类模板参数特化为一个指针类型
1346 public:
1347 T ch = 'c';
1348 };
1349
1350 void TestTehuaTemp() {
1351 CDThhuaTemp<char> otp;
1352 cout << otp.px << endl;
1353 cout << otp.ch << endl;
1354 }
1355 #pragma endregion
1356 #pragma region 同类型赋值,常引用修改
1357 class CSimpleclass {
1358 public:
1359 CSimpleclass() {
1360 cout << "cons" << endl;
1361 }
1362
1363 CSimpleclass(const CSimpleclass& rhs) {
1364 cout << "copy cons" << endl;
1365 }
1366 public:
1367 float fx = 0; //默认未初始化,给它来个初始化
1368 };
1369 void TestSameTypeAssign() {
1370
1371 CSimpleclass oc, oc1;
1372 const CSimpleclass& oc2 = oc;
1373 const CSimpleclass& oc3 = oc;
1374
1375 cout << "-------------------------" << endl;
1376 //【同类型赋值,不调用=运算符,也不调用任何构造函数】
1377 oc1 = oc;
1378
1379 //oc2 = oc3; //常引用本身是个常量,也不能被修改
1380 //oc2 = oc1; //常引用本身是个常量,也不能被修改
1381 //oc2.fx = 30; //常引用不能更改引用的对象内容
1382
1383 const std::string ss;
1384 //ss = "abc"; //wrong
1385 //ss.clear(); //wrong
1386 }
1387 #pragma endregion
1388 #pragma region 堆指针栈指针判断
1389 class CTestPointerType {
1390 public:
1391 CTestPointerType(float fx=0) {
1392 this->fx = fx;
1393 }
1394 float fx;
1395 };
1396
1397 template<class T, int N>
1398 class CHeapDebugger {
1399 public:
1400 static void Print(const T* p){
1401 int sz = N * sizeof(T);
1402
1403 int* ip = (int*)p;
1404 int headFlag = *(ip - 1);
1405 int endFlag = *(int*)((char*)ip + sz);
1406 int orderFlag = *(ip - 2);
1407 int szFlag = *(ip - 3);
1408
1409 bool isHeapPtr = headFlag == endFlag && headFlag == 0xfdfdfdfd && sz == szFlag;
1410 cout << "----------------------------------------------" << endl;
1411 if (isHeapPtr) {
1412 cout << hex << "堆大小:" << szFlag << endl;
1413 cout << "堆编号: " << orderFlag << endl;
1414 cout << "堆首界: " << headFlag << endl;
1415 cout << "堆尾界: " << endFlag << endl;
1416 }
1417 else {
1418 cout << "栈指针" << endl;
1419 }
1420 cout << "----------------------------------------------" << endl;
1421
1422 }
1423 };
1424 void TestPointerType() {
1425 //
1426 const int N = 4;
1427 int*p = new int[N];
1428 for (int i = 0; i < N; i++)
1429 {
1430 p[i] = i;
1431 }
1432
1433 CNormclass* pn = new CNormclass[N];
1434 CTestPointerType*po = new CTestPointerType[N];
1435
1436 const int*pc = &N;
1437 CHeapDebugger<CNormclass, N>::Print(pn);
1438
1439 delete po;
1440
1441 }
1442 #pragma endregion
1443 #pragma endregion
1444
1445 #pragma region 右值引用和MOVE
1446 void TestRef(){
1447 int a = 0, b = 1;
1448 int& ra = a;
1449 cout << ra << endl; //0
1450 ra = b; //此时ra不是a的引用也不是b的引用,而是一个普通变量
1451 b = 300;
1452 cout << ra << endl; //1
1453
1454
1455 }
1456 #pragma endregion
1457 #pragma region C11智能指针
1458
1459 #pragma endregion
1460 #pragma region 正则表达式
1461
1462 #pragma endregion
1463 #pragma region lambda表达式
1464
1465 #pragma endregion
1466 #pragma region unorder_map及hashtable实现
1467 //有没有无冲突哈希算法
1468
1469 #pragma endregion
1470 #pragma region DIJKASTRA最短路径算法
1471
1472 class Obj {
1473 public:
1474 Obj(float fx) {
1475 x = fx;
1476 }
1477 float x;
1478 };
1479 bool cmpfunc(Obj a, Obj b) {
1480 return a.x < b.x;
1481 }
1482
1483 void 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));
1492
1493 int ax = 123;
1494 auto iter = max_element(vec.begin(), vec.end(), [ax](Obj obj1, Obj obj2){
1495 cout << "cap addr of ax : " << ax << endl;
1496 return obj1.x < obj2.x;
1497 });
1498 cout << (*iter).x << endl;
1499 }
1500
1501 void RemoveVecElem(std::vector<int>& v, int e) {
1502 for (auto it = v.begin(); it != v.end();) {
1503 if (*it == e)
1504 {
1505 it = v.erase(it);
1506 break;
1507 }
1508 else
1509 it++;
1510 }
1511 }
1512 void Dijkastra() {
1513 const int m = 99999;
1514 const int n = m;
1515 const int nodeCount = 7;
1516
1517 int 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 };
1526
1527 std::vector<string> sel;
1528 std::vector<int> left{ 0, 1, 2, 23, 4, 15, 6 };
1529 sel.reserve(8);
1530 left.reserve(8);
1531
1532 int startIdx;
1533 cout << ">> 选择一个起点 " << endl;
1534 cin >> startIdx;
1535 cout << ">> v" << startIdx << endl;
1536
1537 if (startIdx >= nodeCount)
1538 return;
1539
1540 RemoveVecElem(left, startIdx);
1541 cout << "after erase : " << left.capacity() << endl;
1542 for (auto e:left)
1543 {
1544 cout << e << ",";
1545 }
1546 cout << endl;
1547
1548 cout << ">> calculating ..." << endl;
1549 int tmp[nodeCount];
1550 for (int i = 0; i < nodeCount; ++i) {
1551 tmp[i] = paths[startIdx][i];
1552 }
1553
1554
1555 std::stringstream ss;
1556 //ss >> "v" >> startIdx;
1557
1558 auto iter = min_element(tmp, tmp + nodeCount);
1559 cout << *iter << "," << iter - tmp << endl;
1560
1561 int curMinNode = iter - tmp;
1562 int curMinPathLen = *iter;
1563 // ss >> "->v" >> curMinNode;
1564 //sel.push_back(ss.str());
1565 //ss.clear();
1566 RemoveVecElem(left, curMinNode);
1567
1568 while (left.size() > 0) {
1569 bool isfind = false;
1570 for (int i = 0; i < nodeCount; ++i) {
1571 int p1 = paths[startIdx][i];
1572 for (int j = 0; j < nodeCount; ++j) {
1573 bool isold = false;
1574 for (int i = 0; i < left.size(); ++i) {
1575 if (left[i] == j)
1576 isold = true;
1577 }
1578 if (!isold) {
1579 int p2 = paths[curMinNode][j];
1580 if (j != curMinNode) { //j != curMinNode
1581 if ((curMinPathLen + p2) < p1) {
1582 isfind = true;
1583 paths[startIdx][i] = (curMinPathLen + p2);
1584 }
1585 }
1586 }
1587 }
1588 }
1589
1590 if (left.size() == 0)break;
1591
1592 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 }
1599
1600 // 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++
1612 namespace EffectiveCpp {
1613 #pragma endregion x
1614 #pragma region 02-以const,enum,inline替代define
1615 class CStaticConst {
1616 public:
1617 //【1】,static const 可以同时存在,这在C#中是不允许的
1618 //在C#中,常量也是属于类而不属于对象,这就等价于C++的 static cosnt 合体了
1619 static const float fx; //【声明式】
1620
1621 //【2】,浮点类型,不能在定义时初始化
1622 //static float fx2 = 3; //【错误】
1623
1624 //【3】,整数类型(整形,char,枚举),可以在定义时初始化,且不需要在类外写定义式
1625 static const int ix = 3; //声明并初始化,注意,这不是定义,也就是说声明时可以赋值
1626
1627 enum {NumTurns = 5};
1628 int scores[NumTurns]; //enum hack
1629
1630 //【不安全宏的替代品】,既有宏的高效率和函数的安全性
1631 template<typename T>
1632 inline T safe_max(const T& a, const T& b) {
1633 return a > b ? a : b;
1634 }
1635 };
1636 const float CStaticConst::fx = 1; //【定义式】:不能写static
1637 //const int CStaticConst::ix = 3; //【错误】,已经初始化过了,不能重复
1638 const int CStaticConst::ix; //定义式,声明时已初始化了。因为是整数类型,这个定义式可以不写
1639
1640 //1,【宏是不安全的】任何时候都不要忘了给宏的实参加上()
1641 //2 替代方法:使用 template inline
1642 #define unsave_max(a, b) (a) > (b) ? (a) : (b)
1643
1644 void Test02() {
1645 CStaticConst oc;
1646 cout << oc.fx << endl;
1647 int a(10), b(20);
1648
1649 //不安全的宏,下面这样的导致b被加两次
1650 max(++a, b++);
1651 cout << "a=" << a << ", b=" << b << endl;
1652 }
1653 #pragma endregion
1654
1655
1656 }
1657
1658 #pragma endregion
1659
1660 #pragma endregion
1661 const int* TestConstarr() {
1662 int* iarr = new int[3]{ 1, 2, 3 };
1663 return iarr;
1664 }
1665 int _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();
1687
1688 const int arr[] = { 1, 23, 4 };
1689 int a1[3], a2[3];
1690 TestConstarr();
1691 return 0;
1692 }