C++学习笔记


/**
*   描述:C++学习笔记,测试程序通过总开关的形式,每次只能打开一个宏。  
*   KUI 20170924
**/

/*
   描述:C++: 保留运行效率,提高开发效率(代码的复用)。
    1. 完全兼容C语言。
    2. 提供了更多特性(类,重载,继承,多态、异常),引入了对象的编程思想。
    3. 提供标准模板库STL(常用数据结构和算法的集合:容器,迭代器,算法)。
*/


/**
   第1课:C到C++的升级
    1. 关键字加强:register,const

    2. c语言const属性
    方法:把类型int去掉,若const修饰p,则p不可变。若const修饰*p,则*p不可变
        2.1 const int *p; //const 修饰*p,p 是指针, *p 是指针指向的对象,不可变
        2.2 int const *p; //const 修饰*p,p 是指针, *p 是指针指向的对象,不可变
        2.3 int *const p; //const 修饰 p, p 不可变, p 指向的对象可变
        2.4 const int *const p; //前一个 const 修饰*p,后一个 const 修饰 p,指针 p 和 p 指向的对象都不可变    
**/

//#define LESSON1_1_variable_init             //1.1 变量初始化:用到时再定义,如for定义的变量,作用域只在for循环体内。
//#define LESSON1_2_register                  //1.2 register寄存器:register变量可以取址,C++编译器自动优化退化为普通变量。
//#define LESSON1_3_global_variable           //1.3 全局变量:不能重复定义,拒绝二义性。
//#define LESSON1_4_const                    //1.4 const :真正的常量,编译器让其进入符号表,故不为该只读变量分配内存。
//#define LESSON1_5_struct_new_type         //1.5 结构体:是新类型,不需要加上struct,直接:结构体名 变量名
//#define LESSON1_6_func_param_return         //1.6 函数:C++要有确定的参数,确定的返回值
//#define LESSON1_7_example1_1_const_array     //1.7 const:数组参数:const常量编译阶段处理的,可以作为数组参数,变量是运行时才确定的,不可以作为数组参数。  
//#define LESSON1_8_example1_2_const_micro     //1.8 const:宏:作用域


/**
    第2课:C++中的引用
    1. 真正的布尔类型bool
    2. 引用:变量的别名
**/

//#define LESSON2_1_bool                   //2.1 布尔类型:true:非0, false:0,真正的
//#define LESSON2_3_three_eyes             //2.3 三目运算符:返回值可以作为左值
//#define LESSON2_4_yinyong                //2.4 引用:变量的别名
//#define LESSON2_5_yinyong                //2.5 引用:代替指针:更好的可读性,实用性
//#define LESSON2_6_yinyong_const          //2.6 引用:const结合, const 声明引用=变量
//#define LESSON2_7_yinyong_const          //2.7 引用:const结合, const 声明引用=数值
//#define LESSON2_8_yinyong_storage_space  //2.8 引用: 引用等效于常指针  int* const a; 地址不能改变
//#define LESSON2_example2_1               //2.9 引用:引用作为返回值,需要考虑作用域


/**
   第3课:函数的升级
    1. 内联函数
    2. 函数占位符
    
//添加环境变量:C:\Program Files (x86)\Dev-Cpp\MinGW32\bin
//预处理:prepressing:             armcpp/g++ -E main.cpp -o main.i  //只是替换:1.#define 删除,展开宏, 2. 处理条件预编译指令#if #ifdef,3.删除注释
//预处理+编译:compilation:        armcpp/g++ -S main.cpp -o main.s  //c代码变为汇编代码: 1.词法分析,语法分析。
//预处理+编译+汇编:assembly:      armcpp/g++ -c mian.cpp -o main.o  //c代码变为目标文件.o(二进制) :1.把汇编指令翻译为机器指令。
//预处理+编译+汇编+链接:linking:  armcpp/g++ main.cpp -o main       //c文件变为可执行文件(二进制) :1.链接库文件。     
    
**/
//#define LESSON3_1_inline_micro           //3.1 内联函数:比函数少开销,比宏安全。
//#define LESSON3_example3_1               //3.2 内联函数:不一定申请成功
//#define LESSON3_2_func_default_param     //3.3 函数参数:声明时指定默认参数
//#define LESSON3_3_func_default_param     //3.3 函数参数:声明时指定默认参数
//#define LESSON3_4_set_position           //3.4 函数:占位
//#define LESSON3_5_set_position           //3.5 函数:占位+默认参数结合


/**
   第4课:函数的升级
   描述:函数重载:函数名+参数列表
    1. 重载函数本质是相互独立的不同函数
    2. 函数参数类型不同:2.1 参数个数不同,2.2 参数类型不同,2.3 参数顺序不同   
    3. 返回值不能作为重载的根据
**/

//#define LESSON4_1_func_overload                //4.1 函数重载:即多态(批注:不是多态),一个函数名搭配不同参数
//#define LESSON4_2_func_overload                //4.2 函数重载:即多态(批注:不是多态),一个函数名搭配不同参数
//#define LESSON4_3_func_overload_default_param  //4.3 函数重载:重载+默认参数,有二义性不要同时使用
//#define LESSON4_4_func_overload_func_point     //4.4 函数重载:函数指针类型必须匹配
//#define LESSON4_5_cplusplus_extern_c           //4.5 c++编译器以c语言方式编译代码: extern "C" {}
//#define LESSON4_6_cplusplus_extern_c           //4.6 C++与C语言相互调用:c++编译器以c语言方式编译代码: extern "C" {}
//#define LESSON4_example4_1_1                   //4.7 C++与C语言相互调用:c++编译器以c语言方式编译代码: extern "C" {}  


/**
   第5课:新的关键字
   描述:new, delete, namespace,xxx_case
 
   关键字new 与malloc函数区别:
    1. 关键字new是c++的一部分,malloc函数是c库提供的函数
    2. new以类型为单元,malloc以字节为单元进行内存分配
    3. new申请类型变量可以进行初始化,malloc不可以。
    
    命名空间使用:
    1. 使用整个命名看空间:using namespace name;
    2. 使用命名空间的变量:using name::variable;
    3.使用默认命名看空间变量:::variable;

    难以解决的bug思路:
    1. 运算符优先级:
    2. 多线程编程,各线程之间的交互
    3. 强制类型转换         
 
**/

//#define LESSON5_1_keyword_new_delete                   //5.1 关键字:new delete 动态分配内存,与mallo有区别
//#define LESSON5_2_keyword_new_delete_init              //5.2 关键字:new delete 初始化
//#define LESSON5_3_keyword_namespace                    //5.3 关键字:namespace 命名空间解决标识符冲突问题。
//#define LESSON5_4_keyword_namespace                    //5.4 关键字:namespace 命名空间的使用。
//#define LESSON5_5_type_conversion                      //5.5 C强制类型转换: c语言可任意类型进行转换,简单灵活,但是过于粗暴
//#define LESSON5_6_type_conversion_static_cast          //5.6 C++强制类型转换:static_cast基本数据类型之间转换,不能用于指针。
//#define LESSON5_7_type_conversion_const_cast           //5.7 C++强制类型转换:const_cast去除变量const属性
//#define LESSON5_8_type_conversion_reinterpret_cast     //5.8 C++强制类型转换:reinterpret_cast指针之间强制类型转换
//#define LESSON5_9_type_conversion_dynamic_cast         //5.9 C++强制类型转换:dynamic_cast 类之间强制类型转换

/**
   第6课:专题一经典问题解析
   描述:
   1. 函数重载: 本质上是不同的函数:
   2.  extern "C"{}:c方式编译主要是对函数名进行编译。
   3. const注意事项
    const注意事项
    1. 符号表为编译器内部过程的东西,不会进入程序存储空间。
    2. 用字面量初始化的const常量才会进入符号表。如:const int value = 1;//符号表。 const int value = x; //分配内存
    3. volatile修饰的const常量不会进入符号表,退化为只读变量。如volatile const value = 1;
    4. const 引用于初始化变量类型相同,初始化变量分配空间。如:const char c = 1, const char& rc = c; //为c分配空间
    5. const 引用于初始化变量类型不同,生成新的只读变量,独立空间。如:const char c = 1; const int& i = c;//新空间  

    引用注意事项:
     1. 引用定义时必须初始化
     2. 引用是变量的别名,与变量同生死。从此,引用的值是变量的值,地址是变量的地址。
     3. 引用在c++用常量指针表示的。int const *p; //指针地址不可以修改。 可以理解为内部处理的东西。

    函数重载注意事项:
    1. 本质上是不同的函数。
    2. c++编译出来: __Z4funcii
    3. c编译出来:_func

    深入理解extern "C" {}
    1. extern "c"{} 告诉c++编译器对包含的代码进行c方式编译
    2. c方式编译主要是对函数名进行编译。2.1 c++编译出来: __Z4funcii, 2.2 c编译出来:_func
    3. 函数体编译还是以C++进行编译
    4. 比较g++ -S main.cpp -main.s(加上extern "C"), g++ -S main.cpp -main.cpp.s(去掉 extern "C")可以知道唯一不同的是函数名。     
**/

//#define LESSON6_example6_1_const                  //6.1 const:const注意事项
//#define LESSON6_example6_2_yinyong_storage_space  //6.2 引用:别名,存储空间  
//#define LESSON6_example6_3_func_overload          //6.3 函数重载: 本质上是不同的函数:__Z4funcic, __Z4funcii
//#define LESSON6_example6_4_type_size              //6.4 类型大小:
//#define LESSON6_example6_5_cplusplus_extern_c     //6.5 extern "C"{}:c方式编译主要是对函数名进行编译。函数体编译还是以C++进行编译


/**
   第7课:面向对象基本概念
    1. 类:类是个抽象的概念(模板:比如人)
        1.1 类:用于抽象描述一类事物所有属性和行为。
        
    2. 对象: 对象是属于某个类的实体,一个具体存在的事物。(实例:比如KUI)
        2.1  对象是一个具体的事物,拥有所属类的全部属性行为,并且每个属性都有特定的值。
        
    1. struct 默认所有成员都是public。
    2. 类组成:成员变量,成员函数。
    3. 类权限:private,public,protected。         
**/

//#define LESSON7_1_struct_to_object        //7.1 struct表示类


/**
   第8课:类中的封装
   描述:
   1. 类的精华在于封装: 将实现与接口分离。
   2. 使用类时,不需要关心其实现细节。只需调用功能接口即可。(手机:只需知道如何发信息,拍照。最好的角色)
   3. 创建一个类时,才需要考虑内部实现细节。 (手机:工程师设计软件细节,硬件细节)
**/

//#define LESSON8_example8_1_struct_member     //8.1 类成员: 成员变量,成员函数。
//#define LESSON8_example8_2_struct_member     //8.2 类成员作用域:类私有成员只能通过成员函数来访问。
//#define LESSON8_1_class_struct               //8.3 struct class区别:struct 默认权限为public,class 默认权限为private,
//#define LESSON8_4_class_operator_test         //8.4 操作类:类的精华在于封装: 将实现与接口分离。

/**
   第9课:构造与析构函数上
   描述:
   1. 构造函数: 用于初始化
   2. 默认:无参构造函数,拷贝构造函数。  
   
    析构函数:
    1. 与类名相同的特殊成员函数:默认:无参构造函数,拷贝构造函数
    2. 可以有参数,但是没有返回值。
    3. 创建对象是自动调用
    4. 可以重载
    5. 用于初始化
 
    注意:
    1. 当类中没有定义任何一个构造函数,C++编译器会为提供无参构造函数和拷贝构造函数
    2. 当类中定义了任意的非拷贝构造函数时,C++编译器不会为提供无参构造函数  
**/

//#define LESSON9_1_object_init             //9.1 类:显式初始化
//#define LESSON9_2_object_init             //9.2 类:没有初始化,不确定数据
//#define LESSON9_3_object_constructor      //9.3 构造函数: 用于初始化
//#define LESSON9_4_object_constructor      //9.4 构造函数: 构造函数重载
//#define LESSON9_5_object_constructor      //9.5 构造函数: 手动:无参构造函数,拷贝构造函数。
//#define LESSON9_6_object_constructor      //9.6 构造函数: 自动:无参构造函数,拷贝构造函数。
//#define LESSON9_class_example_array       //9.7 数组类:优化数组类拷贝构造函数


/**
   第10课:构造与析构函数下
   描述:
   1. 析构函数:释放资源。
**/

//#define LESSON10_1_object_constructor_param_list       //10.1 构造函数:参数列表:顺序无关,参数列表先调用,再调用构造函数
//#define LESSON10_2_object_destructor                   //10.2 析构函数:释放资源,没有参数,没有返回值
//#define LESSON10_3_object_destructor_array             //10.3 析构函数:释放资源,数组类
//#define LESSON10_4_object_destructor_order             //10.4 析构函数:析构函数调用顺序与构造函数调用顺序相反
//#define LESSON10_5_object_destructor_order             //10.5 析构函数:直接调用构造函数,创建一个空白对象,很快就被销毁了


/**
   第11课:类静态成员
   描述:
   1. 类静态成员:属于类,共享与对象。静态成员变量,静态成员函数,
   2. this指针: this == &对象。对象其实就是结构体,对象指针就是结构体地址。通过->访问类成员(变量,函数)
   
    类静态成员:
    1. 类静态成员不需要创建对象即可访问,通过类名访问,有点像命名空间
    2. 类静态成员共享与所有对象。
    3. 类静态成员变量需要初始化分配空间。    

    对象大小:
    1. 对象成员变量与成员函数是分开存储的
    2. 普通成员变量:存储在对象中,与结构体struct相同
    3. 静态成员变量:存储在全局数据区。
    4. 成员函数:存储在代码段中。
    
    5. 从用户的角度class是将属性+方法集成在同一个位置。
       从计算机的角度,依然是数据段+程序段     
       
       
       
//用户角度                                                         //编译器角度
class Test                                                          struct Test
{                                                                   {
    private:                                                            int mI;    
        int mI;                                                     };
                                                                  
    public:                                                         void Test_initialize(Test *pThis, int i)
        Test(int i)                                                 {  
        {                                                               pThis->mI = i;    
            mI = i;                                                 }  
        }                                                           void Test_getI(Test *pThis)
                                                                    {
        int getI()                                                     return pThis->mI;         
        {                                                           }
            return mI;                                                              
        }                                                          
                                                                    void Test_Print()
        static void Print()                                         {         
        {                                                               printf("This is class test.\n");
            printf("This is class test.\n");                        }                      
        }                                                          
};                                                          


//用户角度                                                          //编译器角度
Test a(10);                                                         Test a;
                                                                    Test_initialize(&a, 10);
a.getI();                                                           Test_getI(&a);
Test::Print();                                                      Test_Print();       
    
**/

//#define LESSON11_1_class_static           //11.1 类静态成员:静态成员变量,静态成员函数
//#define LESSON11_2_class_static_count     //11.2 类静态成员:静态成员变量,静态成员函数,统计创建对象个数
//#define LESSON11_3_class_this_point       //11.3 this指针: this == &对象。对象其实就是结构体,对象指针就是结构体地址。通过->访问类成员(变量,函数)
//#define LESSON11_4_class_inner            //11.4 编译器内部运行机制,用户角度,编译器角度


/**
   第12课:操作符重载上
   描述:
   0. 概念:操作符重载是谓操作符提供不同的语义(不同的功能)。
   1. c++标准库就是用c++编写的类库和函数的集合。(并不是c++语言的一部分)
   1. 操作符重载:operator的本质就是函数重载。故遵循函数重载规则。
   2. 友元friend:对外部函数开放访问类类成员权限。
**/

//#define LESSON12_example12_1_stdlib               //12.1 c++标准库:<cstdio>前缀为c,没有.h
//#define LESSON12_example12_2_stdlib               //12.2 c++标准库:<iosteam> cout(显示器对象) cin(键盘对象)使用
//#define LESSON12_example12_3_class_plus           //12.3 类对象:相加编译异常
//#define LESSON12_example12_4_class_plus           //12.4 类对象:相加使用函数方式
//#define LESSON12_example12_6_operator_overload    //12.6 操作符重载:operator+,使用全局函数方式,故需要友元:friend  
//#define LESSON12_example12_7_operator_overload    //12.7 操作符重载:operator<<,使用全局函数方式,故需要友元:friend  


/**
   第13课:操作符重载下
   描述:
   1. =,[],(),->只能通过成员函数来重载,不可以通过全局函数来重载。C++限制的,因为确保为左值使用。
     否则编译异常:std::ostream& operator->(std::ostream&, const Complex&)' must be a nonstatic member function
   2. C++通过占位符来区分,前置++(需要占位符),还是后置++(不需要占位符)。至于为什么,以后理解
   3. C++不要重载 &&,||操作符,违背了短路功能。
       
    解释:为什么=,[],(),->等运算符只能重载成类的成员函数?  
    由上面的代码可以知道,如果将 =,[],(),-> 进行友元全局重载,那么就会出现 1=x; 1[x]; 1->x; 1(x);
    这样的合法语句(起码编译器认为这些是合法的)--参考代码中的 if(1<x) 合法的片段,但显然这些是需要避免的,
    当然这些不是我们程序员的责任,应该有语言的设计者来实现,所以,就……。

    总结:1. 使用成员函数为了使对象为第一个参数。像[],(),->,=必须是对象为左值。
         使用全局函数可能出现第一个参数不为对象而    
   
**/
//#define LESSON13_example13_1_operator_overload_class_inner    //13.1 操作符重载:使用类成员函数实现,故不需要友元:friend
//#define LESSON13_example13_2_operator_overload_class_array    //13.2 操作符重载:只要是标准没有实现的,都可以通过重载来手动的实现 对象+,=,==,!=。
//#define LESSON13_example13_3_operator_overload_plusplus       //13.3 操作符重载:operator++,  //有占位符,后++ ,//无占位符,前++,至于为什么,以后理解
//#define LESSON13_example13_4_operator_overload_and_or         //13.4 操作符重载:operator&&,operator||,不要重载,违背了短路功能。
//#define LESSON13_example13_5_operator_overload_operator_four  //13.5 操作符重载:operator[],=,(),->,解释为什么只能通过成员函数方式来重载。确保为左值,C++限制的。


/**
    第14课:专题二经典问题解析
    描述:
    1. 问题:malloc与free和new与delete有什么区别?
    2. 编译器对构造函数得调用
    3. 无状态函数,状态函数
    4. 类可以实现状态函数,并且这个状态函数可以从头再来。
    
    问题:malloc与free和new与delete有什么区别?
    1. malloc free是库函数,new delete是关键字。
    2. malloc以字节为单位申请堆内存。new以类型为单位申请对内存。
    3. malloc delete只是单纯地对内存进行申请和释放。
    4. new delete对基本类型申请空间时可以进行初始化。对类类型则会调用构造函数和析构函数。     
     
**/

//#define  LESSON14_example_14_1_new_mallloc         //14.1 new malloc区别: 都是申请堆内存, new可以初始化,调用构造函数功能。
//#define LESSON14_example_14_2_constructor          //14.2 编译器对构造函数调用:默认标准调用 Test t1(5);explicit告诉编译器不要自动调用构造函数
//#define LESSON14_example_14_3_class_member_static  //14.3 静态成员变量作用: 用于控制对象数目。单一对象系统
//#define LESSON14_example_14_4_func_auto_static     //14.4 函数中静态、自动变量:静态变量有记忆功能,无法从头再来。自动变量没有记忆功能,每次都是重新开始。
//#define LESSON14_example_14_5_class_auto_static    //14.5 类可以实现状态函数,并且这个状态函数可以从头再来。


/**
    第15课:惊艳的继承

    0.继承概念:类之间的父子关系
        0.1 子类拥有父类所有成员
        0.2 子类就是一种特殊的父类,子类对象可以当做父类对象使用
        0.3 子类可以拥有父类没有的方法和属性。
        0.4 意义:代码复用
         
    1. 类成员访问级别设定:
        1.1 需要被外界访问的成员设置为:public
        1.2 只能在当前类访问的成员设置为:private
        1.3 只能在当前类和子类访问的成员设置为:protected
        备注:private成员在子类依然存在,只是无法访问。

    2.继承方式:
        2.1 public继承:父类所有成员属性都被子类继承了,但是子类内部和外界都无法访问父类的私有成员
        2.2 protected继承,父类public成员退化为子类的protected成员,可以在子类内部使用,不可以在外界使用。
        2.3 private继承,父类public、protected成员退化为子类的private成员, 可以在子类内部使用,不可以在外界使用。
**/

//#define LESSON15_example15_1_jicheng_default                  //15.1 默认继承:父类所有成员都变为子类private成员
//#define LESSON15_example15_2_jicheng_public                   //15.2 public继承:父类所有成员属性都被子类继承了,但是无法访问父类的私有成员
//#define LESSON15_example15_3_jicheng_public                   //15.3 public继承:父类所有成员属性都被子类继承了,可以在子类直接访问父类的protected成员
//#define LESSON15_example15_4_jicheng_public_protected_private //15.4 继承:public、protected、private继承区别



/**
    第16课:继承中的构造与析构
    1. 继承构造函数调用顺序:先调用父类,再调用子类构造函数,析构函数相反
    2. 子类继承父类:且包好其他类成员: 构造函数调用顺序:先父母,后客人,再自己。
    3. 父类子类同名成员变量: 子类同时包含两个成员变量。存放在不同作用域
    4. 父类对象可以包含子类对象,访问的是父类的方法。
    
    子类成员变量名与父类成员变量名相同
    1. 子类同时包含两个成员变量。存放在不同作用域
    2. 通过不同作用域来访问两个变量:2.1 Child::成员变量,2.2 Parent::成员变量
    3. 默认成员变量是子类成员变量     
**/

//#define LESSON16_example16_1_parent_save_child                            //16.1 父类对象可以包含子类对象,访问的是父类的方法。
//#define LESSON16_example16_2_class_parent_child_constructor               //16.2 继承构造函数调用顺序:先调用父类,再调用子类构造函数,析构函数相反
//#define LESSON16_example16_3_class_parent_child_constructor_param_list    //16.3 继承构造函数:参数列表  
//#define LESSON16_example16_4_class_parent_child_others                    //16.4 子类继承父类:且包好其他类成员: 构造函数调用顺序:先父母,后客人,再自己。
//#define LESSON16_example16_5_class_parent_same_member_name                //16.5 父类子类同名成员变量: 子类同时包含两个成员变量。存放在不同作用域



/**
    第17课:继承与多态上
    1. 多态: 同样的调用语句有不同的表现形式(自动探测功能)。
        1.1 根据实际对象而调用相应的方法。如:Parent *p; 若p指向父类对象则调用父类的方法,若p指向子类对象则调用子类重写的方法。
    2. 多态通过关键字virtual来实现。唯一的方式。
         2.1 被重写的虚函数即可表现出多态特性。
        
    函数重写:
    1. 概念:子类定义了与父类相同原型的函数。
    2. 函数重写只发生在父类与子类之间
    3. 父类被重写的函数依然存继承给子类。
    4. 通过作用域标识符::可以访问父类被重写的函数。         

**/

//#define  LESSON17_example17_1_class_member_same_func_name     //17.1 子父类相同成员函数名:子类重写父类成员函数,父类成员函数依然存在子类之中。
//#define  LESSON17_example17_2_class_parent_save_child         //17.2 父类接受子类:只能调用父类的方法。
//#define LESSON17_example17_3_class_parent_save_child_virtual  //17.2 父类接受子类:多态:根据实际对象而调用相应的方法


/**
    第18课:继承与多态下
    0. 小结:
        4.1 函数重载与函数重写不同。
        4.2 多态是通过虚函数表实现的。
        4.3 虚函数在效率会受到影响。
        4.4 抽象类用于表示现实世界中的抽象概念:如形状。
        4.5 抽象类是通过纯虚函数实现的。     
    
    1. 问题:重载和重写有什么区别?什么时候是重载,什么时候是重写?
        1.1 重载发生在同一作用域里面(同一个类里面),故子类无法重载父类的函数。
        1.2 重写发生在父类与子类之间的相同类型函数。
        1.3 重载在编译阶段就根据参数类型及个数就确定了调用哪个函数。而重写是在运行阶段根据实际对象调用哪个函数。
         
    2. 重写:多态:虚函数原理:
         类中声明虚函数时,编译器会生成一个虚函数表,虚函数表就是存储成员函数指针的结构。
         函数调用时,会判断是否为虚函数,若是虚函数则遍历虚函数表,并找到对象的函数指针,并执行。
         若不是虚函数,则直接调用成员函数。(少了个遍历的过程,效率高些)
         
    3. 是否可以将每个类成员函数都声明为虚函数?
        回答:不可以,虚函数调用时会有额外的开销,若对运行效率要求较高的话,最好不要使用虚函数。
        
    构造函数无法发生多态。
    原因:对象在创建的时候又编译器对虚函数表指针进行初始化。
    只有构造函数完成后虚函数表的指针才确定指向父类还是子类。         
**/

//#define LESSON18_example18_1_class_overwrite_overload     //18.1 重写重载区别:重载发生在同一作用域,重写发生在父类子类之间。
//#define LESSON18_example18_2_class_constructor_overwrite  //18.2 构造函数无法调用重写函数,故无法发生多态。
//#define LESSON18_example18_2_class_pure_virtual_func      //18.3 纯虚函数: 只有接口,没有实现,不能创建对象,可以用来定义指针接受子类对象。



/**
    第19课:专题三经典问题解析
    1. 函数重写:多态: 不要将多态应用于数组  
    2. cout格式化输出:十六进制hex,十进制dec,八进制oct
    3. 多继承:
        3.1 多继承带来代码复杂性、难以维护:单继承为树关系,多继承为图关系。 故既要考虑父类也要考虑母类。
        3.2 多继承存在二义性,两个父类有相同的成员变量时,编译不通过。
        3.3 可以用其他设计方法来代替多继承:单继承+接口,然后子类重写父类的方法,或者实现接口的方法。
        
    4. 接口:
        4.1 C++没有接口这个概念,当年还没有接口这个说法。
        4.2 接口类只是功能说明,不是功能实现。  
        4.3 接口可以通过纯虚函数来是实现。     
    
    程序挂掉了
    1. p++ 等同于p+1; 实现:(unsigned int)p + 1*sizeof(*p) , 以p类型为偏移单位。   
    2. 而重写:多态,是通过虚函数表指针来查找相应函数指针。
    3. 当子类的大小比父类大小大时,偏移大小便不同了,故虚函数表指针需错位,故找不到相应函数指针。         
**/

//#define LESSON19_example19_1_class_virtual_array          //19.1 函数重写:多态:不要将多态应用于数组   
//#define LESSON19_example19_2_class_virtual_array          //19.2 函数重写:多态:不要将多态应用于数组   
//#define LESSON19_example19_3_class_more_jicheng           //19.3 多重继承:面向对象语言中只有C++支持,存在二义性,增加了程序复杂性,故被工程抛弃。
//#define LESSON19_example19_4_class_more_jicheng_interface //19.4 多重继承:可以通过单继承+接口来实现。



/**
    第20课:泛型编程:函数模板
    1. 函数模板:同一个接口接受不同类型数据。代码复用,解决代码冗余问题。   
        1.1 提供一种特殊的函数可用于不同类型进行调用。(表象)
        1.2 编译器根据具体类型产生不同函数,帮你写代码(本质)
        
    2. 函数模板:重载
        2.1 函数模板可以被重载,跟普通函数一样。
        2.2 编译器优先考虑匹配普通函数。
        2.3 若函数模板可以产生更好的匹配,则选择函数模板。如:普通函数只有int func(int), 模板:T func(T,T),若调用func(1,2)则调用函数模板。
        2.4 可以手动指定调用函数模板。通过func<>()指定
        2.5 函数模板不允许自动类型转换,普通函数可以。   

        
**/

//#define LESSON20_example_20_1_func_template               //20.1 函数模板:根据实际类型编译器自动生成相应函数。(帮你做了重复的事情)     
//#define LESSON20_example_20_2_func_template               //20.2 函数模板:同一个接口接受不同类型数据。代码复用,解决代码冗余问题。
//#define LESSON20_example_20_3_func_template_overload      //20.3 函数模板:重载:跟普通函数一样。本质还是根据语义产生不同函数名称
//#define LESSON20_example_20_4_func_template_more_param    //20.4 函数模板:多数据类型 template<typename RT, typename T1, typename T2>


/**
    第21课:泛型编程:类模板
    1. 类模板的思想与函数模板相同。相同类自动适应不同类型操作。
    2. 类定义之前加上 template<typename T>。操作对象是类成员。
    3. 使用上只需要定义时指明类型。 如:Array<int> ai(5);
    4. 工程应用:
        4.1 将类模板定义到头文件中
        4.2 或者定义一个.hpp文件存放类函数实现,.h文件存放声明,而.hpp包含.h文件。
**/

//#define LESSON21_example_21_1_class_template            //21.1 类模板:类定义之前加上 template<typename T>。操作对象是类成员。  
//#define LESSON21_example_21_2_class_template_array      //21.2 类模板:泛型数组类,定义时指明类型即可,使用上没差别
//#define LESSON21_example_21_2_class_template_special    //21.3 类模板:特化: 指明一个特殊的类调用 template<>


/**
*   第23课:STL: 标准模板库:常用数据结构和算法的集合
*   1. 容器:数组,栈,队列,链表
*   2. 迭代器:可以理解为元素指针
*   3. 算法: 排序,随机排列,遍历,查找,转换, 合并
*
*   意义:提高开发效率,及程序可靠性  
*   书籍:1. C++ STL标准程序库开发指南, 2. Effective STL
**/

//#define LESSON23_example23_1_stl_verctor        //23.1 容器:向量模板,可以用于数组
//#define LESSON23_example23_2_stl_stack_queue    //23.2 容器:栈,队列
//#define LESSON23_example23_3_stl_list            //23.3 容器:迭代器: 链表
//#define LESSON23_example23_1_stl_algorithm    //23.4 算法



/**
    第25课:异常处理上
    1. 除0异常无法后果无法预知,强大系统可能只是程序挂掉,小系统可能系统挂掉。
    2. 快速看代码经验:只看正常情况代码。
    3. c++处理异常:try处理正常 catch处理异常 throw抛出异常,正常程序异常程序分开。
    4. c++异常处理:一个try 可以对应多个catch,只能精确匹配。
    5. 若抛出来的异常catch匹配不上,则往上抛,若上层也无法catch,则异常终止程序。
     
**/

//#define LESSON25_example25_1_exception_handle_c             //25.1 c语言异常处理:若出现除0异常,通过&v指针返回状态值。
//#define LESSON25_example25_2_exception_handle_c             //25.2 c语言异常处理:正常情况跟异常情况混在一起。显得冗余臃肿
//#define LESSON25_example25_3_exception_handle_c_goto        //25.3 c语言异常处理:goto处理方式,正常异常处理分开。
//#define LESSON25_example25_4_exception_c_plusplus_try_catch //25.4 c++异常处理:try处理正常 catch处理异常 throw抛出异常,正常程序异常程序分开。  
//#define LESSON25_example25_5_exception_c_plusplus_try_catch //25.5 c++异常处理:try处理正常 catch处理异常 throw抛出异常,返回值都可以不需要了
//#define LESSON25_example25_6_exception_c_plusplus_try_catch //25.5 c++异常处理:一个try 可以对应多个catch,只能精确匹配。  


/**
    第26课:异常处理下
    1. catch(...)可以捕获所有异常
    2. catch(...)经常作为最后一个catch出现。前面可以是特定的异常:如catch(char e)
    3. 不要在构造函数里面抛出异常,将导致析构函数无法被调用,出现内存泄露
    4. 工程应用:使用标准库的exception异常类,#include <stdexcept>
        4.1. 软件异常:logic_error  (参数异常)
        4.2. 硬件异常:runtime_error (硬件故障,硬件错误,内存耗尽)
        4.3 what()方法打印异常     
    5. 函数与try结合:函数体庞大时提高代码的可读写。
**/

//#define LESSON26_example26_1_exception                //26.1 c++异常处理:catch(...)可以接收所有异常类型。
//#define LESSON26_example26_2_exception_catch_throw    // 26.2 c++异常处理:catch中抛出异常。将被外面的catch捕获
//#define LESSON26_example26_3_exception_catch_throw    // 26.3 c++异常处理:catch(...)中抛出异常。原封不动抛出。
//#define LESSON26_example26_4_exception_constructor    // 26.4 c++异常处理:不要在构造函数里面抛出异常。资源泄露。
//#define LESSON26_example26_5_exception_project_used   //26.5 工程应用:统一使用标准库的异常类exception
//#define LESSON26_example26_6_exception_fuc_try        //26.6 函数与try结合:try里面就是正常程序,也就是函数体。


/**
    第27课:类动态类型识别
    1. 通过父类来接收子类对象,使用上动态识别出子类还是父类对象。
    2. 方法一:typeid返回type_info类对象引用,typeid(对象名); typeid(类名)同一个意思。返回同一个type_info引用。#include <typeinfo>
    3. 方法二:dynamic_cast :父类对象指针转换为子类对象指针,若返回空指针则表示不是该子类对象,若不为空指针,则表示为该子类对象
    4. 方法三:唯一ID: 设计唯一ID属性,根据多态返回唯一的ID。若方法返回的ID与属性的ID一致,则表示同一类型。  
    
    实现功能:通过dynamic_cast,动态识别对象类型
    优势:
    1. 不用显示额外声明虚函数,用析构函数即可
    2. 不用为每个类分配ID
    缺陷:
    1. 要求目标对象类型是多态的。也就是基类至少有一个虚函数,通声明析构函数为虚函数     
**/

//#define LESSON27_example_27_1_class_type_identify_with_virtual        //27.1 方法一:virtual虚函数 + 唯一ID
//#define LESSON27_example_27_2_class_type_identify_with_dynamic_cast   //27.2 方法二:dynamic_cast + 父类为虚函数(可以虚析构函数)
//#define LESSON27_example_27_3_class_type_identify_with_typeid         //27.3 方法三:typeid(类型) ,专门用于类型识别的,最好的方法



//27.3 方法三:typeid(类型) ,专门用于类型识别的,最好的方法
#ifdef  LESSON27_example_27_3_class_type_identify_with_typeid
#include <cstdlib>
#include <iostream>
#include <typeinfo> //包含typeinfo头文件

using namespace std;

class Parent
{
public:
    virtual ~Parent()
    {
    }
};

class Child : public Parent
{
public:
    int add(int a, int b)
    {
        return a + b;
    }
};

class NewChild : public Parent
{
};

void test(Parent* p)
{
    //类型匹配
    if( typeid(*p) == typeid(Child) )
    {
        //动态类型转换
        Child* c = dynamic_cast<Child*>(p);
    
        cout<<"Dynamic Type: "<<"Child"<<endl;
        cout<<"add: "<<c->add(2, 3)<<endl;
    }
    else if( typeid(*p) == typeid(NewChild) )
    {
        cout<<"Dynamic Type: "<<"NewChild"<<endl;
    }
    else if( typeid(*p) == typeid(Parent) )
    {
        cout<<"Dynamic Type: "<<"Parent"<<endl;
    }

}

/*
    typeid专门用于类型识别。最好的方法
*/

int main(int argc, char *argv[])
{
    Parent parent;
    Child child;
    NewChild nc;
    int index;
    char ch;
    
    //typeid返回type_info类对象引用:该对象是基于类型来操作的。
    const type_info& tp = typeid(parent);   //typeid(Parent)同一个意思。
    const type_info& tc = typeid(char);
    const type_info& tn = typeid(nc);
    const type_info& ti = typeid(index);
    const type_info& tch = typeid(ch);  //typeid(char) 同一个意思

    cout<<tp.name()<<endl;  //6Parent
    cout<<tc.name()<<endl;  //5Child
    cout<<tn.name()<<endl;  //8NewChild
    cout<<ti.name()<<endl;  //i
    cout<<tch.name()<<endl; //c
    
    test(&parent);
    test(&child);
    test(&nc);
    
    const type_info& infop = typeid(parent);   //typeid(Parent)同一个意思。返回同一个type_info引用
    const type_info& infoP = typeid(Parent);   
    
    cout<<hex << &parent <<endl;//0x28fef0
    
    cout<<hex << &infop <<endl; //0x476aec
    cout<<hex << &infoP <<endl; //0x476aec
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//27.2 类动态类型识别:dynamic_cast + 父类为虚函数(可以虚析构函数)
#ifdef LESSON27_example_27_2_class_type_identify_with_dynamic_cast
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
public:
    //条件:必须有个虚函数
    virtual ~Parent()
    {
    }
};

class Child : public Parent
{
public:
    int add(int a, int b)
    {
        return a + b;
    }
};

class NewChild : public Parent
{
};

void test(Parent* p)
{
    //dynamic_cast<XXX*>(p),XXX需要用子类的类型指针:若类型匹配则返回非空指针(子类对象的地址),若不匹配则返回空指针
    Child* c = dynamic_cast<Child*>(p);
    
    if( c != NULL )
    {
        cout<<"Dynamic Type: "<<"Child"<<endl;
        cout<<"add: "<<c->add(2, 3)<<endl;
    }
    else
    {
        if( dynamic_cast<NewChild*>(p) != NULL )
        {
            cout<<"Dynamic Type: "<<"NewChild"<<endl;
        }
        else
        {
            cout<<"Dynamic Type: "<<"Parent"<<endl;
        }
    }
}
/*
    实现功能:通过dynamic_cast,动态识别对象类型
    优势:
    1. 不用显示额外声明虚函数,用析构函数即可
    2. 不用为每个类分配ID
    缺陷:
    1. 要求目标对象类型是多态的。也就是基类至少有一个虚函数,通声明析构函数为虚函数

*/
int main(int argc, char *argv[])
{
    Parent parent;
    Child child;
    NewChild nc;
    
    test(&parent);
    test(&child);
    test(&nc);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//27.1 类动态类型识别:virtual虚函数 + 唯一ID
#ifdef LESSON27_example_27_1_class_type_identify_with_virtual
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
public:
    //有唯一的ID
    enum { ID = 0 };
    
    //根据多态返回唯一的ID。若方法返回的ID与属性的ID一致,则表示同一类型。
    virtual int type()
    {
        return ID;
    }
};

class Child : public Parent
{
public:
    enum { ID = 1 };
    
    int type()
    {
        return ID;
    }
    
    int add(int a, int b)
    {
        return a + b;
    }
};

//使用父类指针进行接收类型,使用时需要识别具体类型。
void test(Parent* p)
{
    //type是父类子类共有的,发生多态时会执行具体对象的方法。可以通过该方法返回唯一ID进行比较,达到动态识别效果
    if( p->type() == Child::ID )
    {
        Child* c = (Child*)p;
        
        cout<<"Dynamic Type: "<<"Child"<<endl;
        cout<<"add: "<<c->add(2, 3)<<endl;
    }
    
    if( p->type() == Parent::ID )
    {
        cout<<"Dynamic Type: "<<"Parent"<<endl;
    }
}

/*
    实现功能:通过virtual虚函数,动态识别对象类型
    条件:
    1. 必须从基类开始就提供虚函数
    2. 所有派生类必须重写虚函数
    3. 每个派生类都必须有唯一的ID
    缺陷:
    1. 可以满足工程动态识别类类型需要,但是随着派生类增多,维护性会变差(主要是唯一ID的确定)
*/

int main(int argc, char *argv[])
{
    Parent parent;
    Child child;
    
    test(&parent);
    test(&child);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}


#endif


//26.6 函数与try结合:try里面就是正常程序,也就是函数体。
#ifdef LESSON26_example26_6_exception_fuc_try   
#include <cstdlib>
#include <iostream>
#include <stdexcept>

using namespace std;

int func1(int i)
{
    try
    {
        if( i > 0 )
        {
            return i;
        }
        else
        {
            throw "error";
        }
    }
    catch(...)
    {
        return -1;
    }
}

//函数与try结合
int func2(int i) try
{
    //try里面就是正常程序,也就是函数体。
    if( i > 0 )
    {
        return i;
    }
    else
    {
        throw "error";
    }
}
catch(...)
{
    return -1;
}

int main(int argc, char *argv[])
{
    for(int i=0; i<5; i++)
    {
        cout<<func2(i)<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//26.5 工程应用:统一使用标准库的异常类exception
#ifdef LESSON26_example26_5_exception_project_used
#include <cstdlib>
#include <iostream>
#include <stdexcept>    //标准库的异常类头文件。

using namespace std;

//通过继承的方式,命名本地化了。
class divide_by_zero : public logic_error
{
public:
    //字节将构造函数参数传递个父类
    divide_by_zero(const char* s) : logic_error(s)
    {
    }
};

double Div(double a, double b)
{
    if( (-0.00000001 < b) && ( b < 0.00000001) )
    {
        //抛出异常对象
        //throw logic_error("Divide by zero...");
        throw divide_by_zero("Divide by zero..."); //更加直观
    }
    
    return  a / b;
}

/*
    //工程应用:统一使用一个异常类。
    标准库异常类:exception类有两个分支
    1. 软件异常:logic_error  (参数异常)
    2. 硬件异常:runtime_error (硬件故障,硬件错误,内存耗尽)
    
    what()方法打印异常
*/

int main(int argc, char *argv[])
{
    try
    {
        cout<<Div(1, 0)<<endl;
    }
    //值拷贝会有额外的开销,比如创建对象,故使用引用。 可以用父类来接收。
    catch(exception& e)
    {
        //对象what方法类获取具体异常消息
        cout<<e.what()<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



// 26.4 c++异常处理:不要在构造函数里面抛出异常。资源泄露。
#ifdef LESSON26_example26_4_exception_constructor   
#include <cstdlib>
#include <iostream>

using namespace std;

class Test
{
    int* p;
public:
    Test()
    {
        cout<<"Test()"<<endl;
        
        p = new int[5];
        
        //不要在构造函数里面抛出异常:导致对象构造不完全,对象的析构函数将无法被调用 ,导致资源泄露。
        //throw 10;
    }
    
    ~Test()
    {
        cout<<"~Test()"<<endl;
        delete[] p;
    }
};

int main(int argc, char *argv[])
{
    try
    {
        Test t;
    }
    catch(int e)
    {
        cout<<"Catch: "<<e<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


// 26.3 c++异常处理:catch(...)中抛出异常。原封不动抛出。
#ifdef LESSON26_example26_3_exception_catch_throw
#include <cstdlib>
#include <iostream>

using namespace std;

int test(int i)
{
    if( (6 <= i) && (i <= 9) )
    {
        throw i;
    }
    
    return i;
}

int main(int argc, char *argv[])
{
    try
    {
        for(int i=0; i<10; i++)
        {
            try
            {
                cout<<test(i)<<endl;
            }
            catch(...)
            {   
                cout<<"Exception Occur"<<endl;
                
                //可变参捕获的异常原封不动抛出。
                throw;
            }
        }
    }
    catch(int e)
    {
        cout<<"Catch: "<<e<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



// 26.2 c++异常处理:catch中抛出异常。将被外面的catch捕获
#ifdef LESSON26_example26_2_exception_catch_throw
#include <cstdlib>
#include <iostream>

using namespace std;

int test(int i)
{
    if( (6 <= i) && (i <= 9) )
    {
        throw i;
    }
    
    return i;
}

int main(int argc, char *argv[])
{
    try
    {
        for(int i=0; i<10; i++)
        {
            try
            {
                cout<<test(i)<<endl;
            }
            catch(int e)
            {   
                cout<<"Exception: "<<e<<endl;
                
                //catch中抛出异常。将被外面的catch捕获
                throw e;
            }
        }
    }
    catch(int e)
    {
        cout<<"Catch: "<<e<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif

//26.1 c++异常处理:catch(...)可以接收所有异常类型。
#ifdef LESSON26_example26_1_exception
#include <cstdlib>
#include <iostream>

using namespace std;

int test(int i)
{
    if( i == 1 )
    {
        throw "p";
    }
    
    if( i == 2 )
    {
        throw 0.5;
    }
    
    if( i == 3 )
    {
        throw 3;
    }
    
    if( i == 4 )
    {
        throw 'c';
    }
    
    return i;
}

int main(int argc, char *argv[])
{
    for(int i=0; i<10; i++)
    {
        
        /*
            该设计方法类似用c语言实现:
            1. return 同一类型的各个返回值。
            2. 上层函数(存储异常后)判断是否为异常情况(catch(...)),若为异常情况则将该异常返回给上层(throw)。
            缺陷:无法抛出不同类型异常。
        */        
        
        try
        {
            cout<<test(i)<<endl;
        }
        //多个catch捕获异常是,特殊的catch排列在前面
        catch(char e)
        {   
            cout<<"Exception: "<<e<<endl;
        }
        //可变参: 接收全部异常。
        catch(...)
        {
            cout<<"Exception Occur"<<endl;
        }
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif




//25.5 c++异常处理:一个try 可以对应多个catch,只能精确匹配。  
#ifdef LESSON25_example25_6_exception_c_plusplus_try_catch
#include <cstdlib>
#include <iostream>

using namespace std;

int test(int i)
{
    if( i == 1 )
    {
        //异常值为:int整型
        throw -1;
    }
    
    if( i == 2 )
    {
        //异常值为:const char* 字符串
        throw "ERROR";  //字符串类型为:const char*
    }
    
    if( i == 3 )
    {
        //异常值为:double浮点型
        throw 0.5;
    }
    
    if( i == 4 )
    {
        //异常值为:char字符型
        throw 'd';
    }
    
    return i;
}

/*
    catch异常
    1. 一个try 可以对应多个catch
    2. 不能模糊匹配,不能强制类型转化,只能精确匹配。
*/

int main(int argc, char *argv[])
{
    for(int i=0; i<5; i++)
    {
        
        /*
            该设计方法类似用c语言实现:
            1. return 同一类型的各个返回值。
            2. 上层函数判断一一判断返回值(冗余),if() else if () else if ()..
        */
        try
        {
            cout<<test(i)<<endl;
        }
        //捕获异常值为:整型  
        catch(int e)
        {
            cout<<"Int: "<<e<<endl;
        }
        
        //捕获异常值为:字符串
        catch(const char* e)
        {
            cout<<"const char*: "<<e<<endl;
        }
        //捕获异常值为: 浮点型
        catch(double e)
        {
            cout<<"double: "<<e<<endl;
        }
        
        //捕获异常值为: 字符型
        catch (char e)
        {
            cout << "char:" <<e <<endl;     
        }
        
        //批注:若抛出来的异常catch匹配不上,则往上抛,若上层也无法catch,则异常终止程序。
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//25.5 c++异常处理:try处理正常 catch处理异常 throw抛出异常,返回值都可以不需要了
#ifdef LESSON25_example25_5_exception_c_plusplus_try_catch
#include <cstdlib>
#include <iostream>

using namespace std;

void MemSet(void* dest, unsigned int length, unsigned char v)
{
    if( dest == NULL )
    {
        //抛出异常
        throw -1;
    }
    
    if( length < 4 )
    {
        //抛出异常
        throw -2;
    }
    
    if( (v < 0) || (v > 9) )
    {
        //抛出异常
        throw -3;
    }
    
    //通过异常检测,返回值都可以不需要了
    unsigned char* p = (unsigned char*)dest;
    
    for(int i=0; i<length; i++)
    {
        p[i] = v;
    }
}

int main(int argc, char *argv[])
{
    int ai[5];
    double ad[4];
    char ac[3];
    
    //正常处理程序
    try
    {
        MemSet(ai, sizeof(ai), 0);
        MemSet(ad, sizeof(ad), 1);
        MemSet(ac, sizeof(ac), 2);
    }
    //异常处理程序:参数为throw处理的异常值
    catch(int e)
    {
        cout<<e<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//25.4 c++异常处理:try处理正常 catch处理异常 throw抛出异常,正常程序异常程序分开。   
#ifdef LESSON25_example25_4_exception_c_plusplus_try_catch     
#include <cstdlib>
#include <iostream>

using namespace std;

#define DIV_ZERO_ERROR -1

double Div(double a, double b)
{
    if( (-0.000000001 < b) && (b < 0.000000001) )
    {
        //抛出异常。
        throw DIV_ZERO_ERROR;
    }
    
    return a / b;
}

/*
    快速看代码经验:只看正常情况代码。
*/

int main(int argc, char *argv[])
{
    //正常程序
    try
    {
        cout<<Div(3, 1.1)<<endl;
        
        //除0异常发生
        cout<<Div(1, 0)<<endl;
        cout<<"continue: "<<endl;
        
        cout<<Div(1, 2)<<endl;
    }
    //异常程序:捕获throw出来的异常。
    //若异常没有catch处理,则返回上层,若上层没有catch处理。则异常终止程序。
    catch(int error)
    {
        cout<<"Exception: "<<endl;
        cout<<error<<endl;
    }
    
    
    //test
    try
    {
        cout << "try start:" << endl;
        throw 1;
        cout << "try end:" << endl;
    }
    catch(int error)
    {
         cout << "catch:" << endl;
         cout << "error:" << error << endl;
    }

    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//25.3 c语言异常处理: goto处理方式,正常异常处理分开。
#ifdef LESSON25_example25_3_exception_handle_c_goto
#include <cstdlib>
#include <iostream>

using namespace std;

int MemSet(void* dest, unsigned int length, unsigned char v)
{
    if( dest == NULL )
    {
        return -1;
    }
    
    if( length < 4 )
    {
        return -2;
    }
    
    if( (v < 0) || (v > 9) )
    {
        return -3;
    }
    
    unsigned char* p = (unsigned char*)dest;
    
    for(int i=0; i<length; i++)
    {
        p[i] = v;
    }
    
    return 0;
}

int main(int argc, char *argv[])
{
    int ai[5];
    double ad[4];
    char ac[3];
    int ret = 0;
    
    ret = MemSet(ai, sizeof(ai), 0);

    if( ret != 0 )
    {
        goto ERROR;
    }

//使用goto来处理异常程序。 //goto很危险,可能会跳过重要的初始化程序。
ERROR:
    //统一释放资源等
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//25.2 c语言异常处理: 正常情况跟异常情况混在一起。显得冗余臃肿
#ifdef LESSON25_example25_2_exception_handle_c
#include <cstdlib>
#include <iostream>

using namespace std;

int MemSet(void* dest, unsigned int length, unsigned char v)
{
    //异常判断。并且返回各种异常值
    if( dest == NULL )
    {
        return -1;
    }
    
    if( length < 4 )
    {
        return -2;
    }
    
    if( (v < 0) || (v > 9) )
    {
        return -3;
    }
    
    unsigned char* p = (unsigned char*)dest;
    
    for(int i=0; i<length; i++)
    {
        p[i] = v;
    }
    
    return 0;
}

int main(int argc, char *argv[])
{
    int ai[5];
    double ad[4];
    char ac[3];
    int ret;
    
    ret = MemSet(ai, sizeof(ai), 0);
    
    //正常状态,跟异常状态混在一起,不好区分
    //优化:1. 可以通过goto来分开正常异常代码,但是goto很危险喔。2. 可以通过宏来区别。  
    if( ret == 0 )
    {
    }
    else if( ret == -1 )
    {
    }
    else if( ret == -2 )
    {
    }
    else if( ret == -3 )
    {
    }
    
    
    ret = MemSet(ad, sizeof(ad), 1);
    //该异常处理方式显得冗余,臃肿。增加阅读难度。
    //优化:可以通过异常出现则往上抛,由上层处理异常情况。 但是这样每次都得释放资源处理。代码膨胀。
    if( ret == 0 )
    {
    }
    else if( ret == -1 )
    {
    }
    else if( ret == -2 )
    {
    }
    else if( ret == -3 )
    {
    }
    
    ret = MemSet(ac, sizeof(ac), 2);
    
    if( ret == 0 )
    {
    }
    else if( ret == -1 )
    {
    }
    else if( ret == -2 )
    {
    }
    else if( ret == -3 )
    {
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}
#endif


//25.1 c语言异常处理: 若出现除0异常,通过&v指针返回状态值。
#ifdef LESSON25_example25_1_exception_handle_c
#include <cstdlib>
#include <iostream>

using namespace std;
 
//除法运算除0异常处理
double Div(double a, double b, bool* valid)
{
    //没有指针异常判断
    *valid = true;
    
    //浮点数值判断
    if( (-0.000000001 < b) && (b < 0.000000001) )
    {
        *valid = false;
        
        return 0;
    }
    
    return a / b;
}

double Add(double a, double b)
{
    return a + b;
}

double Minus(double a, double b)
{
    return a - b;
}

double Multi(double a, double b)
{
    return a * b;
}

int main(int argc, char *argv[])
{
    bool v = false;
    
    cout << "nomal case:" << endl;
    cout<<Div(6, 2, &v)<<endl;
    cout<<v<<endl;    

    /*  c语言处理异常方式:
        若出现除0异常,通过&v指针返回状态值。
        问题是:倘若&指针也有异常呢,那么就引入另外一个异常。而解决另外一个异常则原来异常则解决不了。
    */
    cout << endl << "error case:" << endl;
    cout<<Div(Add(3, 3), Minus(2, 2), &v)<<endl;
    cout<<v<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}


#endif




//23.4 算法
#ifdef LESSON23_example23_1_stl_algorithm

#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void current(int& v)
{
    cout<<v<<endl;
}

void print(vector<int>& vec)
{
    cout<<"Elements in vector:"<<endl;
    
    //for (int i=0; i<vec.size(); i++)
    //{
    //    cout << vec[i] << endl;    
    //}
    
    //遍历后回调current函数指针
    for_each(vec.begin(), vec.end(), current);
}

int compare(const int& a, const int& b)
{
    return a < b;
}

/*
*   algorithm: 1.for_ench, 2. sort, 3. ramdom_shuffle
*/

int main(int argc, char *argv[])
{
    vector<int> v(10);
    
    for(int i=9; i>=0; i--)
    {
        v[i] = 9 - i;
    }
        
    print(v);
    
    //使用默认的比较器<进行排序
    //sort(v.begin(), v.end());
    
    //根据函数返回值进行排序
    sort(v.begin(), v.end(), compare);
    
    //随机排列
    //random_shuffle(v.begin(), v.end());
    
    print(v);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//23.3 容器:迭代器: 链表
#ifdef LESSON23_example23_3_stl_list

#include <cstdlib>
#include <iostream>
#include <list> //链表头文件

using namespace std;

/*
*   list: 1. push_back, 2.insert, 3.begin, 4. end
*/
int main(int argc, char *argv[])
{
    list<double> l;
    
    cout<<"l size: "<<l.size()<<endl;
    
    for(int i=0; i<5; i++)
    {
        l.push_back((i + 1) / 1000.0);  //最后位置插入
    }
    
    cout<<"l size: "<<l.size()<<endl;
    
    //迭代器可以理解为元素指针
    list<double>::iterator current = l.begin();
    
    cout<<"Elements in l:"<<endl;
    
    while( current != l.end() )
    {
        cout<<*current<<endl;
        
        current++;
    }
    
    current = l.begin();
    
    current++;
    current++;
    
    l.insert(current, 0.1); //当前位置插入
    
    cout<<"Elements in l:"<<endl;
    
    for(list<double>::iterator p = l.begin(); p != l.end(); p++)
    {
        cout<<*p<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif

    
//23.2 容器:栈,队列
#ifdef LESSON23_example23_2_stl_stack_queue
#include <cstdlib>
#include <iostream>
#include <stack>
#include <queue>

using namespace std;

/*
*   stack: 1. push, 2.pop, 3.empty, 4.top
*/

void StackUsage()
{
    cout<<"Stack Usage"<<endl;
    
    stack<double> s;    //定义栈对象
    
    for(int i=0; i<5; i++)
    {
        s.push(i/100.0);    //压栈操作
    }
    
    cout<<"Elements in s:"<<endl;
    
    while( !s.empty() ) //判断栈是否为空
    {
        double v = s.top(); //获取栈顶元素操作
        
        s.pop();   //出栈操作
        
        cout<<v<<endl;
    }
}

/*
*   queue: 1. push, 2.pop, 3.empty, 4.front
*/

void QueueUsage()
{
    cout<<"Queue Usage"<<endl;
    
    queue<int> q;
    
    for(int i=0; i<5; i++)
    {
        q.push(i + 1);
    }
    
    cout<<"Elements in q:"<<endl;
    
    while( !q.empty() )
    {
        int v = q.front();
        
        q.pop();
        
        cout<<v<<endl;
    }
    
}

int main(int argc, char *argv[])
{
    StackUsage();
    QueueUsage();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//23.1 容器:向量模板,可以用于数组
#ifdef LESSON23_example23_1_stl_verctor
#include <cstdlib>
#include <iostream>
#include <vector>  //向量, 库数组类

using namespace std;

/*
*   vector: 1. size, 2.resize, 3. begin, 4.end, 5.erase, 6.push_back, 7.insert, 8.swap
*   操作:创建对象,赋值,取值。
*/

int main(int argc, char *argv[])
{
    vector<int> vi(20);   //新建数组对象 _大小喔
    
    cout<<"vi size: "<<vi.size()<<endl;
    
    for(int i=0; i<5; i++)
    {
        vi[i] = i + 1;
    }
    
    vi.resize(5);  //重新指定大小
    
    cout<<"Elements in vi:"<<endl;
    
    for(int i=0; i<vi.size(); i++)
    {
        cout<<vi[i]<<endl;
    }
    
    vector<int> vin;
    
    vin = vi;   //直接赋值 拷贝
    
    vi.resize(0);
    
    cout<<"Elements in vin:"<<endl;
    
    for(int i=0; i<vin.size(); i++)
    {
        cout<<vin[i]<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif




//21.3 类模板:特化: 指明一个特殊的类调用 template<>
#ifdef LESSON21_example_21_2_class_template_special
#include <cstdlib>
#include <iostream>

using namespace std;

template<typename T>
class Test
{
public:
    T test(T v)
    {
        cout<<"T test(T v)"<<endl;
        cout<<"sizeof(T) = "<<sizeof(T)<<endl;
        
        return v;
    }
};

//类模板特化,指明特殊类型,然后将调用这里。
template<>  //特殊指明
class Test<int> //特殊指明
{
public:
    int test(int v)
    {
        cout<<"int test(int v)"<<endl;
        cout<<"sizeof(int) = "<<sizeof(int)<<endl;
        
        return v;
    }
};

//继承特化类,之后使用就先普通类一样。
class MyTest : public Test<int>
{
public:
    void print(void)
    {
        cout<<"MyTest void print(void)"<<endl;
    }
};

int main(int argc, char *argv[])
{
    Test<int> t1;   //调用特化类:有点像函数模板里面的普通类型函数
    Test<double> t2;
    
    cout<<t1.test(1)<<endl;
    
    cout<<t2.test(1.0)<<endl;
    
    
    cout << endl << "MyTest" << endl;
    MyTest m;
    m.test(1);
    m.print();
    
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif

//21.2 类模板:泛型数组类,定义时指明类型即可,使用上没差别
#ifdef LESSON21_example_21_2_class_template_array   

//array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_

template<typename T>
class Array
{
private:
    int mLength;
    T* mSpace;

public:
    Array(int length);
    Array(const Array& obj);
    int length();
    ~Array();
    T& operator[](int i);
    Array& operator= (const Array& obj);
    bool operator== (const Array& obj);
    bool operator!= (const Array& obj);
};

#endif


//array.hpp
#ifndef _ARRAY_DEF_H_
#define _ARRAY_DEF_H_

//#include "Array.h"

template<typename T>
Array<T>::Array(int length)
{
    if( length < 0 )
    {
        length = 0;
    }
    
    mLength = length;
    mSpace = new T[mLength];
}

template<typename T>
Array<T>::Array(const Array& obj)
{
    mLength = obj.mLength;
    
    mSpace = new T[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
}

template<typename T>
int Array<T>::length()
{
    return mLength;
}

template<typename T>
Array<T>::~Array()
{
    mLength = -1;
    
    delete[] mSpace;
}

template<typename T>
T& Array<T>::operator[](int i)
{
    return mSpace[i];
}

template<typename T>
Array<T>& Array<T>::operator= (const Array<T>& obj)
{
    delete[] mSpace;
    
    mLength = obj.mLength;
    
    mSpace = new int[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
    
    return *this;
}

template<typename T>
bool Array<T>::operator== (const Array<T>& obj)
{
    bool ret = true;
    
    if( mLength == obj.mLength )
    {
        for(int i=0; i<mLength; i++)
        {
            if( mSpace[i] != obj.mSpace[i] )
            {
                ret = false;
                break;
            }
        }
    }
    else
    {
        ret = false;
    }
    
    return ret;
}

template<typename T>
bool Array<T>::operator!= (const Array& obj)
{
    return !(*this == obj);
}

#endif



#include <cstdlib>
#include <iostream>
//#include "Array.hpp"

using namespace std;

/*
    类模板工程应用:
    1.  
*/

int main(int argc, char *argv[])
{
    //使用上只需要定义时指明类型。
    Array<int> ai(5);
    
    for(int i=0; i<ai.length(); i++)
    {
        ai[i] = i + 1;
    }
    
    for(int i=0; i<ai.length(); i++)
    {
        cout<<ai[i]<<endl;
    }
    
    Array<double> ad(10);
    
    for(int i=0; i<ad.length(); i++)
    {
        ad[i] = (i + 1) / 100.0;
    }
    
    for(int i=0; i<ad.length(); i++)
    {
        cout<<ad[i]<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif




//21.1 类模板:类定义之前加上 template<typename T>。操作对象是类成员。  
#ifdef LESSON21_example_21_1_class_template     
#include <cstdlib>
#include <iostream>

using namespace std;

//声明泛型:类模板,与函数模板声明一样,操作对象是类成员。
template<typename T>
class Operator
{
public:
    T add(T a, T b);
    T minus(T a, T b);
};

//每个实现都得加上 泛型声明
template<typename T>

//类名称后面加上<typename>说明为泛型。
T Operator<T>::add(T a, T b)
{
    return a + b;
}

template<typename T>
T Operator<T>::minus(T a, T b)
{
    return a - b;
}

int main(int argc, char *argv[])
{
    //类模板定义对象。
    Operator<int> op1;
    Operator<double> op2;
    
    cout<<op1.add(5, 4)<<endl;
    cout<<op1.minus(4, 5)<<endl;
    
    cout<<op2.add(1.3, 0.01)<<endl;
    cout<<op2.minus(0.01, 1.3)<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif
 

//20.4 函数模板:多数据类型 template<typename RT, typename T1, typename T2>
#ifdef LESSON20_example_20_4_func_template_more_param
#include <cstdlib>
#include <iostream>

using namespace std;

//声明以下可能会用到的数据类型
template<typename RT, typename T1, typename T2>
RT Add(T1 a, T2 b)
{
    //强制类型转换
    return static_cast<RT>(a + b);
}


int main(int argc, char *argv[])
{
    //传统方式指定,用这种方式就好了。
    cout<<Add<double, char, float>('a', 100.0f)<<endl;

    //偷懒方式,将不是形参传递的类型放在首位。
    cout<<Add<double>('a', 100.0f)<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//20.3 函数模板:重载:  跟普通函数一样。本质还是根据语义产生不同函数名称
#ifdef LESSON20_example_20_3_func_template_overload
#include <cstdlib>
#include <iostream>

using namespace std;

int Max(int a, int b)
{
    cout<<"int Max(int a, int b)"<<endl;
    return a > b ? a : b;
}

template<typename T>
T Max(T a, T b)
{
    cout<<"T Max(T a, T b)"<<endl;
    return a > b ? a : b;
}

//函数模板重载:跟普通函数一样。本质还是根据语义产生不同函数名称
template<typename T>
T Max(T a, T b, T c)
{
    cout<<"T Max(T a, T b, T c)"<<endl;
    return Max(Max(a, b), c);
}

/*
    函数模板:重载
    1. 函数模板可以被重载,跟普通函数一样。
    2. 编译器优先考虑匹配普通函数。
    3. 若函数模板可以产生更好的匹配,则选择函数模板。如:普通函数只有int func(int), 模板:T func(T,T),若调用func(1,2)则调用函数模板。
    4. 可以手动指定调用函数模板。通过func<>()指定
    5. 函数模板不允许自动类型转换,普通函数可以。
*/


int main(int argc, char *argv[])
{
    int a = 1;
    int b = 2;
    
    cout<<Max(a, b)<<endl;
    
    //手动指定函数模板方式: Max<>()
    cout<<Max<>(a, b)<<endl;
    
    cout<<Max(3.0, 4.0)<<endl;
    
    cout<<Max(5.0, 6.0, 7.0)<<endl;
    
    //函数模板不能模糊匹配(强制类型转换)。普通函数可以,故调用普通函数。
    cout<<Max('a', 100)<<endl;  //cout<<"int Max(int a, int b)"<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//20.2 泛型编程:函数模板:同一个接口接受不同类型数据。代码复用,解决代码冗余问题。
#ifdef LESSON20_example_20_2_func_template
#include <cstdlib>
#include <iostream>

using namespace std;

//函数模板:交换两个值
template<typename T>
void Swap(T& a, T& b)
{
    T t = a;
    a = b;
    b = t;
}

//函数模板:对数组进行排序
template<typename T>
void SelectSort(T array[], int length)
{
    for(int i=0; i<length; i++)
    {
        T min = array[i];
        int index = i;
        
        for(int j=i+1; j<length; j++)
        {
            if( array[j] < min )
            {
                min = array[j];
                index = j;
            }
        }
        
        Swap<T>(array[i], array[index]);
    }
}


/*
    把template<typename T>的T当作一种类型,在函数使用的时候将这种类型具体化(指定)。
*/

int main(int argc, char *argv[])
{
    int array[] = {3, 2, 5, 3 , 4};
    
    //指明类型:函数名<type>()
    SelectSort<int>(array, 5);
    
    for(int i=0; i<5; i++)
    {
        cout<<array[i]<<endl;
    }
    
    cout << endl;
    
    char ca[] = {'b', 'c', 'a', 'e', 'd', 'f'};
    
    SelectSort(ca, 6);
    
    for(int i=0; i<6; i++)
    {
        cout<<ca[i]<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//20.1 泛型编程:函数模板:同一个接口接受不同类型数据。代码复用,解决代码冗余问题。        
#ifdef LESSON20_example_20_1_func_template      
#include <cstdlib>
#include <iostream>

using namespace std;

//泛型编程:声明函数模板:函数声明定义前加上:template<typename T>
template<typename T>
//若T为int:则__Z4SwapIiEvRT_S1_:
void Swap(T& a, T& b)
{
    cout << "void Swap(T& a, T& b)" <<endl;
    T t = a;
    a = b;
    b = t;
}

//__Z4SwapRiS_: 与泛型可以同时存在因为是不同函数名
void Swap(int& a, int& b)
{
    cout << "void Swap(int& a, int& b)" <<endl;
    int t = a;
    a = b;
    b = t;
}

int main(int argc, char *argv[])
{
    int a = 1;
    int b = 2;
    
    //默认:编译器自动推导类型。优先选择普通函数:void Swap(int& a, int& b)
    //__Z4SwapRiS_:
    Swap(a, b);
    
    //若T为int:则__Z4SwapIiEvRT_S1_:
    Swap<int>(a, b);
    
    cout<<"a = "<<a<<endl;
    cout<<"b = "<<b<<endl;
    
    float fa = 3;
    float fb = 4;
    
    //手动指定类型。 在函数名称与括号之间加上<type>显式
    //__Z4SwapIfEvRT_S1_:
    Swap<float>(fa, fb);
    
    cout<<"fa = "<<fa<<endl;
    cout<<"fb = "<<fb<<endl;
    
    char ca = 'a';
    char cb = 'b';
    
    //Swap(ca, 4);  //Error 需要一一匹配。
    //默认:编译器自动推导类型。
    //__Z4SwapIcEvRT_S1_:
    Swap(ca, cb);
    
    cout<<"ca = "<<ca<<endl;
    cout<<"cb = "<<cb<<endl;

    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif




//19.4 多重继承:可以通过单继承+接口来实现。
#ifdef LESSON19_example19_4_class_more_jicheng_interface
#include <cstdlib>
#include <iostream>

using namespace std;


//定义接口
class Interface1
{
public:
    //使用纯虚函数来实现
    virtual void print() = 0;
    virtual int add(int i, int j) = 0;
};

struct Interface2
{
    virtual int add(int i, int j) = 0;
    virtual int minus(int i, int j) = 0;
};


//多继承:接口
class Child : public Interface1, public Interface2
{
public:  
    void print()
    {
        cout<<"Child::print"<<endl;
    }
    
    int add(int i, int j)
    {
        return i + j;
    }
    
    int minus(int i, int j)
    {
        return i - j;
    }
};

int main(int argc, char *argv[])
{
    Child c;
    
    c.print();
    
    cout<<c.add(3, 5)<<endl;
    cout<<c.minus(4, 6)<<endl;
    
    Interface1* i1 = &c;
    Interface2* i2 = &c;
    
    cout<<i1->add(7, 8)<<endl;
    cout<<i2->add(7, 8)<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif

//19.3 多重继承:面向对象语言中只有C++支持,增加了程序复杂性,故被工程抛弃。
#ifdef LESSON19_example19_3_class_more_jicheng
#include <cstdlib>
#include <iostream>

using namespace std;

class Object
{
protected:
    int d;
public:
    void f()
    {
        cout<<"Object::f"<<endl;
    }
};
//二义性可以通过虚继承来解决,但是问题来了,大工程怎么知道哪些要要虚
//class P1 : virtual public Object
class P1 : public Object
{
protected:
    int i;
};

//class P2 : virtual public Object
class P2 : public Object
{
protected:
    int j;
};


//多重继承
class Child : public P1, public P2
{
public:
    Child(int i, int j)
    {
        //提示d是模糊的,编译器不知道怎么办了
        this->d = 0;
        this->i = i;
        this->j = j;
    }
    
    void print()
    {
        cout<<"i = "<<i<<" "<<"j = "<<j<<endl;
    }
};

int main(int argc, char *argv[])
{
    Child c(1, 2);
    
    c.print();
    c.f();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//19.2 函数重写:多态: 不要将多态应用于数组   
#ifdef LESSON19_example19_2_class_virtual_array
     
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
protected:
    int i;
public:
    virtual void f()
    {
        cout<<"Parent::f"<<endl;
    }
};

class Child : public Parent
{
protected:
    int j;
public:
    Child(int i, int j)
    {
        this->i = i;
        this->j = j;
    }
    
    void f()
    {
        cout<<"i = "<<i<<" "<<"j = "<<j<<endl;
    }
};

int main(int argc, char *argv[])
{
    Parent* p = NULL;
    Child* c = NULL;
    Child ca[3] = {Child(1, 2), Child(3, 4), Child(5, 6)};
    
    p = ca;
    c = ca;
    
    cout<<hex<<p+1<<endl;
    
    p->f();
    c->f();
    
    /*
        程序挂掉了
        1. p++ 等同于p+1; 实现:(unsigned int)p + 1*sizeof(*p) , 以p类型为偏移单位。   
        2. 而重写:多态,是通过虚函数表指针来查找相应函数指针。
        3. 当子类的大小比父类大小大时,偏移大小便不同了,故虚函数表指针需错位,故找不到相应函数指针。
    */
    cout << dec << endl;
    //两个类大小不同
    cout << "sizeof(Parent): " << sizeof(Parent) <<endl;    
    cout << "sizeof(Child): " << sizeof(Child) <<endl;
    
    cout << hex << endl;
    
    cout << "&ca[0]:" << &ca[0] << endl;//0x28fef4
    cout << "&ca[1]:" << &ca[1] << endl;//0x28ff00 = 0x28fef4+0x0c = &ca[0] + sizeof(Parent)
    
     cout<<"p++:"<<p+1<<endl;//0x28fefc = 0x28fef4+0x08 = &ca[0] + sizeof(Child)  故:不要将多态应用于数组   
    
    
    
    
    //p++;  //Error
    c++;
    
    p->f();
    c->f();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//19.1 函数重写:多态: 不要将多态应用于数组   
#ifdef LESSON19_example19_1_class_virtual_array
     
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
protected:
    int i;
public:
    virtual void f()
    {
        cout<<"Parent::f"<<endl;
    }
};

class Child : public Parent
{
protected:
    int j;
public:
    Child(int i, int j)
    {
        this->i = i;
        this->j = j;
    }
    
    void f()
    {
        cout<<"i = "<<i<<" "<<"j = "<<j<<endl;
    }
};

int main(int argc, char *argv[])
{
    Parent* p = NULL;
    Child* c = NULL;
    Child ca[3] = {Child(1, 2), Child(3, 4), Child(5, 6)};
    
    
    p = ca;
    c = ca;
    
    //iomanip.h是I/O流控制头文件,就像C里面的格式化输出一样.以下是一些常的:
    //dec 置基数为10 相当于"%d"
    //hex 置基数为16 相当于"%X"
    //oct 置基数为8 相当于"%o"
    cout<<dec<<16<<endl;
    cout<<hex<<16<<endl;
    cout<<oct<<16<<endl;

    cout<<hex<<p+1<<endl;
    
    p->f();
    c->f();
    
    /*
        程序挂掉了
        1. p++ 等同于p+1; 实现:(unsigned int)p + 1*sizeof(*p) , 以p类型为偏移单位。   
        2. 而重写:多态,是通过虚函数表指针来查找相应函数指针。
        3. 当子类的大小比父类大小大时,偏移大小便不同了,故虚函数表指针需错位,故找不到相应函数指针。
    */
    //p++;  //Error
    c++;
    
    p->f();
    c->f();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//18.3 纯虚函数: 只有接口,没有实现,不能创建对象,可以用来定义指针接受子类对象。
#ifdef LESSON18_example18_2_class_pure_virtual_func
#include <cstdlib>
#include <iostream>

using namespace std;

//形状是没有大小的。
class Shape
{
public:
    //定义纯虚函数,只有接口,没有实现
    virtual double area() = 0;
};

class Rectangle : public Shape
{
    double m_a;
    double m_b;
public:
    Rectangle(double a, double b)
    {
        m_a = a;
        m_b = b;
    }
    
    double area()
    {
        return m_a * m_b;
    }
};

class Circle : public Shape
{
    double m_r;
public:
    Circle(double r)
    {
        m_r = r;
    }
    
    double area()
    {
        return 3.14 * m_r * m_r;
    }
};

//纯虚函数可以用来接受它的子类对象。
void area(Shape* s)
{
    cout<<s->area()<<endl;
}

int main(int argc, char *argv[])
{
    Rectangle rect(2, 3);
    Circle circle(4);
    
    //纯虚函数无法创建对象
    //Shape s;
    
    area(&rect);
    area(&circle);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//18.2 构造函数无法调用重写函数,故无法发生多态。
#ifdef LESSON18_example18_2_class_constructor_overwrite
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
public:
    Parent()
    {
        //创建子类对象时会调用父类构造函数,此时调用重写的函数,多态是不会发生的。
        this->func();   //void Parent::func()
    }
    
    void rewrite(void)
    {
        this->func();   //void Child::func()
    }
    
    virtual void func()
    {
        cout<<"void Parent::func()"<<endl;
    }
};

class Child : public Parent
{
public:
    Child()
    {
        this->func();
    }
        
    void func()
    {
        cout<<"void Child::func()"<<endl;
    }
};

/*
    构造函数无法发生多态。
    原因:对象在创建的时候又编译器对虚函数表指针进行初始化。
    只有构造函数完成后虚函数表的指针才确定指向父类还是子类。
     
*/


int main(int argc, char *argv[])
{
    Child c;
    
    //会调用重写函数,发生多态。
    c.rewrite();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif

//18.1 重写重载区别:重载发生在同一作用域,重写发生在父类子类之间。
#ifdef LESSON18_example18_1_class_overwrite_overload
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
protected:
    char i;
    
public:
    //同类(同一作用域)里面的同名函数发生重载
    virtual void func()
    {
        cout<<"void func()"<<endl;
    }
    
    virtual void func(int i)
    {
        cout<<"void func(int i)"<<endl;
    }
    
    virtual void func(int i, int j)
    {
        cout<<"void func(int i, int j)"<<endl;
    }
};

class Child : public Parent
{
public:  
    //重写父类成员函数
    void func(int i, int j)
    {
        cout<<"void func(int i, int j)"<<" "<<i + j<<endl;
    }
    
    void func(int i, int j, int k)
    {
        cout<<"void func(int i, int j, int k)"<<" "<<i + j + k<<endl;
    }
 
};

void run(Parent* p)
{
    p->func(1, 2);
}

/*
    1. 问题:重载和重写有什么区别?什么时候是重载,什么时候是重写?
        1.1 重载发生在同一作用域里面(同一个类里面),故子类无法重载父类的函数。
        1.2 重写发生在父类与子类之间的相同类型函数。
        1.3 重载在编译阶段就根据参数类型及个数就确定了调用哪个函数。而重写是在运行阶段根据实际对象调用哪个函数。
         
    
    2. 多态:虚函数原理:
         类中声明虚函数时,编译器会生成一个虚函数表,虚函数表就是存储成员函数指针的结构。
         函数调用时,会判断是否为虚函数,若是虚函数则遍历虚函数表,并找到对象的函数指针,并执行。
         若不是虚函数,则直接调用成员函数。(少了个遍历的过程,效率高些)
         
    3. 是否可以将每个类成员函数都声明为虚函数?
        回答:不可以,虚函数调用时会有额外的开销,若对运行效率要求较高的话,最好不要使用虚函数。
         
*/


int main(int argc, char *argv[])
{
    Parent p;
    
    p.func();
    p.func(1);
    p.func(1, 2);
    
    Child c;
    
    c.func(1, 2);
    
    run(&p);
    run(&c);
    
    cout << "sizeof(Parent) :" << sizeof(Parent) <<endl;    //8: 4个字节是int i,4个字节是虚函数表指针
    cout << "sizeof(Child) :" << sizeof(Child) <<endl;  //8
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif





//17.2 父类接受子类:多态:根据实际对象而调用相应的方法
#ifdef LESSON17_example17_3_class_parent_save_child_virtual
#include <cstdlib>
#include <iostream>

using namespace std;

class Boss
{
private:
    static Boss* cInstance;
    
    Boss()
    {
    }
public:
    static Boss* GetInstance()
    {
        if( cInstance == NULL )
        {
             cInstance = new Boss();
        }
        
        return cInstance;
    }
    
    int fight()
    {
        cout<<"Boss::fight()"<<endl;
        return 10;
    }
};

Boss* Boss::cInstance = NULL;

class Master
{
public:
    virtual int eightSwordKill()
    {
        cout<<"Master::eightSwordKill()"<<endl;
        return 8;
    }
};

class NewMaster : public Master
{
public:
    virtual int eightSwordKill()
    {
        cout<<"NewMaster::eightSwordKill()"<<endl;
        return Master::eightSwordKill() * 2;
    }
};

void fieldPK(Master* master, Boss* boss)
{
    int k = master->eightSwordKill();
    int b = boss->fight();
    
    if( k < b )
    {
        cout<<"Master is killed..."<<endl;
    }
    else
    {
        cout<<"Boss is killed..."<<endl;
    }
}

int main(int argc, char *argv[])
{
    Boss* boss = Boss::GetInstance();
    
    cout<<"Master vs Boss"<<endl;
    
    Master master;
    
    fieldPK(&master, boss);
    
    cin.get();
    
    cout<<"New Master vs Boss"<<endl;
    
    
    
    NewMaster newMaster;
    
    fieldPK(&newMaster, boss);
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}


#endif

//17.2 父类接受子类:只能调用父类的方法。
#ifdef LESSON17_example17_2_class_parent_save_child
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
protected:
    int i;
public:
    Parent()
    {
        cout<<"Parent()"<<endl;
        i = 1;    
    }
    
    void print()
    {
        cout<<"I'm Parent..."<<endl;
        cout<<"i = " << i <<endl;
    }
};

class Child : public Parent
{
//若子类成员变量与父类相同。 void howToPrint(Parent* p):调用的是父类的方法,若传进来的是&child,故访问的成员变量还是父类的i
//protected:
//    int i;
public:
    Child()
    {
        cout<<"Child()"<<endl;
        i = 2;    
    }
    void print()
    {
        cout<<"I'm Child..."<<endl;
        cout<<"i = " << i <<endl;
    }
};

//调用的是父类的方法,若传进来的是&child,故访问的成员变量还是child的i
void howToPrint(Parent* p)
{
    p->print();
}

void run()
{
    Child child;
    Parent* pp = &child;
    Parent& rp = child;
    
    child.print();  //I'm Child...
    
    pp->print();    //I'm Parent...
    rp.print();//I'm Parent...
    
    cout << "..." <<endl;
    Parent p;
    howToPrint(&child);//I'm Parent...
    howToPrint(&p);//I'm Parent...
}

int main(int argc, char *argv[])
{
    run();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//17.1 子父类相同成员函数名:子类重写父类成员函数,父类成员函数依然存在子类之中。
#ifdef LESSON17_example17_1_class_member_same_func_name
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
public:
    void print()
    {
        cout<<"I'm Parent..."<<endl;
    }
};

class Child : public Parent
{
public:
    
    //子类重写父类成员函数,父类成员函数依然存在子类之中。
    void print()
    {
        cout<<"I'm Child..."<<endl;
    }
};

/*
    函数重写:
    1. 概念:子类定义了与父类相同原型的函数。
    2. 函数重写只发生在父类与子类之间
    3. 父类被重写的函数依然存继承给子类。
    4. 通过作用域标识符::可以访问父类被重写的函数。
*/

int main(int argc, char *argv[])
{
    Child child;
    
    child.print();
    
    //通过作用域标识符::可以访问父类被重写的函数。
    child.Parent::print();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif




//16.5 父类子类同名成员变量: 子类同时包含两个成员变量。存放在不同作用域
#ifdef LESSON16_example16_5_class_parent_same_member_name
#include <cstdlib>
#include <iostream>

using namespace std;


class Parent
{
protected:
    int i;
    int f;
};

//子类继承父类
class Child : public Parent
{
protected:
    //子类成员变量名与父类成员变量名相同
    int i;
    
    void f()
    {
        cout<<"Parent::i = "<<Parent::i<<endl;
        cout<<"Child::i = "<<Child::i<<endl;
        cout<<"Parent::f = "<<Parent::f<<endl;
        
        //默认调用子类的i
        cout<<"i = "<<i<<endl;
    }
public:
    Child(int i, int j)
    {
        Parent::i = i;
        Child::i = j;
    
        Parent::f = i + j;
        
        f();
    }
};

/*
    子类成员变量名与父类成员变量名相同
    1. 子类同时包含两个成员变量。存放在不同作用域
    2. 通过不同作用域来访问两个变量:2.1 Child::成员变量,2.2 Parent::成员变量
    3. 默认成员变量是子类成员变量
*/

void run()
{
    Child child(1, 3);
}

int main(int argc, char *argv[])
{
    run();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//16.4 子类继承父类:且包好其他类成员: 构造函数调用顺序:先父母,后客人,再自己。
#ifdef LESSON16_example16_4_class_parent_child_others
#include <cstdlib>
#include <iostream>

using namespace std;

class Object
{
public:
    Object(const char* s)
    {
        cout<<"Object()"<<" "<<s<<endl;
    }
};

//父类继承对象类
class Parent : public Object
{
public:
    //1. 先调用Object构造函数,
    Parent(const char* s) : Object(s)
    {
        cout<<"Parent()"<<" "<<s<<endl;
    }
};

//子类继承父类
class Child : public Parent
{
protected:
    //子类成员包含其他类
    Object o1;
    Object o2;
public:
    //1. 先调用Parent构造函数,2. 再调用o1参数初始化,2.最后调用o2参数初始化
    Child() : o2("o2"), o1("o1"), Parent("Parameter from Child!")
    {
        cout<<"Child()"<<endl;
    }
};

void run()
{
    Child child;
}

/*
    如果一个类继承了父类并且有其他对象作为成员,
    1. 构造函数调用顺序:先父母,后客人,再自己。
*/

int main(int argc, char *argv[])
{
    run();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//16.3 继承构造函数:参数列表  
#ifdef LESSON16_example16_3_class_parent_child_constructor_param_list
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
public:
    Parent(const char* s)
    {
        cout<<"Parent(): "<<" "<<s<<endl;
    }
    
    ~Parent()
    {
        cout<<"~Parent()"<<endl;
    }
};

class Child : public Parent
{
public:
    //参数列表
    Child() : Parent("Parameter from Child!")
    {
        cout<<"Child()"<<endl;
    }
    
    ~Child()
    {
        cout<<"~Child()"<<endl;
    }
};

void run()
{
    Child child;
}

int main(int argc, char *argv[])
{
    run();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif

//16.2 继承构造函数调用顺序:先调用父类,再调用子类构造函数,析构函数相反
#ifdef  LESSON16_example16_2_class_parent_child_constructor
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
public:
    Parent()
    {
        cout<<"Parent()"<<endl;
    }
    
    ~Parent()
    {
        cout<<"~Parent()"<<endl;
    }
};

class Child : public Parent
{
public:
    Child()
    {
        cout<<"Child()"<<endl;
    }
    
    ~Child()
    {
        cout<<"~Child()"<<endl;
    }
};

void run()
{
    //先调用父类,再调用子类构造函数,析构函数相反
    Child child;
}

int main(int argc, char *argv[])
{
    run();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif

//父类对象可以包含子类对象,访问的是父类的方法。
#ifdef LESSON16_example16_1_parent_save_child
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
protected:
    const char* name;
public:
    Parent()
    {
        cout<<"Parent()"<<endl;
        name = "Parent";
    }
    
    void print()
    {
        cout<<"Name: "<<name<<endl;
    }
};

class Child : public Parent
{
protected:
    int i;
    int j;
public:
    Child()
    {
        
    }
    Child(int i)
    {
        cout<<"Child(int i)"<<endl;
        this->name = "Child";
        this->i = i;
    }
    
    void print_child()
    {
        cout<<"I am Child"<<endl;
    }    
};

int main(int argc, char *argv[])
{
    Child child(1000);
    
    //父类对象可以包含子类对象,访问的是父类的方法。
    Parent parent = child;
    Parent* pp = &child;
    Parent& rp = child;
    
    //子类无法接收父类
    //Child c = parent; //Error
    
    child.print_child();
    
    parent.print();
    
    //父类无法访问子类成员
    //parent.print_child(); //Error
    
    pp->print();
    
    rp.print();
    
    cout << "sizeof(Child):" << sizeof(Child) << endl;//12
    cout << "sizeof(Parent):" << sizeof(Parent) << endl;//4
    
    cout << "sizeof(child):" << sizeof(child) << endl;//12
    cout << "sizeof(parent):" << sizeof(parent) << endl;//4  
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//15.4 继承:public、protected、private继承区别
#ifdef LESSON15_example15_4_jicheng_public_protected_private
#include <cstdlib>
#include <iostream>

using namespace std;

class A
{
private:
    int a;
protected:
    int b;
public:
    int c;
    
    A()
    {
        a = 0;
        b = 0;
        c = 0;
    }
    
    void set(int a, int b, int c)
    {
        this->a = a;
        this->b = b;
        this->c = c;
    }
};

class B : public A
{
public:
    void print()
    {
        cout<<"B:"<< endl;
        //父类的私有成员不能在子类直接访问
        //cout<<"a = "<<a;
        cout<<"b = "<< b << endl;
        cout<<"c = " << c <<endl;
    }
};

class C : protected A
{
public:
    void print()
    {
        cout<<"C:"<< endl;
        //cout<<"a = "<<a;
        cout<<"b = "<< b << endl;
        cout<<"c = " << c <<endl;
    }
    
     void setC(int a, int b, int c)
    {
        set(a, b, c);
    }       
};

class D : private A
{
public:
    void print()
    {
        cout<<"D:"<< endl;
        //cout<<"a = "<<a;
        cout<<"b = "<< b << endl;
        cout<<"c = " << c <<endl;
    }
    
     void setD(int a, int b, int c)
    {
        set(a, b, c);
        
        //private继承,可以在内部访问父类protected,public成员。
        this->b = 1;
        this->c = 1;
    }   
};

/*
    类成员访问级别设定:
    1. 需要被外界访问的成员设置为:public
    2. 只能在当前类访问的成员设置为:private
    3. 只能在当前类和子类访问的成员设置为:protected
    
    备注:private成员在子类依然存在,只是无法访问。
*/

/*
    继承:
    1. public继承:父类所有成员属性都被子类继承了,但是子类内部和外界都无法访问父类的私有成员
    2. protected继承,父类public成员退化为子类的protected成员,可以在子类内部使用,不可以在外界使用。
    3. private继承,父类public、protected成员退化为子类的private成员, 可以在子类内部使用,不可以在外界使用。
*/



int main(int argc, char *argv[])
{
    A aa;
    B bb;
    C cc;
    D dd;
   
    aa.c = 100;
    //public继承可以在外界直接访问父类的public成员
    bb.c = 100;
    
    //protected继承不可以在外界直接访问父类的public成员,但可以在子类内部直接访问
    //cc.c = 100;
    
    //private继承不可以在外界直接访问父类的public成员,但可以在子类内部直接访问
    //dd.c = 100;

    aa.set(1, 2, 3);
    bb.set(10, 20, 30);
    
    //protected继承不可以在外界直接访问父类的public成员,但可以在子类内部直接访问
    //cc.set(40, 50, 60);
    cc.setC(40, 50, 60);
    
    //private继承不可以在外界直接访问父类的public成员,但可以在子类内部直接访问  
    //dd.set(70, 80, 90);
    dd.setD(40, 50, 60);
   
    bb.print();
    cc.print();
    dd.print();
 
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//15.3 public继承:父类所有成员属性都被子类继承了,可以直接访问父类的protected成员
#ifdef LESSON15_example15_3_jicheng_public
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
//父类protected成员,可以在子类直接使用。
protected:
    int a;
public:
    Parent()
    {
        a = 1000;
    }
    
    void print()
    {
        cout<<"a = "<<a<<endl;
    }
};

class Child : public Parent
{
protected:
    int b;
public:
    void set(int a, int b)
    {
        //父类protected成员,可以在子类直接使用。
        this->a = a;
        this->b = b;
    }
};

int main(int argc, char *argv[])
{
    Parent parent;
    Child child;
    
    parent.print();
    child.print();
    
    child.set(2000, 400);
    child.print();
    
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//15.2 public继承:父类所有成员属性都被子类继承了,但是无法访问父类的私有成员
#ifdef LESSON15_example15_2_jicheng_public
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
private:
    int a;
public:
    Parent()
    {
        a = 1000;
    }
    
    void print()
    {
        cout<<"a = "<<a<<endl;
    }
};


//public继承
class Child : public Parent
{
private:
    int b;
public:
    void set(int a, int b)
    {
        //无法直接访问父类的private成员
        //this->a = a;
        //this->b = b;
    }
};

int main(int argc, char *argv[])
{
    Parent parent;
    Child child;
    
    parent.print();
    
    //public继承可以在外部直接访问父类的public成员。
    child.print();
    
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif




//15.1 默认继承:父类所有成员都变为子类private成员
#ifdef LESSON15_example15_1_jicheng_default
#include <cstdlib>
#include <iostream>

using namespace std;

class Parent
{
private:
    int a;
public:
    Parent()
    {
        a = 1000;
    }
    
    void print()
    {
        cout<<"a = "<<a<<endl;
    }
};


//默认继承,父类的所有成员都变为private,相当于:class Child :private Parent
class Child : Parent
{
    public:
    void print_own(void)
    {
        print();    
    }
};

int main(int argc, char *argv[])
{
    Parent parent;
    Child child;
    
    parent.print();
    
    //无法直接访问,因为该方法是private。
    //child.print();
    child.print_own();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif





//14.5 类可以实现状态函数,并且这个状态函数可以从头再来。
#ifdef LESSON14_example_14_5_class_auto_static
#include <cstdlib>
#include <iostream>

using namespace std;

class Fib
{
private:
    //使用自动变量,该变量与对象同生死,故类似静态变量。
    int a1;
    int a2;
public:
    Fib()
    {
        a1 = 0;
        a2 = 1;
    }
    
    //操作符()重载
    int operator() ()
    {
        int ret = a2;
        int t = a2;
        
        a2 = a2 + a1;
        a1 = t;
        
        return ret;
    }
};

int main(int argc, char *argv[])
{    
    Fib fib;
    
    cout<<"Fib fib;"<<endl;
    
    for(int i=1; i<=10; i++)
    {
        cout<<fib()<<endl;
    }
    
    
    //重新创建对象即可从头再来。
    Fib fib1;
    cout<<"Fib fib1;"<<endl;
    
    for(int i=1; i<=4; i++)
    {
        cout<<fib1()<<endl;
    }    
    
    for(int i=1; i<=4; i++)
    {
        cout<<fib1()<<endl;
    }        
    
    cout<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//14.4 函数中静态、自动变量:静态变量有记忆功能,无法从头再来。自动变量没有记忆功能,每次都是重新开始。
#ifdef LESSON14_example_14_4_func_auto_static
#include <cstdlib>
#include <iostream>

using namespace std;

//无状态函数,无记忆功能
int fib1(int i)
{
    int a1 = 0;
    int a2 = 1;
    int ret = a2;
    
    while( i > 1)
    {
        ret = a2 + a1;
        a1 = a2;
        a2 = ret;
        i--;
    }
    
    return ret;
}

//状态函数,有记忆功能
int fib2()
{
    static int a1 = 0;
    static int a2 = 1;
    
    int ret = a2;
    int t = a2;
    
    a2 = a2 + a1;
    a1 = t;
    
    return ret;
}

int main(int argc, char *argv[])
{
    for(int i=1; i<=10; i++)
    {
        cout<<fib1(i)<<endl;
    }
    
    for(int i=1; i<=10; i++)
    {
        cout<<fib2()<<endl;
    }
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//14.3 静态成员变量作用: 用于控制对象数目。单一对象系统
#ifdef LESSON14_example_14_3_class_member_static   
#include <cstdlib>
#include <iostream>

using namespace std;

class Singleton
{
private:
    //1.设计一个静态变量对象指针
    static Singleton* cInstance;
    
    //2. 构造函数是private,故外接无法直接创建对象。
    Singleton()
    {
    }
public:
    //3. 提供一个获取对象的方法。在方法里面控制对象个数
    static Singleton* GetInstance()
    {
        if( cInstance == NULL )
        {
            cout<<"new Singleton()"<<endl;
            cInstance = new Singleton();
        }
        
        return cInstance;
    }
    
    void print()
    {
        cout<<"I'm Singleton!"<<endl;
    }
};

//静态成员指针变量初始化
Singleton* Singleton::cInstance = NULL;

void func()
{
    //Singleton s; //构造函数为private,无法直接创建对象。
    Singleton* s = Singleton::GetInstance();
    Singleton* s1 = Singleton::GetInstance();
    Singleton* s2 = Singleton::GetInstance();
    
    cout<<s<<" "<<s1<<" "<<s2<<endl;
    
    s->print();
}

int main(int argc, char *argv[])
{
    func();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif




//14.2 编译器对构造函数调用:默认标准调用 Test t1(5);其他方式可能会转化为这种方式。
#ifdef LESSON14_example_14_2_constructor
#include <cstdlib>
#include <iostream>

using namespace std;

class Test
{
public:
    //explicit Test(int i)//告诉编译器不要自动调用构造函数
    Test(int i)
    {
        cout<<"Test(int i)"<<endl;
    }
    
    //explicit Test(const Test& obj)    //告诉编译器不要自动调用构造函数
    Test(const Test& obj)
    {
        cout<<"Test(const Test& obj)"<<endl;
    }
    
    ~Test()
    {
        cout<<"~Test"<<endl;
    }
};

void func()
{
    //标准的使用方式
    Test t1(5);
    
    //将int类型 5赋值给对象,编译器尝试调用Test(5)再赋值给t2,这样还是浪费资源。故继续优化,直接Test t1(5);。
    Test t2 = 5;
    
    //手动调用构造函数生成一个对象,之后将对象赋值给t3。  //中间临时对象浪费资源,编译器会优化: 直接Test t1(5);
    Test t3 = Test(5);
}

int main(int argc, char *argv[])
{
    func();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//14.1 new malloc区别: 都是申请堆内存, new可以初始化,调用构造函数功能。
#ifdef  LESSON14_example_14_1_new_mallloc
#include <cstdlib>
#include <iostream>

using namespace std;

class Test
{
private:
    int i;
public:
    Test()
    {
        cout<<"Test()"<<endl;
        i = 0;
    }
    
    Test(int i)
    {
        cout<<"Test(int i)"<<endl;
        this->i = i;
    }
    
    ~Test()
    {
        cout<<"~Test"<<endl;
    }
    
    int getI()
    {
        return i;
    }
};

void func()
{
    //从堆里面申请sizeof(int)个字节空间。
    int* p = reinterpret_cast<int*>(malloc(sizeof(int)));
    
    //从堆里面申请int类型字节空间,并初始化。
    int* q = new int();
    
    //malloc空间若没有重新赋值则是乱码。
    *p = 5;
    
    //new空间时已经初始化,故不需要再次赋值。
    //*q = 10;
    
    cout<<*p<<" "<<*q<<endl;
    
    free(p);
    delete q;
    
    
    //只是单纯地分配内存空间
    Test* op = reinterpret_cast<Test*>(malloc(sizeof(Test)));
    
    //new对象时自动调用构造函数
    Test* oq = new Test;
    
    cout<<op->getI()<<endl;
    cout<<oq->getI()<<endl;
    
    free(op);
    delete oq;
}

/*
    问题:malloc与free和new与delete有什么区别?
    1. malloc free是库函数,new delete是关键字。
    2. malloc以字节为单位申请堆内存。new以类型为单位申请对内存。
    3. malloc delete只是单纯地对内存进行申请和释放。
    4. new delete对基本类型申请空间时可以进行初始化。对类类型则会调用构造函数和析构函数。
*/

int main(int argc, char *argv[])
{
    func();
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif




//13.5 操作符重载:operator[],=,(),->,解释为什么只能通过成员函数方式来重载。确保为左值
#ifdef LESSON13_example13_5_operator_overload_operator_four
#include <iostream>
 
class X
{
public:
    X(){}
    X(int){} // int 类型可以被隐式转换成 X
    friend bool operator<(const X& x1, const X& x2) { return true; } // 只是测试,无意义
    
    //编译不通过:提示改函数应该为非静态成员函数。'bool operator[](const X&, const X&)' must be a nonstatic member function
    //friend bool operator[](const X& x1, const X& x2) { return true; } // 只是测试,无意义
    //friend bool operator()(const X& x1, const X& x2) { return true; } // 只是测试,无意义
    //friend bool operator=(const X& x1, const X& x2) { return true; } // 只是测试,无意义
    //friend bool operator->(const X& x1, const X& x2) { return true; } // 只是测试,无意义
};
 
class Y
{
public:
    Y(){}
    Y(int){} // int 类型可以被隐式转换成 Y
    bool operator<(const Y& y) const { return true; } // 只是测试,无意义
    
    //编译可以通过
    bool operator[](const Y& y) const { return true; } // 只是测试,无意义
    bool operator()(const Y& y) const { return true; } // 只是测试,无意义
    bool operator=(const Y& y) const { return true; } // 只是测试,无意义
    bool operator->(void) const { return true; } // 只是测试,无意义
          
};

/*
解释:为什么=,[],(),->等运算符只能重载成类的成员函数?  
由上面的代码可以知道,如果将 =,[],(),-> 进行友元全局重载,那么就会出现 1=x; 1[x]; 1->x; 1(x);
这样的合法语句(起码编译器认为这些是合法的)--参考代码中的 if(1<x) 合法的片段,但显然这些是需要避免的,
当然这些不是我们程序员的责任,应该有语言的设计者来实现,所以,就……。

总结:1. 使用成员函数为了使对象为第一个参数。像[],(),->,=必须是对象为左值。
     使用全局函数可能出现第一个参数不为对象而
*/
 
int main()
{
    X x;
    //if(1 < x) // 合法,使用友元重载函数,1 可以被隐式地转换为 X 类型 --友元函数的第一个参数
    if (operator<(1, x))
    {}
 
    Y y;
    //if(1 < y) // 不合法,使用成员重载函数,函数的第一个参数是 const *this,1 不能被隐式转换
    //if (1.operator<(y))
    if (y[1])
    if (y.operator[](1))
    {}
 
    return 0;
}
// 注:编译的时候可以通过注释掉不同的代码来查看错误(即合法性),后面解释不能作为友元全局重载的原因

#endif



//13.4 操作符重载:operator&&,operator||,不要重载,违背了短路功能。
#ifdef LESSON13_example13_4_operator_overload_and_or
#include <cstdlib>  //c++标准库
#include <iostream>

using namespace std;

class Test
{
    int i;
public:
    Test(int i)
    {
        this->i = i;
    }
    
    //成员函数:返回值,功能名称,参数
    Test operator+ (const Test& obj)
    {
        Test ret(0);
        
        cout<<"Test operator+ (const Test& obj)"<<endl;
        
        //成员函数操作的是成员变量
        ret.i = i + obj.i;
      
        //运算结果,值返回  
        return ret;
    }
    
    bool operator&& (const Test& obj)
    {
        cout<<"bool operator&& (const Test& obj)"<<endl;
        
        return i && obj.i;
    }
};

int main(int argc, char *argv[])
{
    int a1 = 0;
    int a2 = 1;
    
    if( a1 && (a1 + a2) )
    {
        //不会执行
        cout<<"Hello"<<endl;
    }
    
    
    Test t1 = 0;
    Test t2 = 1;
    
    //默认功能:与&&:短路功能,第一个条件为假,第二个条件不会执行
    //实际情况:操作符重载通过函数来实现,故第二个条件先执行,之后再执行第一个条件。与默认功能相违背。故不要对与&& ,或||进行重载
    //if (t1.operator&&(t1.operator+(t2)))
    if( t1 && (t1 + t2) )
    {
        cout<<"World"<<endl;
    }
    
    
    //或||也一样,若第一个条件为真,则第二个条件不会执行。故也不能进行操作符重载
    //if (t1.operator || (t1.operator+(t2)))
    //if( t1 || (t1 + t2) )
    //{
    //    cout<<"World"<<endl;
    //}    
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//13.3 操作符重载:operator++,  //有占位符,后++ ,//无占位符,前++,至于为什么,以后理解
#ifdef LESSON13_example13_3_operator_overload_plusplus
#include <cstdlib>
#include <iostream>

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }
    
    int getA()
    {
        return a;
    }
    
    int getB()
    {
        return b;
    }
    
    Complex operator+ (const Complex& c2);
    
    //有占位符,后++
    Complex operator++ (int);
    
    //无占位符,前++,至于为什么,以后理解
    Complex& operator++();
    
    friend ostream& operator<< (ostream& out, const Complex& c);
};

ostream& operator<< (ostream& out, const Complex& c)
{
    out<<c.a<<" + "<<c.b<<"i";
    
    return out;
}


Complex Complex::operator++ (int)
{
    //后++:先保存本身,之后自增。效率低些
    Complex ret = *this;
    
    a++;
    b++;
    
    return ret;
    
}

Complex& Complex::operator++()
{
    //前++:直接自增,效率高
    ++a;
    ++b;
    
    return *this;
}

Complex Complex::operator+ (const Complex& c2)
{
    Complex ret(0, 0);
    
    ret.a = this->a + c2.a;
    ret.b = this->b + c2.b;
    
    return ret;
}

int main(int argc, char *argv[])
{
    Complex c1(1, 2);
    Complex c2(3, 4);
    Complex c3 = c2;
    
    c2++;
    ++c3;
    
    cout<<c1<<endl;
    cout<<c2<<endl;
    cout<<c3<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//13.2 操作符重载:只要是标准没有实现的,都可以通过重载来手动的实现 对象+,=,==,!=。
#ifdef LESSON13_example13_2_operator_overload_class_array  

#include <stdio.h>

class Array
{
private:
    int mLength;
    int* mSpace;

public:
    Array(int length);
    Array(const Array& obj);
    int length();
    ~Array();
    int& operator[](int i);
    Array& operator= (const Array& obj);
    bool operator== (const Array& obj);
    bool operator!= (const Array& obj);
};


Array::Array(int length)
{
    if( length < 0 )
    {
        length = 0;
    }
    
    mLength = length;
    mSpace = new int[mLength];
}

Array::Array(const Array& obj)
{
    mLength = obj.mLength;
    
    mSpace = new int[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
}

int Array::length()
{
    return mLength;
}

Array::~Array()
{
    mLength = -1;
    printf("%08X\n", mSpace);
    delete[] mSpace;
}

int& Array::operator[](int i)
{
    return mSpace[i];
}

Array& Array::operator= (const Array& obj)
{
    //=:删除自身空间,重新分配大小,再值拷贝
    delete[] mSpace;
    
    mLength = obj.mLength;
    
    mSpace = new int[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
    
    //this是对象地址,引用是对象本身
    return *this;
}

bool Array::operator== (const Array& obj)
{
    bool ret = true;
    
    //先比较长度
    if( mLength == obj.mLength )
    {
        for(int i=0; i<mLength; i++)
        {
            //再比较数组元素
            if( mSpace[i] != obj.mSpace[i] )
            {
                ret = false;
                break;
            }
        }
    }
    else
    {
        ret = false;
    }
    
    return ret;
}

bool Array::operator!= (const Array& obj)
{
    return !(*this == obj);
}

int main()
{
    Array a1(10);
    Array a2(0);
    Array a3(0);
    
    if( a1 != a2 )
    {
        printf("a1 != a2\n");
    }
    
    for(int i=0; i<a1.length(); i++)
    {
        a1[i] = i + 1;
    }
    
    for(int i=0; i<a1.length(); i++)
    {
        printf("Element %d: %d\n", i, a1[i]);
    }
    
    a3 = a2 = a1;
    
    if( a1 == a2 )
    {
        printf("a1 == a2\n");
    }
    
    for(int i=0; i<a2.length(); i++)
    {
        printf("Element %d: %d\n", i, a2[i]);
    }
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif



//13.1 操作符重载:使用类成员函数实现,故不需要友元:friend
#ifdef LESSON13_example13_1_operator_overload_class_inner
#include <cstdlib>
#include <iostream>

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a, int b)
    {
        this->a = a;
        this->b = b;
    }
    
    int getA()
    {
        return a;
    }
    
    int getB()
    {
        return b;
    }
    
    //类成员函数实现操作符重载:因为有this指针,故只要一个参数
    Complex operator+ (const Complex& c2);
    
    friend ostream& operator<< (ostream& out, const Complex& c);
};

//无法修改左操作数类时:比如标准库的ostream类的out作为左操作时,无法在ostream类添加成员函数,故,必须的用全局函数方式进行重载。
ostream& operator<< (ostream& out, const Complex& c)
{
    out<<c.a<<" + "<<c.b<<"i";
    
    return out;
}

Complex Complex::operator+ (const Complex& c2)
{
    Complex ret(0, 0);
    
    ret.a = this->a + c2.a;
    ret.b = this->b + c2.b;
    
    return ret;
}

int main(int argc, char *argv[])
{
    Complex c1(1, 2);
    Complex c2(3, 4);
    Complex c3 = c1 + c2;
    
    cout<<c1<<endl;
    cout<<c2<<endl;
    cout<<c3<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//12.7 操作符重载:operator<<,使用全局函数方式,故需要友元:friend  
#ifdef LESSON12_example12_7_operator_overload
#include <cstdlib>
#include <iostream>

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a = 0, int b = 0)
    {
        this->a = a;
        this->b = b;
    }
    
    int getA()
    {
        return a;
    }
    
    int getB()
    {
        return b;
    }
    
    friend Complex operator+ (const Complex& c1, const Complex& c2);
    friend ostream& operator<< (ostream& out, const Complex& c);
};


//1. 返回ostream对象:cout,是为了兼容c++标准操作。可以连续输出
//2. 第一个参数为操作符的左边,第二个为操作符的右边
ostream& operator<< (ostream& out, const Complex& c)
{
    out<<c.a<<" + "<<c.b<<"i";
    
    return out;
}

Complex operator+ (const Complex& c1, const Complex& c2)
{
    Complex ret;
    
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    
    return ret;
}

int main(int argc, char *argv[])
{
    Complex c1(1, 2);
    Complex c2(3, 4);
    Complex c3 = c1 + c2;   //+操作符重载,
    
    cout<<c1<<endl;     //<<左移操作符重载,实现可以打印一个对象数据
    cout<<c2<<endl;
    cout<<c3<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif

 //12.6 操作符重载:operator+,使用全局函数方式,故需要友元:friend  
#ifdef LESSON12_example12_6_operator_overload
#include <cstdlib>
#include <iostream>

using namespace std;

class Complex
{
    int a;
    int b;
public:
    Complex(int a = 0, int b = 0)
    {
        this->a = a;
        this->b = b;
    }
    
    int getA()
    {
        return a;
    }
    
    int getB()
    {
        return b;
    }
    
    //友元,告诉编译器,该函数为类的朋友,可以访问类的任何成员(成员变量,成员函数)
    friend Complex operator+ (const Complex& c1, const Complex& c2);
};

//操作符重载,全局函数:需要两个参数
Complex operator+ (const Complex& c1, const Complex& c2)
{
    Complex ret;
    
    //通过访问类成员变量或函数是实现逻辑功能
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    
    return ret;
}

int main(int argc, char *argv[])
{
    Complex c1(1, 2);
    Complex c2(3, 4);
    Complex c3 = c1 + c2;   //从使用的角度,类对象可以先加,本质是通过调用函数的方式使用的,如下
    //Complex c3 = operator+(c1, c2);
    
    cout<<"c3.a = "<<c3.getA() <<endl;
    cout<<"c3.b = "<<c3.getB() <<endl;    
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif

 
//12.4 类对象:相加使用函数方式
#ifdef LESSON12_example12_4_class_plus
#include <cstdlib>
#include <iostream>

using namespace std;

struct Complex
{
    int a;
    int b;
};

Complex add(const Complex& c1, const Complex& c2)
{
    Complex ret;
    
    ret.a = c1.a + c2.a;
    ret.b = c1.b + c2.b;
    
    return ret;
}

int main(int argc, char *argv[])
{
    Complex c1 = {1, 2};
    Complex c2 = {3, 4};
    Complex c3 = add(c1, c2);
    
    cout<<"c3.a = "<<c3.a<<endl;
    cout<<"c3.b = "<<c3.b<<endl;
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif



//12.3 类对象:相加编译异常
#ifdef LESSON12_example12_3_class_plus
#include <cstdlib>
#include <iostream>

using namespace std;

struct Complex
{
    int a;
    int b;
};

int main(int argc, char *argv[])
{
    Complex c1 = {1, 2};
    Complex c2 = {3, 4};
    Complex c3 = c1 + c2;   //对象不可以相加,编译器读不懂。故需要在类中重载+操作符。
    
    cout << "Press the enter key to continue ...";
    cin.get();
    return EXIT_SUCCESS;
}

#endif


//c++标准库:<iosteam> cout cin使用
#ifdef LESSON12_example12_2_stdlib      

#include <iostream> //cout,cin对象使用时需要包含的头文件

using namespace std;

int main()
{
    cout<<"Hello World"<<endl;

    int x;
    int y;

    cout<<"1st Parameter: ";
    cin>>x;

    cout<<"2nd Parameter: ";
    cin>>y;

    cout<<"Result: "<<x+y<<endl;
    
    cin.get();
    cin.get(); //多个get才能停止在屏幕

    return 0;
}
#endif



//c++标准库:<cstdio>前缀为c,没有.h
#ifdef  LESSON12_example12_1_stdlib
#include <cstdio>   //c++的标准库,与c语言<stdio.h>不同,但是实现了c语言标准库的全部内容。

using namespace std;

int main()
{
    printf("Hello World!\n");

    printf("Press any key to continue...");

    getchar();

    return 0;
}
#endif




//11.4 编译器内部运行机制,用户角度,编译器角度
#ifdef LESSON11_4_class_inner

//本质就是基于c语言的结构体struct。进行内部转换。

/*
//用户角度                                                         //编译器角度
class Test                                                          struct Test
{                                                                   {
    private:                                                            int mI;    
        int mI;                                                     };
                                                                  
    public:                                                         void Test_initialize(Test *pThis, int i)
        Test(int i)                                                 {  
        {                                                               pThis->mI = i;    
            mI = i;                                                 }  
        }                                                           void Test_getI(Test *pThis)
                                                                    {
        int getI()                                                     return pThis->mI;         
        {                                                           }
            return mI;                                                              
        }                                                          
                                                                    void Test_Print()
        static void Print()                                         {         
        {                                                               printf("This is class test.\n");
            printf("This is class test.\n");                        }                      
        }                                                          
};                                                          


//用户角度                                                          //编译器角度
Test a(10);                                                         Test a;
                                                                    Test_initialize(&a, 10);
a.getI();                                                           Test_getI(&a);
Test::Print();                                                      Test_Print();
    
*/

#endif





//11.3 this指针: this == &对象。对象其实就是结构体,对象指针就是结构体地址。通过->访问类成员(变量,函数)
#ifdef LESSON11_3_class_this_point
#include <stdio.h>


struct C {
    int i;
    int j;
    int k;
    static int c;    
};

class Test
{
    int i;
    int j;
    int k;
    
    static int c;
public:
    Test(int i, int j, int k)
    {
        //对象指针:this == &t1。对象其实就是结构体,对象指针就是结构体地址。通过->访问类成员(变量,函数)
        this->i = i;
        this->j = j;
        this->k = k;
        this->print_test();
    }
    
    void print()
    {
        printf("Object Address: %08X\n", this);
        printf("&c = %08X, c = %d\n", &c, c);
        printf("&i = %08X, i = %d\n", &i, i);
        printf("&j = %08X, j = %d\n", &j, j);
        printf("&k = %08X, k = %d\n", &k, k);
    }
    
    void print_test()
    {
        printf("print_test\n");    
    }
};

int Test::c;

int main()
{
    Test t1(0, 1, 2);
    Test t2(3, 4, 5);
    
    printf("t1 Address: %08X\n", &t1);
    t1.print();
    printf("t2 Address: %08X\n", &t2);
    t2.print();
    
    
    /*
        对象大小:
        1. 对象成员变量与成员函数是分开存储的
        2. 普通成员变量:存储在对象中,与结构体struct相同
        3. 静态成员变量:存储在全局数据区。
        4. 成员函数:存储在代码段中。
        
        5. 从用户的角度class是将属性+方法集成在同一个位置。
           从计算机的角度,依然是数据段+程序段
    */
    printf("\nsize:\n");
    printf("sizeof(C) = %d\n", sizeof(C));
    printf("sizeof(Test) = %d\n", sizeof(Test));    
    printf("sizeof(t1) = %d\n", sizeof(t1));  
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif



//11.2 类静态成员:静态成员变量,静态成员函数,统计创建对象个数
#ifdef LESSON11_2_class_static_count
#include <stdio.h>

class Test
{
private:
    static int cCount;
public:
    static int GetCount()
    {
        return cCount;
    }
    
    //构造函数,创建对象时调用
    Test()
    {
        cCount++;
    }
    
    //析构函数,销毁对象时调用
    ~Test()
    {
        cCount--;
    }
};

//为类静态成员变量分配空间
int Test::cCount = 0;

void run()
{
    Test ta[100];
    
    printf("Number of Object: %d\n", Test::GetCount());
}

int main()
{
    Test t1;
    Test t2;
    
    printf("Number of Object: %d\n", Test::GetCount());
    
    run();
    
    printf("Number of Object: %d\n", Test::GetCount());
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//11.1 类静态成员:静态成员变量,静态成员函数
#ifdef LESSON11_1_class_static
#include <stdio.h>

class Test
{
private:
    //类静态成员变量
    static int cI;
public:
    
    //类静态成员函数
    static int GetI()
    {
        return cI;
    }
    
    static void SetI(int i)
    {
        cI = i;
    }
    
    void print()
    {
        printf("cI = %d\n", cI);
    }
};

//初始化类静态成员变量
int Test::cI = 0;


/*
    类静态成员:
    1. 类静态成员不需要创建对象即可访问,通过类名访问,有点像命名空间
    2. 类静态成员共享与所有对象。
    3. 类静态成员变量需要初始化分配空间。
    
*/


int main()
{
    printf("Test::cI = %d\n", Test::GetI());
    
    Test::SetI(5);
    printf("Test::cI = %d\n", Test::GetI());
    
    Test t1;
    Test t2;
    
    t1.print();
    t2.print();
    
    t1.SetI(10);
    
    t2.print();
    
    printf("Test::cI = %d\n", Test::GetI());
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//10.5 析构函数:直接调用构造函数,创建一个空白对象,很快就被销毁了
#ifdef LESSON10_5_object_destructor_order   
#include <stdio.h>

class Test
{
private:
    int mI;
    int mJ;
    const char* mS;
public:
    Test()
    {
        printf("Test()\n");
        
        mI = 0;
        mJ = 0;
    }
    
    Test(const char* s)
    {
        printf("Test(const char* s)\n");
        
        //构造一个对象,然后马上释放
        Test();
        
        mS = s;
    }
    
    ~Test()
    {
        printf("~Test()\n");
    }
    
    void print()
    {
        printf("mI = %d, mJ = %d, mS = %s\n", mI, mJ, mS);
    }
};

void run()
{
    Test t = Test("Delphi Tang"); // Test t("Delphi Tang");
    
    t.print();
}

int main()
{
    run();
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//10.4 析构函数:析构函数调用顺序与构造函数调用顺序相反
#ifdef LESSON10_4_object_destructor_order
#include <stdio.h>

class Test
{
private:
    int mI;
public:
    Test()
    {
        printf("Test()\n");
        mI = -1;
    }
    
    Test(int i)
    {
        printf("Test(int i), i = %d\n", i);
        mI = i;
    }
    
    Test(const Test& obj)
    {
        printf("Test(const Test& obj), i = %d\n", obj.mI);
        mI = obj.mI;
    }
    
    //析构函数调用顺序与构造函数调用顺序相反
    ~Test()
    {
        printf("~Test(), i = %d\n", mI);
    }
};

void func(Test t)
{
    Test r(1);
}

void run()
{
    Test t(0);
    
    func(t);
}

int main()
{
    run();
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif

//10.3 析构函数:释放资源,数组类
#ifdef LESSON10_3_object_destructor_array
#include <stdio.h>

class Array
{
private:
    int mLength;
    int* mSpace;

public:
    Array(int length);
    Array(const Array& obj);
    int length();
    void setData(int index, int value);
    int getData(int index);
    ~Array();
};


Array::Array(int length)
{
    if( length < 0 )
    {
        length = 0;
    }
    
    mLength = length;
    mSpace = new int[mLength];
}

Array::Array(const Array& obj)
{
    mLength = obj.mLength;
    
    mSpace = new int[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
}

int Array::length()
{
    return mLength;
}

void Array::setData(int index, int value)
{
    mSpace[index] = value;
}

int Array::getData(int index)
{
    return mSpace[index];
}

//析构函数,释放资源
Array::~Array()
{
    mLength = -1;
    delete[] mSpace;
}



int main()
{
    Array a1(10);
    
    for(int i=0; i<a1.length(); i++)
    {
        a1.setData(i, i);
    }
    
    for(int i=0; i<a1.length(); i++)
    {
        printf("Element %d: %d\n", i, a1.getData(i));
    }
    
    Array a2 = a1;
    
    for(int i=0; i<a2.length(); i++)
    {
        printf("Element %d: %d\n", i, a2.getData(i));
    }
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif



//10.2 析构函数:释放资源,没有参数,没有返回值
#ifdef LESSON10_2_object_destructor
#include <stdio.h>

class Test
{
private:
    int mI;
public:
    //构造函数
    Test(int i) : mI(i)
    {
        printf("Test(), mI = %d\n", mI);
    }
    
    //析构函数
    ~Test()
    {
        printf("~Test(), mI = %d\n", mI);
    }
};

void run()
{
    Test t1(1);
    Test t2(2);
}

int main()
{
    run();
    
    printf("Press any key to continue...");
    getchar();
    
    return 0;
}

#endif

         

//10.1 构造函数:参数列表:顺序无关,参数列表先调用,再调用构造函数
#ifdef LESSON10_1_object_constructor_param_list    
#include <stdio.h>

class M
{
private:
    int mI;
public:
    M(int i)
    {
        printf("M(int i), i = %d\n", i);
        mI = i;
    }
    
    int getI()
    {
        return mI;
    }
};

class Test
{
private:
    //const int c = 0;//无法直接初始化,故该变量将分配内存,退化为只读变量
    const int c;
    
    //类包含另一个类对象
    M m1;
    M m2;
public:
    //参数列表:顺序无关,参数列表先调用,再调用构造函数
    Test() : m2(3), m1(2), c(1)
    {
        printf("Test()\n");
    }
    
    void print()
    {
        printf("c = %d, m1.mI = %d, m2.mI = %d\n", c, m1.getI(), m2.getI());
    }
};

/*
    初始化:创建对象时
    赋值:对象已经存在了
*/


int main()
{
    Test t1;
    t1.print();
    
    printf("Press any key to continue...");
    getchar();
    
    return 0;
}


#endif





//9.7 数组类:优化数组类拷贝构造函数
#ifdef LESSON9_class_example_array

#include <stdio.h>


class Array
{
private:
    int mLength;
    int* mSpace;

public:
    Array(int length);
    Array(const Array& obj);
    int length();
    void setData(int index, int value);
    int getData(int index);
    void destory();
};



Array::Array(int length)
{
    if( length < 0 )
    {
        length = 0;
    }
    
    mLength = length;
    mSpace = new int[mLength];
}

//重新设计拷贝构造函数,优化
Array::Array(const Array& obj)
{
    mLength = obj.mLength;
    
    mSpace = new int[mLength];
    
    for(int i=0; i<mLength; i++)
    {
        mSpace[i] = obj.mSpace[i];
    }
}

int Array::length()
{
    return mLength;
}

void Array::setData(int index, int value)
{
    mSpace[index] = value;
}

int Array::getData(int index)
{
    return mSpace[index];
}

void Array::destory()
{
    mLength = -1;
    delete[] mSpace;
}


int main()
{
    Array a1(10);
    
    for(int i=0; i<a1.length(); i++)
    {
        a1.setData(i, i);
    }
    
    for(int i=0; i<a1.length(); i++)
    {
        printf("Element %d: %d\n", i, a1.getData(i));
    }
    
    Array a2 = a1;
    
    for(int i=0; i<a2.length(); i++)
    {
        printf("Element %d: %d\n", i, a2.getData(i));
    }
    
    a1.destory();
    
    //若没有重新构造拷贝构造函数,两个对象指向同一个存储空间。导致异常
    a2.destory();
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif

//9.6 构造函数: 自动:无参构造函数,拷贝构造函数。
#ifdef LESSON9_6_object_constructor
#include <stdio.h>


class Test
{
private:
    int i;
    int j;
    int k;
    
public:
    void print()
    {
        printf("i = %d, j = %d, k = %d\n", i, j, k);
    }
};

int main()
{
    Test t1;
    Test t2 = t1;
    
    t1.print();
    t2.print();
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//9.5 构造函数: 无参构造函数,拷贝构造函数。
#ifdef LESSON9_5_object_constructor
#include <stdio.h>

/*
    注意:
    1. 当类中没有定义任何一个构造函数,C++编译器会为提供无参构造函数和拷贝构造函数
    2. 当类中定义了任意的非拷贝构造函数时,C++编译器不会为提供无参构造函数
*/

class Test
{
public:
    Test()
    {
        printf("Test()\n");
    }
    
    Test(const Test& obj)
    {
        printf("Test(const Test& obj)\n");
    }
};

int main()
{
    Test t1;
    Test t2 = t1;
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//9.4 构造函数: 用于初始化
#ifdef LESSON9_4_object_constructor
#include <stdio.h>

class Test
{
private:
    int i;
    int j;
    int k;
    
public:
    Test()
    {
        i = 0;
        j = 0;
        k = 0;
    }
    
    Test(int v)
    {
        i = v;
        j = v;
        k = v;
    }
    
    void print()
    {
        printf("i = %d, j = %d, k = %d\n", i, j, k);
    }
    
    void print(int v)
    {
        printf("v = %d\n", v);
    }
};

int main()
{
    Test t1(4);
    Test t2 = 5;
    Test t3 = Test(6);
    Test t4;
    
    t4.print();
    t1.print();
    t2.print();
    t3.print();
    
    Test tA[3];
    
    for(int i=0; i<3; i++)
    {
        tA[i].print();
    }
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}



#endif



//9.3 构造函数: 用于初始化
#ifdef LESSON9_3_object_constructor
#include <stdio.h>

class Test
{
private:
    int i;
    int j;
    int k;
    
public:
    Test(int v)
    {
        i = v;
        j = v;
        k = v;
    }
    
    void print()
    {
        printf("i = %d, j = %d, k = %d\n", i, j, k);
    }
};

/*
    析构函数:
    1. 与类名相同的特殊成员函数:默认:无参构造函数,拷贝构造函数
    2. 可以有参数,但是没有返回值。
    3. 创建对象是自动调用
    4. 可以重载
    5. 用于初始化
    
     
*/

int main()
{
    Test t1(4);
    Test t2 = 5;
    Test t3 = Test(6);
    
    t1.print();
    t2.print();
    t3.print();
    
    Test tA[3] = {Test(1), Test(2), Test(3)};
    
    for(int i=0; i<3; i++)
    {
        tA[i].print();
    }
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}


#endif



#ifdef LESSON9_2_object_init
#include <stdio.h>

class Test
{
private:
    int i;
    int j;
    int k;
    
public:
    void initialize()
    {
        i = 0;
        j = 0;
        k = 0;
    }
    
    void print()
    {
        printf("i = %d, j = %d, k = %d\n", i, j, k);
    }
};

int main()
{
    Test t1;
    Test t2;
    Test t3;
    
    t1.initialize();
    
    t1.print();
    t2.print();
    t3.print();
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//9.1 类:初始化
#ifdef LESSON9_1_object_init      
#include <stdio.h>

class Test
{
private:
    int i;
public:
    void initialize()
    {
        i = 0;
    }
    
    int getI()
    {
        return i;
    }
};

int main()
{
    Test t1;
    Test t2;
    Test t3;
    
    t1.initialize();
    t2.initialize();
    t3.initialize();
    
    printf("t1.i = %d\n", t1.getI());
    printf("t2.i = %d\n", t2.getI());
    printf("t3.i = %d\n", t3.getI());
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif




//8.4 操作类:类的精华在于封装: 将实现与接口分离。
#ifdef LESSON8_4_class_operator_test
#include <stdio.h>

class Operator
{
private:
    char mOp;
    double mP1;
    double mP2;
    
public:
    bool setOperator(char op);
    void setParameter(double p1, double p2);
    bool result(double& r);
};


//设置操作符,通过成员变量记录下来
bool Operator::setOperator(char op)
{
    bool ret = false;
        
    if( (op == '+') || (op == '-') || (op == '*') || (op == '/') )
    {
        ret = true;
        mOp = op;
    }
    else
    {
        mOp = '\0';
    }
        
    return ret;
}

//设置操作参数,通过成员变量记录下来
void Operator::setParameter(double p1, double p2)
{
    mP1 = p1;
    mP2 = p2;
}

//根据已经设置的参数及操作符,做运算     
bool Operator::result(double& r)
{
    bool ret = true;
        
    switch( mOp )
    {
        case '/':
            if( (-0.000000001 < mP2) && (mP2 < 0.000000001) )
            {
                ret = false;
            }
            else
            {
                r = mP1 / mP2;
            }
            break;
        case '+':
            r = mP1 + mP2;
            break;
        case '*':
            r = mP1 * mP2;
            break;
        case '-':
            r = mP1 - mP2;
            break;
        default:
            ret = false;
            break;
    }
        
    return ret;
}


int main(int argc, char *argv[])
{
    Operator op;
    double r = 0;
    
    printf("nul = %d\n", '\0');
    
    op.setOperator('/');
    op.setParameter(8, 4);
    
    if( op.result(r) )
    {
        printf("Result is %f\n", r);
    }
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif




   


//8.3 struct class区别:struct 默认权限为public,class 默认权限为private,
#ifdef LESSON8_1_class_struct
#include <stdio.h>

struct A
{
    int i;
    
    int getI()
    {
        return i;
    }
};

class B
{
    int i;
    
    int getI()
    {
        return i;
    }
};

int main(int argc, char *argv[])
{
    A a;
    B b;
    
    //struct 默认权限为public,可以直接访问
    a.i = 1;
    a.getI();
    
    //class 默认权限为private,不能直接访问
    //b.i = 2;
    //b.getI();
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//8.2 类成员作用域:类私有成员只能通过成员函数来访问。
#ifdef LESSON8_example8_2_struct_member
#include <stdio.h>

int i = 11;

struct Test
{
private:
    int i;

public:
    int j;
        
    int getI()
    {
        i = 3;
        
        return i;
    }
};

int main()
{
    int i = 2;
    
    Test test;
    
    test.j = 4;
    
    printf("i = %d\n", i);
    printf("::i = %d\n", ::i);
    //printf("test.i = %d\n", test.i);
    printf("test.j = %d\n", test.j);
    
    //类私有成员只能通过成员函数来访问。
    printf("test.getI() = %d\n", test.getI());
    
    printf("Press any key to continue...");
    getchar();
    
    return 0;
}

#endif




//8.1 类成员: 成员变量,成员函数。
#ifdef LESSON8_example8_1_struct_member
#include <stdio.h>

struct Biology
{
    bool living;
};

struct Animal : Biology
{
    bool movable;
    void findFood()
    {
    }
};

struct Plant : Biology
{
    bool growable;
};

struct Beast : Animal
{
    void sleep()
    {
    }
};

struct Human : Animal
{
    void sleep()
    {
        printf("I'm sleeping...\n");
    }
    
    void work()
    {
        printf("I'm working...\n");
    }
};

struct Girl : Human
{
private:
    int age;

public:
    void play()
    {
        printf("I'm girl, I'm playing...\n");
    }
    
    void print()
    {
        age = 22;
        
        printf("Girl's age is %d\n", age);
         
        play();
        sleep();
        work();
    }
};

struct Boy : Human
{
public:
    int age;
    
    void play()
    {
        printf("I'm boy, I'm playing...\n");
    }
    
    void print()
    {
        age = 23;
        
        printf("Boy's age is %d\n", age);
        
        play();
        sleep();
        work();
    }
};

/*
    1. struct 默认所有成员都是public。
    2. 类组成:成员变量,成员函数。
    3. 类权限:private,public,protected。
*/


int main(int argc, char *argv[])
{
    Girl girl;
    
    girl.print();

    Boy boy;
    
    boy.print();
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif





//7.1 struct表示类
#ifdef  LESSON7_1_struct_to_object
#include <stdio.h>

struct Biology  //生物类
{
    bool living;   //生命属性
};

struct Animal : Biology   //动物类,继承了生物类
{
    bool movable;      //属性
    void findFood()   //行为
    {
    }
};

struct Plant : Biology   //植物类,继承了生物类
{
    bool growable;
};

struct Beast : Animal   //禽兽类 ,继承了动物类
{
    void sleep()
    {
    }
};

struct Human : Animal   //人类 ,继承了动物类
{
    void sleep()
    {
        printf("I'm sleeping...\n");
    }
    
    void work()
    {
        printf("I'm working...\n");
    }
};

int main(int argc, char *argv[])
{
    Human human;
    
    human.living = true;
    human.sleep();
    human.work();
    
    printf("human.living = %d\n",human.living );   // 继承的属性都可以使用  
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif



//6.5 extern "C"{}:c方式编译主要是对函数名进行编译。函数体编译还是以C++进行编译
#ifdef LESSON6_example6_5_cplusplus_extern_c
#include <stdio.h>

extern "C"
{
    
    void func(int x)
    {
        const int i = 1;
        int& ri = const_cast<int&>(i);
        
        ri = 5;
        
        printf("i = %d\n", i);
        printf("ri = %d\n", ri);
    }

}

void func(const char* s)
{
    printf("%s\n", s);
}

int func(int a, int b)
{
    return a + b;
}

/*
    深入理解extern "C" {}
    1. extern "c"{} 告诉c++编译器对包含的代码进行c方式编译
    2. c方式编译主要是对函数名进行编译。2.1 c++编译出来: __Z4funcii, 2.2 c编译出来:_func
    3. 函数体编译还是以C++进行编译
    4. 比较g++ -S main.cpp -main.s(加上extern "C"), g++ -S main.cpp -main.cpp.s(去掉 extern "C")可以知道唯一不同的是函数名。
*/

int main()
{
    func(1);
    func("Delphi Tang");
    func(1, 2);
    
    getchar();
    return 0;
}


#endif


//6.4 类型大小:  
#ifdef LESSON6_example6_4_type_size
#include <stdio.h>

int main()
{
    printf("sizeof(\'1\') = %d\n", sizeof('1'));    //1:char
    printf("sizeof(2) = %d\n", sizeof(2));  //4:int
    printf("sizeof(3.0) = %d\n", sizeof(3.0));  //8:double
    
    char c = '1';
    short s = '1';
    int i = '1';
    long l = '1';
    long long ll = '1';
    
    c = 2;  //int赋值給char,无溢出,默认转换,若溢出,则截断。
    s = 2;
    i = 2;
    l = 2;
    ll = 2;
    
    float f = 0;
    double d = 0;
    
    f = 3.0;
    d = 3.0;
    
    getchar();
    return 0;
}

#endif



//6.3 函数重载: 本质上是不同的函数:__Z4funcic, __Z4funcii
#ifdef LESSON6_example6_3_func_overload
#include <stdio.h>

//c++编译出来: __Z4funcii
void func(int a, int b)
{
    printf("void func(int a, int b)\n");
}

//__Z4funcic
void func(int a, char b)
{
    printf("void func(int a, char b)\n");
}

//__Z4funcci
void func(char a, int b)
{
    printf("void func(char a, int b)\n");
}

//__Z4funccc
void func(char a, char b)
{
    printf("void func(char a, char b)\n");
}

/*
    函数重载注意事项:
    1. 本质上是不同的函数。
    2. c++编译出来: __Z4funcii
    3. c编译出来:_func
*/


int main()
{
    int a = 1;
    char b = '2';
    
    func(a, a);
    func(a, b);
    func(b, a);
    func(b, b);
    
    func(1, 2);
    func(1, '2');
    func('1', 2);
    func('1', '2');
    
    getchar();
    
    return 0;
}

#endif


//6.2 引用:别名,存储空间  
#ifdef LESSON6_example6_2_yinyong_storage_space
#include <stdio.h>

struct SV
{
    int x;
    int y;
    int z;
};

struct SR
{
    int& x;
    int& y;
    int& z;
};

/*
    引用注意事项:
     1. 引用定义时必须初始化
     2. 引用是变量的别名,与变量同生死。从此,引用的值是变量的值,地址是变量的地址。
     3. 引用在c++用常量指针表示的。int const *p; //指针地址不可以修改。 可以理解为内部处理的东西。
*/


int main()
{
    SV sv = {1, 2, 3};
    SR sr = {sv.x, sv.y, sv.z};
    
    printf("&sv = %p\n", &sv);
    printf("&sv.x = %p\n", &sv.x);
    printf("&sv.y = %p\n", &sv.y);
    printf("&sv.z = %p\n", &sv.z);
    
    printf("&sr = %p\n", &sr);  //有自己独立的空间
    printf("&sr.x = %p\n", &sr.x);  //是sv.x的引用(别名),故地址与&sv.x同
    printf("&sr.y = %p\n", &sr.y);
    printf("&sr.z = %p\n", &sr.z);
    
    SV& rsv = sv;
    
    rsv.x = 4;
    rsv.y = 5;
    rsv.z = 6;
    
    printf("sv.x = %d\n", sv.x);
    printf("sv.y = %d\n", sv.y);
    printf("sv.z = %d\n", sv.z);
    
    getchar();
    return 0;
}

#endif


//6.1 const:const注意事项
#ifdef LESSON6_example6_1_const
#include <stdio.h>

/*
    const注意事项
    1. 符号表为编译器内部过程的东西,不会进入程序存储空间。
    2. 用字面量初始化的const常量才会进入符号表。如:const int value = 1;//符号表。 const int value = x; //分配内存
    3. volatile修饰的const常量不会进入符号表,退化为只读变量。如volatile const value = 1;
    4. const 引用于初始化变量类型相同,初始化变量分配空间。如:const char c = 1, const char& rc = c; //为c分配空间
    5. const 引用于初始化变量类型不同,生成新的只读变量,独立空间。如:const char c = 1; const int& i = c;//新空间  
*/


int main()
{
    const int x = 1;    //常量,进入符号表
    const int& rx = x;  //为const常量取引用,导致为其分配空间。
    
    int& nrx  = const_cast<int&>(x);
    
    nrx = 5;
    
    printf("x = %d\n", x);  //1
    printf("rx = %d\n", rx);    //5
    printf("nrx = %d\n", nrx);  //5
    printf("x = %p\n", &x);
    printf("rx = %p\n", &rx);
    printf("nrx = %p\n", &nrx);

    volatile const int y = 2;   //valatile 修饰const,导致const常量不会进入符号表,退化为只读变量
    int* p = NULL;

    p = const_cast<int*>(&y);
    *p = 6;

    printf("y = %d\n", y);  //6
    printf("*p = %d\n", *p);    //6
    
    const int z = y;    //用变量赋值,会为其分配空间

    p = const_cast<int*>(&z);
    *p = 7;

    printf("y = %d\n", y);
    printf("z = %d\n", z);
    printf("*p = %d\n", *p);

    char c = 'c';
    char& rc = c;
    const int& trc = c; //const 引用与初始化变量类型不一样,会为其重新分配空间。
    
    rc = 'a';
    
    printf("c = %c\n", c);//a
    printf("rc = %c\n", rc);//a
    printf("trc = %c\n", trc);//c
    
    printf("&c = %p\n", &c);
    printf("&rc = %p\n", &rc);
    printf("&trc = %p\n", &trc);
        
    getchar();
    
    return 0;
}

#endif


//5.8 C++强制类型转换:reinterpret_cast指针之间强制类型转换
#ifdef  LESSON5_8_type_conversion_reinterpret_cast
#include <stdio.h>

int main()
{
    int i = 0;
    char c = 'c';
    int* pi = &i;
    char* pc = &c;
    
    printf("pc = %p\n", pc);
    printf("pi = %p\n", pi);
    
    //int类型指针转换为char类型指针
    printf("int* to char*\n");
    pc = reinterpret_cast<char*>(pi);
    printf("pc = %p\n", pc);
    printf("pi = %p\n", pi);
    
    //char类型指针转换为int类型指针
    printf("\nchar* to int*\n");
    pc = &c;
    pi = reinterpret_cast<int*>(&c);
    printf("pc = %p\n", pc);
    printf("pi = %p\n", pi);    
    
    //c = reinterpret_cast<char>(i); // Oops!
    
    pi = reinterpret_cast<int*>(0x12345678);    //不安全
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif

//5.7 C++强制类型转换:const_cast去除变量const属性
#ifdef LESSON5_7_type_conversion_const_cast
#include <stdio.h>

//xxx_cast<TYPE>(表达式)
#include <stdio.h>

int main()
{
    const int& j = 1;
    const int x = 2;
    
    //const_cast去除变量const属性
    int& k = const_cast<int&>(j);
    int& y = const_cast<int&>(x);
    
    k = 5;
    printf("k = %d\n", k);
    printf("j = %d\n", j);
    
    y = 8;
    printf("x = %d\n", x);
    printf("y = %d\n", y);
    printf("&x = %p\n", &x);
    printf("&y = %p\n", &y);
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}


#endif


//5.6 C++强制类型转换:基本数据类型之间转换,不能用于指针。
#ifdef LESSON5_6_type_conversion_static_cast
#include <stdio.h>

//xxx_cast<TYPE>(表达式)

int main()
{
    int i = 0x12345;
    float f = 3.456f;
    double d = 2.3412341;
    char c = 'c';
    int* pi = &i;
    char* pc = &c;
    
    //int类型转换为char类型
    c = static_cast<char>(i);
    printf("c = %x\n", c);

    c = static_cast<char>(f);
    printf("c = %x\n", c);
    
    c = static_cast<char>(d);
    printf("c = %x\n", c);
               
    //不能用于指针转换
    //pc = static_cast<char*>(pi);
    printf("pc = %p\n", pc);
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif



//5.5 强制类型转换: c语言可任意类型进行转换,简单灵活,但是过于粗暴
#ifdef LESSON5_5_type_conversion
#include <stdio.h>

typedef void(PF)(int);

struct Point
{
    int x;
    int y;
};

//c语言可以任意类型进行转换,简单灵活,但是过于粗暴,容易出问题。
//(TYPE)(表达式)或者 TYPE(表达式)
/*
    难以解决的bug思路:
    1. 运算符优先级:
    2. 多线程编程,各线程之间的交互
    3. 强制类型转换     
*/

int main()
{
    int v = 0x12345;
    PF* pf = (PF*)v;
    char c = char(v);
    
    Point* p = (Point*)v;
    
    printf("p->x = %d\n", p->x);
    printf("p->y = %d\n", p->y);
    
    //程序挂掉
    pf(v);
        
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//5.4 关键字:namespace 命名空间的使用。
#ifdef LESSON5_4_keyword_namespace
#include <stdio.h>
#include <stdio.h>

namespace First
{
    int i = 0;
}

namespace Second
{
    int i = 1;
    
    namespace Internal
    {
        struct P
        {
            int x;
            int y;
        };
    }
}
/*
    命名空间使用:
    1. 使用整个命名看空间:using namespace name;
    2. 使用命名空间的变量:using name::variable;
    3.使用默认命名看空间变量:::variable;
*/
int main()
{
    //使用命名空间
    using namespace First;
    using Second::Internal::P;
    
    printf("i = %d\n", i);
    i = 11;
    printf("i = %d\n", i);
    printf("i = %d\n", Second::i);
    
    P p = {2, 3};
    
    printf("p.x = %d\n", p.x);
    printf("p.y = %d\n", p.y);
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}


#endif


//5.3 关键字:namespace 命名空间解决标识符冲突问题。
#ifdef LESSON5_3_keyword_namespace
#include <stdio.h>

namespace First
{
    int i = 0;
}

namespace Second
{
    int i = 1;
    
    namespace Internal
    {
        struct P
        {
            int x;
            int y;
        };
    }
}

int main()
{
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif

//5.2 关键字:new delete 初始化
#ifdef LESSON5_2_keyword_new_delete_init
#include <stdio.h>

struct Student {
    char *name;
    int age;    
};

int main()
{
    int* pi = new int(1);
    float* pf = new float(2.0f);
    char* pc = new char('c');
    
    //分配空间时就进行初始化
    Student *s = new Student{"KUI", 25};
    
    printf("*pi = %d\n", *pi);
    printf("*pf = %f\n", *pf);
    printf("*pc = %c\n", *pc);
    printf("name = %s, age = %d\n", s->name, s->age);
    
    delete pi;
    delete pf;
    delete pc;
    delete s;
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//5.1 关键字:new delete 动态分配内存,与mallo有区别
#ifdef LESSON5_1_keyword_new_delete
#include <stdio.h>


/*
   关键字new 与malloc函数区别:
    1. 关键字new是c++的一部分,malloc函数是c库提供的函数
    2. new以类型为单元,malloc以字节为单元进行内存分配
    3. new申请类型变量可以进行初始化,malloc不可以。
*/

int main()
{
    //new一个对象,以类型为单元
    int* p = new int;
    
    *p = 5;
    *p = *p + 10;
    
    printf("p = %p\n", p);
    printf("*p = %d\n", *p);
    
    delete p;
    
    //申请数组内存单元
    p = new int[10];
    
    for(int i=0; i<10; i++)
    {
        p[i] = i + 1;
        
        printf("p[%d] = %d\n", i, p[i]);
    }
    
    //删除数组内存单元
    delete[] p;
    
    printf("Press any key to continue...");
    getchar();
    return 0;
}

#endif


//4.7 C++与C语言相互调用:c++编译器以c语言方式编译代码: extern "C" {}  
#ifdef  LESSON4_example4_1_1

#include <stdio.h>

//example4-1
/*
//add.h
int add(int a, int b);

//add.c
#include "add.h"

int add(int a, int b)
{
    return a + b;
}

//main.cpp
#include <stdio.h>

extern "C"
{
#include "add.h"
}


int main()
{
    printf("1 + 2 = %d\n", add(1, 2));
    
    return 0;
}
*/


//example4-2
/*
//add.h
int add(int a, int b);

//add.cpp

extern "C"
{

#include "add.h"

int add(int a, int b)
{
    return a + b;
}

}


//main.c
#include <stdio.h>

#include "add.h"


int main()
{
    printf("1 + 2 = %d\n", add(1, 2));
    
    return 0;
}
*/

int main(int argc, char *argv[])
{
    printf("cplusplus test\n");
    
    //example4-1
    //opem cmd
    //1. gcc -c add.c -o add.o
    //2. g++ main.cpp add.o
    //3. a.exe
    
    //example4-2
    //opem cmd
    //1. g++ -c add.c -o add.o
    //2. gcc main.cpp add.o
    //3. a.exe    
    
    
    getchar();
    return 0;    
}
 

#endif



//4.6 C++与C语言相互调用:c++编译器以c语言方式编译代码: extern "C" {}
#ifdef LESSON4_6_cplusplus_extern_c
#include <stdio.h>
#include <string.h>

//extern "C" {
//    //c语言方式编译        
//}

//若编译器为c++则使用c语言方式编译
#ifdef __cplusplus
extern "C" {
#endif

#ifdef __cplusplus
}
#endif



//C++ 内置宏定义
#ifdef __cplusplus
extern "C" {
#endif

int func(int a, int b)
{
    return a + b;
}

//c语言规则没有重载概念
#if 0
int func(const char* s)
{
    return strlen(s);
}
#endif

#ifdef __cplusplus
}
#endif

//C与C++并不对立,可以同时存在于同一个项目。就像C与汇编语言一样。
int main(int argc, char *argv[])
{
    int c = func(1, 2);
    printf("c = %d\n", c);
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif




//4.5 c++编译器以c语言方式编译代码: extern "C" {}
#ifdef LESSON4_5_cplusplus_extern_c
#include <stdio.h>
#include <string.h>

//extern "C" {
//    //c语言方式编译        
//}

//若编译器为c++则使用c语言方式编译
#ifdef __cplusplus
extern "C" {
#endif

int func(int x)
{
    return x;
}

//int func(int x, int y)
//{
//    return x;    
//}
#ifdef __cplusplus
}
#endif


int main(int argc, char *argv[])
{    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif

//4.4 函数重载:函数指针类型必须匹配
#ifdef LESSON4_4_func_overload_func_point
#include <stdio.h>
#include <string.h>

int func(int x) // int(int a)
{
    return x;
}

int func(int a, int b)
{
    return a + b;
}

int func(const char* s)
{
    return strlen(s);
}


typedef int(*PFUNC)(int a); // int(int a)

int main(int argc, char *argv[])
{
    int c = 0;
    //int (*p) int(a);  //直接定义函数指针
    //p = func;
    PFUNC p = func;  
    
    c = p(1);   //int func(int x)   //函数类型与重载的函数类型相同。
    printf("c = %d\n", c);
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif




//4.3 函数重载:重载+默认参数,有二义性不要同时使用
#ifdef LESSON4_3_func_overload_default_param
#include <stdio.h>
#include <string.h>

#if 0
int func(int a, int b, int c = 0)
{
    return a * b * c;
}
#else
int func(int a, int b)
{
    return a + b;
}
#endif
int main(int argc, char *argv[])
{
    int c = 0;
    
    c = func(1, 2); // 存在二义性,调用失败,编译不能通过
    
    printf("c = %d\n", c);
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif


#ifdef  LESSON4_2_func_overload
#include <stdio.h>
#include <string.h>

int func(int x)
{
    return x;
}

int func(int a, int b)
{
    return a + b;
}

int func(const char* s)
{
    return strlen(s);
}

int func(int a, const char* s)
{
    return a;
}

int func(const char* s, int a)
{
    return strlen(s);
}


/*
*   函数重载至少满足:1. 参数个数不同,2. 参数类型不同,参数顺序不同
*/

int main(int argc, char *argv[])
{
    int c = 0;
    
    c = func(1);
    printf("c = %d\n", c);
    
    c = func(1, 2);         
    printf("c = %d\n", c);
        
    c = func("ab");    
    printf("c = %d\n", c);
    
    c = func("ab", 1);
    printf("c = %d\n", c);

    c = func(1, "ab");
    printf("c = %d\n", c);
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif




//4.1 函数重载: 一个函数名搭配不同参数
#ifdef LESSON4_1_func_overload
#include <stdio.h>
#include <string.h>

int func(int x)
{
    return x;
}

int func(int a, int b)
{
    return a + b;
}

int func(const char* s)
{
    return strlen(s);
}


//一个函数名搭配不同参数,就用不同的实体。
int main(int argc, char *argv[])
{
    int c = 0;
    
    c = func(1);
    
    printf("c = %d\n", c);
    
    c = func(1, 2);
    
    printf("c = %d\n", c);
    
    c = func("12345");
    
    printf("c = %d\n", c);
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif

 //3.5 函数:占位+默认参数结合
#ifdef LESSON3_5_set_position
#include <stdio.h>

//占位参数不使用,用于兼容C语言,及拓展
int func(int a, int b, int = 0)
{
    return a + b;
}

int main(int argc, char *argv[])
{
    printf("func(1, 2, 3) = %d\n", func(1, 2));   //少一个参数也正常。
    printf("func(1, 2, 3) = %d\n", func(1, 2, 3));
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif



//3.4 函数:占位
#ifdef LESSON3_4_set_position
#include <stdio.h>

//占位参数不使用,用于兼容C语言,及拓展
int func(int a, int b, int)
{
    return a + b;
}

int main(int argc, char *argv[])
{
    //printf("func(1, 2, 3) = %d\n", func(1, 2));   //少一个参数将异常。
    printf("func(1, 2, 3) = %d\n", func(1, 2, 3));
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif






//3.3 函数参数:声明时指定默认参数
#ifdef LESSON3_3_func_default_param
#include <stdio.h>

//一旦指定默认参数后,后面所有参数都必须使用默认参数。
int add(int a, int b = 0, int c = 0, int d = 0)
{
    return a + b + c;
}

int main(int argc, char *argv[])
{
    printf("add(2) = %d\n", add(2));
    printf("add(1, 2) = %d\n", add(1, 2));
    printf("add(1, 2, 3) = %d\n", add(1, 2, 3));
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif



//3.3 函数参数:声明时指定默认参数
#ifdef LESSON3_2_func_default_param
#include <stdio.h>

//声明时指定默认参数
int mul(int x = 1);

int main(int argc, char *argv[])
{
    printf("mul(2) = %d\n", mul(2));
    printf("mul(-2) = %d\n", mul(-2));
    printf("mul() = %d\n", mul());
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

//定义时不再指定
int mul(int x)
{
    return x * x;
}

#endif


//3.2 内联函数:不一定申请成功
#ifdef LESSON3_example3_1
#include <stdio.h>

//加上 __attribute__((always_inline))则一直内联。该编译器为c++特有的,为了兼容性,最好不要使用。
inline int f_inline(int a, int b) __attribute__((always_inline));                                    
int g_no_inline(int a, int b);

//预处理+编译:compilation:        g++ -S main.cpp -o main.s  //c代码变为汇编代码: 查看是否用函数调用。
 
/*
*   注意:内联函数体应该短小,类似中断。过大的话则失去设计的意义。
*/
int main(int argc, char *argv[])
{
    int r1 = f_inline(1, 2);    //内联实现机制与const类似。都是进入符号表
    int r2 = g_no_inline(1, 2);
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

int f_inline(int a, int b)
{
    return a < b ? a : b;
}

int g_no_inline(int a, int b)
{
    return a < b ? a : b;
}

#endif





//3.1 内联函数:比函数少开销,比宏安全。
#ifdef  LESSON3_1_inline_micro
#include <stdio.h>

#define FUNC(a, b) ((a) < (b) ? (a) : (b))

int func(int a, int b)
{
    return a < b ? a : b;   
}

//添加环境变量:C:\Program Files (x86)\Dev-Cpp\MinGW32\bin
//预处理:prepressing:             armcpp/g++ -E main.cpp -o main.i  //只是替换:1.#define 删除,展开宏, 2. 处理条件预编译指令#if #ifdef,3.删除注释
//预处理+编译:compilation:        armcpp/g++ -S main.cpp -o main.s  //c代码变为汇编代码: 1.词法分析,语法分析。
//预处理+编译+汇编:assembly:      armcpp/g++ -c mian.cpp -o main.o  //c代码变为目标文件.o(二进制) :1.把汇编指令翻译为机器指令。
//预处理+编译+汇编+链接:linking:  armcpp/g++ main.cpp -o main       //c文件变为可执行文件(二进制) :1.链接库文件。
int main(int argc, char *argv[])
{
    int a = 1;
    int b = 3;
    int c = func(++a, b);   //内联函数:参数,返回值检查(且无副作用),完全可以代替 宏定义
    
    printf("inline:\n");
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    printf("c = %d\n", c);
    
    a = 1;
    b = 3;
    c = FUNC(++a, b);
    
    printf("micro:\n");
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    printf("c = %d\n", c);    
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif



//2.9 引用:引用作为返回值,需要考虑作用域
#ifdef LESSON2_example2_1
#include <stdio.h>

int& f()
{
    static int a = 0;
    
    return a;
}

int& g()
{
    int a = 1;
    
    //变量内存已经被销毁了,故通过内存擦操作则会异常
    return a;
}

int main()
{
    int a = g();
    int& b = g();//返回a的引用,but 已释放的 a 可以再被引用
    
    f() = 10;//静态变量的引用 可以作为 左值,右值
    
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    printf("f() = %d\n", f());
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}
#endif


//2.8 引用: 引用等效于常指针  int* const a;
#ifdef LESSON2_8_yinyong_storage_space
#include <stdio.h>

//举例:等效,为了实用性,c++内部屏蔽掉
//void func(int &a)         // void func(int * const a)     //地址不能修改,变量值可以修改
//{                             //{
//    a = 5;                        //    *a = 5;
//}                             //}

struct TRef
{
    int& a; //引用int &a等效与常指针 int* const a;
    int& b;
};

int main(int argc, char *argv[])
{
    //char &a,char &b效果大小还是8
    printf("sizeof(TRef) = %d\n", sizeof(TRef));   //8, 引用等效于常指针,故大小与指针相同
    
    
    int a = 1;
    int b = 2;
    int c = 3;
    TRef rA = {a, b};
    
    printf("&a = %08X\n", &a);
    printf("&b = %08X\n", &b);
    printf("&rA = %08X\n", &rA);
    printf("sizeof(TRef) = %d\n", sizeof(TRef));    //32bit系统中,8

                     
    printf("a = %d\n", a );
            
    rA.a = 10;                 
    printf("&rA.a = %p\n", &rA.a );   
    printf("a = %d\n", a );   //a 的值被修改了
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif


//2.7 引用:const结合, const 声明引用=数值
#ifdef LESSON2_7_yinyong_const

#include <stdio.h>

int main(int argc, char *argv[])
{
    const int &b = 1;   //情况二: const 声明引用=数值, 编译器为其分配内存空间,作为只读变量,int &b = 1;编译不通过,不能这么用
    int* p = (int*)&b;

    //b = 5;

    *p = 5;     //只读变量通过修改地址可以修改内容

    printf("b = %d\n", b);

    printf("Press enter to continue ...");
    getchar();      

}

#endif


 //2.6 引用:const结合, const 声明引用=变量
#ifdef LESSON2_6_yinyong_const

#include <stdio.h>

int main(int argc, char *argv[])
{
    int a = 4;
    const int &b = a;     //情况一: const 声明引用=变量 , 给变量加上只读属性(操作引用时)
    int* p = (int*)&b;  //若不去除const属性 则修改不了
    
    
    //b = 5; //给普通变量加上只读属性。 错误警告
    
    *p = 5;    //通过地址修改可以改变 ,等效==> //*((int*)&b) = 5;
    //*((int*)&b) = 5;
    
    printf("a = %d, b = %d\n", a, b);    //5, 5
    printf("&a = %p, &b = %p\n", &a, &b); //地址相同
    
    printf("Press enter to continue ...");
    getchar();  
    return 0;
}

#endif

//2.5 引用:代替指针:更好的可读性,实用性
#ifdef LESSON2_5_yinyong
#include <stdio.h>

//void swap(int *a, int *b)
//{
//    int t;
//    t = *a;
//    *a = *b;
//    *b = t;
//}
void swap(int& a, int& b)
{
    int t = a;
    a = b;
    b = t;
}

int main(int argc, char *argv[])
{
    int a = 4;
    int b = 5;
    
    //注意引用变量的生命周期,即作用域
    swap(a, b);   //引用 某种程度可以代替指针 ,相对于 swap(&a, &b)可读性好很多
    
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif


//2.4 引用:变量的别名
#ifdef LESSON2_4_yinyong
#include <stdio.h>

int main(int argc, char *argv[])
{
    int a = 4;
    int& b = a; // 普通引用定义时必须初始化,作为形参就不需要
                //引用就是取别名 ,就是原有变量的另一个名称,与该变量有相同的值,相同的地址。  eg: 陈腾奎,KUI
    
    b = 5;
    
    printf("a = %d\n", a);
    printf("b = %d\n", b);
    printf("&a = %08X\n", &a);
    printf("&b = %08X\n", &b);
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif


//2.3 三目运算符:返回值可以作为左值
#ifdef LESSON2_3_three_eyes
#include <stdio.h>

int main(int argc, char *argv[])
{
    int a = 1;
    int b = 2;
                            //C语言:三目运算符不能做左值
    (a < b ? a : b) = 3;    //C++:三目运算符可以做左值, 三目运算符?:返回都是变量可以做左值,返回数值则不可以
    
    printf("a = %d, b = %d\n", a, b);  //(返回的是引用 &)
    
    printf("Press enter to continue ...");
    getchar();    

}

#endif


//2.1 布尔类型:true:非0, false:0,真正的
#ifdef LESSON2_1_bool
#include <stdio.h>

int main(int argc, char *argv[])
{
    int a;
    bool b = true;    //布尔只有 假 false = 0 , 真: true = 非 0 占用一个bit (没优化则占用一个byte,优化可能只占用一个bit,这个取决于编译器)


    printf("true = %d, false = %d\n", true, false);  // true=1, false=0        
    printf("b = %d, sizeof(b) = %d\n", b, sizeof(b));  //b = 1, sizeof(b) = 1大小为一个字节

    b = 3; // -5,  
    a = b;    
    printf("a = %d, b = %d\n", a, b);        //a = 1, b = 1
    
    a = 10;
    b = a;
    printf("a = %d, b = %d\n", a, b);        //a = 10, b = 1
    
      
    b = 0;
    printf("b = %d\n", b);
    
    b = false;
    printf("b = %d\n", b);   
    
    b++;    //可以++, 不能--
    printf("b = %d\n", b);           // b = 1
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif



//1.8 const:宏:作用域
#ifdef  LESSON1_8_example1_2_const_micro
#include <stdio.h>

void f()
{
    #define a 3
    const int b = 4;
    //#undef a  //作用域解除
}

void g()
{
    printf("a = %d\n", a);
    //printf("b = %d\n", b);
}

int main(int argc, char *argv[])
{
    f();
    g();
    
    printf("Press enter to continue ...");
    getchar();
    
    return 0;
}
#endif

//1.7 const:与宏的区别:const常量编译阶段处理的,可以作为数组参数,变量是运行时才确定的,不可以作为数组参数。        
#ifdef LESSON1_7_example1_1_const_array    
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
    //#define a 1 //等效,预编译阶段处理的
    const int a = 1;    //该常量与宏定义类似,但是又不同,有自己的作用域,还有数据类型
    const int b = 2;    //数组_常量 预编译是 可以通过 ,c语言是变量,错误了
    
    //b = 10;
    //const常量编译阶段处理的,故常量(符号表获取)作为数组参数是没问题的,若用变量作用数组元素,编译阶段出问题了。(因为变量是在运行阶段才知道值的)。
    char array[a + b] = {0};
    int i = 0;
    
    memset(array, 0xaa, sizeof(array));
    for(i=0; i<(a+b); i++)
    {
        printf("array[%d] = 0x%x\n", i, array[i] & 0xff);
    }
    
    printf("Press enter to continue ...");
    getchar();
    
    return 0;
}

#endif



//1.6 函数:C++要有确定的参数,确定的返回值
#ifdef LESSON1_6_func_param_return
#include <stdio.h>

//f(i)    //  c ++函数必须的指明类型名 ,c语言不指定默认为int
void f(int i)
{
    printf("i = %d\n", i);
}

//g()   //默认类型为void
int g(void)
{
    return 5;
}

int main(int argc, char *argv[])
{
    printf("Begin...\n");
    
    f(10);
    
    printf("g() = %d\n", g());
    
    printf("End...\n");
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif
 
//1.5 结构体:是新类型,不需要加上struct,直接:结构体名 变量名
#ifdef LESSON1_5_struct_new_type
#include <stdio.h>

struct Student
{
    const char* name;
    int age;
};

int main(int argc, char *argv[])
{
    //新类型定义变量
    Student s1 = {"Delphi", 30};
    Student s2 = {"Tang", 30};
    
    Student KUI = {"KUI", 23};
    printf(" name: %s\n age = %d\n",KUI.name ,KUI.age );  //结构体变量 ‘. ’   指针 ' -> '     
    
    printf("Press enter to continue ...");
    getchar();
    
    return 0;
}

#endif
 
//1.4 const :真正的常量,编译器让其进入符号表,故不为该只读变量分配内存。
#ifdef LESSON1_4_const
#include <stdio.h>

/*
*   c语言const属性
*   把类型int去掉,若const修饰p,则p不可变。若const修饰*p,则*p不可变
*/
//const int *p; //const 修饰*p,p 是指针, *p 是指针指向的对象,不可变
//int const *p; //const 修饰*p,p 是指针, *p 是指针指向的对象,不可变
//int *const p; //const 修饰 p, p 不可变, p 指向的对象可变
//const int *const p; //前一个 const 修饰*p,后一个 const 修饰 p,指针 p 和 p 指向的对象都不可变
 

int main(int argc, char *argv[])
{
    const int c = 2;
    int* p = (int*)&c;
    int array[c];
    
    printf("Begin...\n");
    
    *p = 5; //怎么修改都没有用
    //c = 3;  //c++  const为常量 :不能修改 but c语言可以修改
    printf("c = %d\n", c);  //0, 直接从符号表里取出 //若发现遇到extern,或&取址符号,则分配相应内存,但是c常量还是无法赋值。  
    printf("*p = %d\n", *p); //5, 操作的是变量的内存空间
    
    printf("End...\n");
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif
 
 
 
//1.3 全局变量:不能重复定义,拒绝二义性。
#ifdef LESSON1_3_global_variable
#include <stdio.h>

//int g_var;    //重复定义,而c语言不会提示该错误。
                //全局变量重复定义  c++不支持,but c语言可以    非这样不可 得用extern int g_var;
                
extern int g_var;  
int g_var = 1;

int main(int argc, char *argv[])
{
    printf("Begin...\n");
    
    printf("g_var = %d\n", g_var);
    
    printf("End...\n");
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif
 

//1.2 register寄存器:register变量可以取址,C++编译器自动优化退化为普通变量。
#ifdef LESSON1_2_register
#include <stdio.h>

int main(int argc, char *argv[])
{
    //C语言:变量属性:register,auto,static
    register int c = 0;
    register int r = 1;
    
    printf("Begin...\n");
    
    printf("&c = %08X\n", &c);  //寄存器变量有地址了,表明并没有存储在寄存器而是内存。
                                //register变量可以取址  (自动优化:退化为普通变量) ,C++有自动优化功能,于是register没什么用了,只是为了兼容C
    
    printf("End...\n");
    
    printf("Press enter to continue ...");
    getchar();    
    return 0;
}

#endif



//1.1 变量初始化:用到时再定义,如for定义的变量,作用域只在for循环体内。
#ifdef LESSON1_1_variable_init

#include <stdio.h>

/*
*   完全兼容c语言
*/

int main(int argc, char *argv[])
{
    int c = 0;
    
    for(int i=0; i<10; i++)    //c++ 用到再定义  c语言不可以
    {
        for(int j=0; j<10; j++)
        {
            c += i * j;
        }
        
        //printf("j = %d\n", j);       //作用域只在for循环
    }  

    printf("Press enter to continue ...");
    getchar();    //暂停,获取一个字符
    return 0;
}


#endif





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值