C++全总结

C++全总结

   1 // CPPTEST.cpp : 定义控制台应用程序的入口点。
   2 //
   3 
   4 #include "stdafx.h"
   5 #include
   6 #include 
   7 #include
   8 #include
   9 #include 
  10 #include"TMyNumOperator.h"
  11 #include"abc.h"
  12 #include 
  13 #include
  14 #include 
  15 #include 
  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 _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();//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 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 TestStrSplit(string s, char sep){
 179 //    std::list 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 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 class MyVector{
 296 //    std::vector _lst;
 297 //
 298 //public:
 299 //
 300 //    void Test2();
 301 //};
 302 //
 303 //template void MyVector::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 <<"," <")" << 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 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()不合法
 870     //3,【注意这里第二个参数是个引用类型,若是AddTwoNumber对象类型则会出错,不能在类中定义本类对象】
 871     friend void operator+ <>(T os, AddTwoNumber& 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& 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 //类模板的前置声明
 895 template //函数模板的前置声明
 896 T1 AddTwoNumber::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
 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& rhs) {
1023         operator=(rsh);
1024     }
1025 
1026     SmartPointer operator=(const SmartPointer& 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
1340 class CTehuaTemp {
1341 public:
1342     T px = "abc";//2,被特化为了一个char*类型指针,故可以这样用
1343 };
1344 template
1345 class CDThhuaTemp : public CTehuaTemp {//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::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 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
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 }

 

posted on 2018-07-30 17:00 时空观察者9号 阅读(...) 评论(...) 编辑 收藏

你可能感兴趣的:(C++全总结)