C++记录学习

97 阅读18分钟


#include <jni.h>
#include <string>
#include <iostream>
#include <ctime>
#include <fstream>

#include <android/log.h>
#include <vector>
#include <algorithm>

#define TAG "fct"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__);

typedef int i;
using namespace std;

void 给变量起别名();

void 参数传递();

void swap_1(int a, int b);

void swap_2(int *a, int *b);

void swap_3(int &a, int &b);

int &函数的调用可以作为左值();

int &函数的调用可以作为左值();

void 修饰形参_防止误操作(int &a);


extern "C" JNIEXPORT jstring JNICALL
Java_com_android_jnitest_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    string hello = "Hello from C++";
    std::cout << "asdasd" << endl;
//    给变量起别名();
//    参数传递();
    return env->NewStringUTF(hello.c_str());
}

extern "C" JNIEXPORT jint JNICALL
Java_com_android_jnitest_MainActivity_switchNum(
        JNIEnv *env,
        jobject /* this */) {
    string hello = "Hello from C++";
    cout << "asdasd" << endl;

    return 1;
}

/**
 * 引用
 * 给变量起别名:
 * 数据类型 &别名=原变量名
 */
void 给变量起别名() {
    int a = 10;
    int &b = a;
    b = 20;
    LOGD("a=%d", a)
    LOGD("b=%d", b)
}

/**
 * 参数传递
 * 1:值传递
 * 2:地址传递
 * 3:引用传递
 */
void 参数传递() {
    int a = 10;
    int b = 20;
    swap_1(a, b);//不能改变 a,b值
    swap_2(&a, &b);//能改变 a,b值
    swap_3(a, b);//能改变a,b值(相当于传递的别名)
}

//值传递
void swap_1(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

//地址传递
void swap_2(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

//引用传递
void swap_3(int &a, int &b) {
    int temp = a;
    a = b;
    b = temp;
}

/**
 * 引用做函数的返回值
 * 1、不要返回局部变量的引用
 * 2、函数的调用可以作为左值
 */
void 引用做函数的返回值() {
    int &ref = 函数的调用可以作为左值();
    函数的调用可以作为左值() = 100;
    LOGD("ref=%d", ref);//ref已经被改变。
}

//int &不要返回局部变量的引用() {
//    //局部变量存放在内存模型的栈区,方法执行完会被释放,
//    // 无法保证返回的a,后面还能被访问到
//    //解决方法加static进行修饰,变成全局区的
//
//    int a = 10;
//    return a;
//}

//如果函数的返回值是引用,这个函数可以作为左值
int &函数的调用可以作为左值() {
    static int a = 10;
    return a;
}

void 修饰形参_防止误操作(const int &a);
/**
 * 常量引用
 */
//使用场景:修饰形参,防止误操作
void 常量引用() {
    const int &ref = 10;
    //ref = 20; 不可修改了

    int a = 100;
    const int &b = a;
    修饰形参_防止误操作(b);
}

void 修饰形参_防止误操作(const int &a) {
    //a = 100;形参不可修改了
}

/**
 * 函数提高,
 * 函数的默认参数
 * *注意:
 * 1、如果某个位置设置了默认参数,那后面都要设置默认参数,不然报错
 * 2、如果函数的声明有默认函数,函数实现就不能有默认参数
 */
int 函数的默认参数(int a, int b = 20, i c = 30) {
    return a + b + c;
}

//申明
int 如果函数的声明有默认函数_函数实现就不能有默认参数(int a = 10, int b = 20);

//实现
int 如果函数的声明有默认函数_函数实现就不能有默认参数(int a, int b) {
    return a + b;
}

/**
 * 函数占位参数
 * 语法:返回值类型 函数名 (数据类型){}
 * 占位参数可以有默认参数 int=10
 */
int 函数占位参数(int a, int) {
    return 1;
}

/**
 * 函数重载
 * 满足条件:
 * 1、同一个作用域下
 * 2、函数名称相同
 * 3、函数类型不同 或者个数不同 、顺序不同
 */
void 函数重载() {}

void 函数重载(int a) {}

void 函数重载(string a) {}

void 函数重载(int a, string b) {}

void 函数重载(string b, int a) {}

/**
* 类和对象
 * 封装 继承 多态
*/
class Car {
    //访问权限
public:
    //属性
    int price;
    string mark;

    void print() {
        LOGD("价格——品牌:%d%s", price, mark.c_str());

    }
};

void useCar() {
    Car car;//car后面不能加小括号,不然就是函数申明了;
    car.price = 1800000;
    car.mark = "大众";
    car.print();

}

/**
* struct和class的区别(差不多,都能用)
 * 1、struct默认权限为公共
 * 2、class默认权限为私有
*/
class A1 {
    string name;//默认权限 是私有

public:
    string getName() {
        return name;
    }

    void setName(string name) {
        this->name = name;
    }
};

struct A2 {
    int name;//默认权限 是公共
};

void structclass的区别() {
    A1 a1;
//    a1.name = 100;//报错
    a1.setName("fct");

    A2 a2;
    a2.name = 100;

    A2 *a = new A2();
    a->name = 100;
}

/**
* 构造函数和析构函数
 * 编译器默认实现了这两个函数的空实现
*
*/
class Car2 {

public:
    //构造函数 :对象初始化,可以有参数,创建对象时自动调用
    Car2() {
        price = 1;
        name = "pass";
    }

    //析构函数: 对象清理,不能有参数。对象销毁时,自动调用
    ~Car2() {
        price = 0;
        name = "";
    }

    int price;
    string name;
};

void 构造函数和析构函数() {
    Car2 car2;
}

/**
* 构造和析构函数的分类以及调用
 * 默认构造函数
 * 有参构造函数
 * 拷贝构造函数
*/
class Car3 {

public:
    //构造函数 :对象初始化,可以有参数,创建对象时自动调用
    /**
     * 默认构造函数
     */
    Car3() {
        price = 1;
        name = "pass";
    }

    /**
    * 有参构造函数
    */
    Car3(int p) {
        price = p;
        name = "pass";
    }

    /**
    * 拷贝构造函数
    */
    Car3(const Car3 &car) {
        price = car.price;
    }


    //析构函数: 对象清理,不能有参数。对象销毁时,自动调用
    ~Car3() {
        price = 0;
        name = "";
    }

    int price;
    string name;
};

void 构造和析构函数的分类以及调用() {
    //1:括号法
    Car3 car3(10);
    Car3 car33(car3);
    //显示法
    Car3 car31 = Car3(10);
    //隐式转换法
    Car3 car32 = 10;//相当于 Car3 car31 = Car3(10);
}

/**
* 拷贝构造函数调用时机
* C++中拷贝构造函数调用时机通常有三种情况:
* 1、使用一个已经创建完毕的对象来初始化一个新对象。
* 2、值传递的方式给函数套数传值。
* 3、以值方式返回局部对象
*/
class Person {
public:
    Person() {
        LOGD("%s", "构造函数")
    }

    //有参构造函数
    Person(int age) {
        this->age = age;
        LOGD("%s", "有参构造函数")
    }

    //拷贝构造函数
    Person(const Person &person) {
        age = person.age;
        LOGD("%s", "拷贝构造函数")
    }

    //析构函数
    ~Person() {
        LOGD("%s", "析构函数")
    }

    int age;
};

void 值传递的方式给函数套数传值(Person p);

Person 值传递的方式给函数套数传值();

void 拷贝构造函数调用时机() {
    //1:使用一个已经创建完毕的对象来初始化一个新对象。
    Person p1(10);
    Person p2(p1);

    //2:值传递的方式给函数套数传值
    //此时拷贝构造函数也会被调用,因为作为形参,会被复制一个新临时副本
    值传递的方式给函数套数传值(p2);

    //3:以值方式返回局部对象
    Person p3 = 值传递的方式给函数套数传值();
}

void 值传递的方式给函数套数传值(Person p) {

}

Person 值传递的方式给函数套数传值() {
    Person p;
    return p;//此时不会直接返回p,而是拷贝一个新的副本,再返回出去
}

/**
 * 构造函数的传递规则
 * 如果自己实现了有参构造函数,编译器就不会默认提供默认构造函数;
 * 如果自己实现了拷贝构造函数,编译器就不会默认提供 默认和有参构造函数。
 */


/**
 * 深拷贝和浅拷贝
 * 浅拷贝:简单的复制操作,编译默认实现的拷贝构造函数就是浅拷贝
 * 深拷贝:在堆区重新申请空间,进行拷贝操作
 *
 * 总结:如果属性有堆区开辟内存的,一定要自己实现拷贝构造函数,防止浅拷贝带来的问题。
 */

class Animal {
public:
    Animal() {

    }

    Animal(int age, int size) {
        this->age = age;
        this->size = new int(size);
    }

    //拷贝构造函数
    Animal(const Animal &animal) {
        age = animal.age;//浅拷贝
        size = new int(*animal.size);//深拷贝
    }

    //析构函数通常是用来,释放内存,
    // 比如当前属性有指针变量时,需要手动释放堆区内存
    //但是往往也会造成重复释放 size属性内存区域,
    //比如 Animal a1(1,10);
    //            Animal a1(1,10);
    //            Animal a2(a1);
    //以上两句代码就会造成浅拷贝时,重复执行析构函数,重复释放(delete) 堆区内存的问题
    //因为a2,先执行析构 释放了,a1再执行,已经没了。
    //所以引申出了,深拷贝  每次都重新申请一个堆区内存,于是再释放的时候,就是释放不同的内存区域
    ~Animal() {
        if (size != NULL) {
            delete size;


        }
    }

public:
    int age;
    int *size;
};

/**
* 初始化列表
 *
 * 初始化属性(之前是用构造函数)
 *
 * 语法: 构造函数():属性值1(值1),属性值2(值2)....{}
*/
class Food {
public:
    //等于默认赋值了
    Food() : a(10), b(20), c(30) {

    }

    //不想默认赋值的时候,可以采用以下方式
    Food(int _a, int _b, int _c) : a(_a), b(_b), c(_c) {

    }

public:
    int a;
    int b;
    int c;
};

/**
 * 类对象作为类成员
 *
 * 其中涉及到的知识点:
 * 当前类和类成员构造函数和析构函数分别哪个现在执行、
 * 构造函数: 类成员-当前类
 * 析构函数:当前类-类成员
 */
class Bed {
public:
    Bed(int size) : size(size) {}

public:
    int size;
};

class Room {
public:
    //此处虽然参数是int size,但是使用 初始化列表进行设置属性值,没有报错
    //是因为下面的代码 bed(size)相当于 Bed bed=size;(隐式转换法)
    Room(float area, int size) : area(area), bed(size) {}

public:
    float area;
    Bed bed;
};


/**
 * 静态成员
 * 静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
 * 静态成员分为:
 * 静态成员变量
 * 静态成员函数
 */

class Fruit {
public:
    //所有对象都共享同一份数据
    //编译阶段就分配内存
    //类内声明,类外初始化
    static int kind;//静态成员变量
    string name;

    //所有对象共享一个函数
    //静态成员函数只能访问静态成员变量
    static void getFruit() {//静态成员函数
        kind = 2;
//        name = "apple";//报错
    }
};

//类内声明,类外初始化
int Fruit::kind = 0;

void 访问静态成员变量() {
    //因为静态成员变量不属于某个对象,所有对象都共享一份数据
    //因此静态成员变量有两种访问方式
    //1:通过对象进行访问
    Fruit fruit;
    fruit.kind = 1;
    //2:通过类名进行访问(:: 表示 作用域 下)
    Fruit::kind = 2;
};

/**
* this指针
 *
 * 它是一个指针
*/
class Cup {
public:
    Cup() {}

    //参数名和属性名字一样得时候,用this赋值
    Cup(int type) {
        this->type = type;
    }

    //用来返回当前对象
    Cup factory() {
        return *this;
    }

public:
    int type;
};


/**
* 空指针访问成员函数
*/
class NBA {
public:
    NBA() {}

    void showNBA() {
        LOGD("%s", "我是NBA");
    }

    void showTeam() {
//        if (this == NULL) {
//            return;
//        }
//        LOGD("%s", name.c_str());
    }

    string name;
};

void 空指针访问成员函数() {
    /**
     *
     * 创建一个NBA类型得指针,并且设为空。(空指针)
     */
    NBA *nba = NULL;
    /**
     * 不会报空指针
     */
    nba->showNBA();
    /**
     * 会报this 空指针得错误。因为成员函数在类内调用当前类属性得时候,
     * 会默认加上this指针。但是传入得指针是空。
     * 解决方法:
     * if(this==NULL){
     * return;
     * }
     *
     */
    nba->showTeam();

}

/**
* 常函数
* 常对象
*/

class Apple {
public:
    Apple() {}

public:
    int price;
    mutable int size;

    /**
     * 常函数
     * this的本质是 指针常量(Apple *const this;) 指针的指向不能修改。
     * 如果想要指针指向的值也不能修改 就再加上const。( const Apple *const this;)
     * 所以常函数的本质就是:const Apple *const this
     * 但是如果有特殊属性需要去修改,那就加上 mutable 关键字 去修饰变量
     */
    void setPrice() const {
//        this->price = 1;//报错,不能修改
        this->size = 2;
    }

    void show() {

    }
};

void 常对象() {
    const Apple apple;//在对象前加const,变成常对象
//    apple.price = 1;//会报错,和上面是一个原因
    apple.size = 1;//不报错,因为加了mutable
    //常对象只能调用常函数
    apple.setPrice();
//    apple.show();//会报错,不能调用普通成员函数,因为普通成员函数可以修改属性
};

/**
* 友元
 * 用来让函数或者类可以访问对象的私有属性
 * 全局函数做友元
 * 类做友元
 * 成员函数做友元
*/

class Orange {
    //表示 全局函数(全局函数做为友元)可以访问当前类的私有属性
    friend void 全局函数做友元();

public:
    string name;
private:
    int price;
};

//全局函数做为友元
void 全局函数做友元() {
    Orange orange;
    orange.name = "橘子";
    orange.price = 1;
}

//类做友元
class Employee;//提前声明,但是没定义,告诉编译我等会在定义,别给我报错提示
class Boss {

public:
    Boss();//提前声明

    void askSalary();//提前声明,等会可以放在类外进行实现

public:
    Employee *employee;
};

class Boss2 {
public:
    Boss2();

    void 成员函数做友元();

public:
    Employee *employee;
};

class Employee {
    friend class Boss;

    friend void Boss2::成员函数做友元();

public:
    Employee();//提前声明,等会可以放在类外进行实现,使用 :: 作用域就行

public:
    string name;
private:
    int salary;
};

Employee::Employee() {
    name = "fct";
    salary = 1800;
}

Boss::Boss() {
    employee = new Employee;
};

void Boss::askSalary() {
    employee->name = "asd";
    employee->salary = 1900;
}

Boss2::Boss2() {
    employee = new Employee;
}

void Boss2::成员函数做友元() {
    employee->name = "asd";
    employee->salary = 1900;
}

void 类做友元() {
    Boss boss;
    boss.askSalary();
}


/**
 * 运算符重载:
 * 1、成员函数实现重载
 * 2、全局函数实现重载
 */
class Rice {
public:
    int a;

    //成员函数实现重载
//    Rice operator+(Rice &rice) {
//        Rice temp;
//        temp.a = this->a + rice.a;
//        return temp;
//    }
};

//全局函数实现重载
Rice operator+(Rice &rice1, Rice &rice2) {
    Rice temp;
    temp.a = rice1.a + rice2.a;
    return temp;
}

Rice operator+(Rice &rice1, int a) {
    Rice temp;
    temp.a = rice1.a + a;
    return temp;
}

void 运算符重载() {
    Rice rice1;
    Rice rice2;
    Rice rice = rice1 + rice2;
    Rice rice_ = rice1 + 10;
}

/**
 * 继承
 * class 子类 :继承方式 父类
 * 继承方式:
 * 公共继承 public
 * 保护继承 protected
 * 私有继承 private
 */
class AsiaAnima {
public:
    string type;
    string name;

};

class Cat : public AsiaAnima {


};

void setCatName() {
    Cat cat;
    cat.name = "aa";
};

/**
 * 继承中 父类和子类出现同名函数和同名属性如何调用
 * 如果是静态成员 处理方式也一样
 */
class Base {
public:
    Base() {
        m_A = 100;
    }

public:
    int m_A;
    static string m_B;
public:
    void func() {

    }

    static void func2() {}
};

class Son : public Base {
public:
    Son() {
        m_A = 100;
    }

public:
    int m_A;
    static string m_B;
public:
    void func() {

    }

    static void func2() {}
};


void 父类和子类出现同名函数和同名属性如何调用() {
    Son son;
    son.m_A = 1000;
    son.Base::m_A = 1000;
    son.func();
    son.Base::func();

    son.m_B = "1";
    son.Base::m_B = "1";
    //或者通过类名得方式访问静态成员
    Son::m_B = "1";
    Base::m_B = "1";
    Son::Base::m_B = "1";

    son.func2();
    son.Base::func2();
    Son::func2();
    Base::func2();
    Son::Base::func2();
}


/**
* 多继承
 * class 子类 :继承方式 父类1,继承方式 父类1。。。。
*/
class Base1 {
};

class Base2 {
};

class SonMul : public Base1, public Base2 {

};

/**
* 菱形继承
 * 菱形继承概念:
 * 两个派生类继承同一个基类
 * 又有某个类同时继承者两个派生类
 * 这种继承被称为萎形继承,或者钻石继承
*/

class Animal_ {
public:
    int m_Age;
};

class Yang : virtual public Animal {
};

class Tuo : virtual public Animal {
};

class YangTuo : public Yang, public Tuo {
};

void 菱形继承() {
    /**
     * 二义性问题
     * 可以通过作用域的放方式去解决
     */
    YangTuo yangTuo;
//    yangTuo.age=18;会报错
    yangTuo.Yang::age = 18;
    yangTuo.Tuo::age = 20;

    /**
     * 两份数据选用哪个呢?age到底18还是20?
     * 实际我们只要一份就行了。不用两份浪费资源
     *
     * 可以利用虚继承 解决菱形继承的问题
     * 使用关键字 virtual  虚继承
     * 使用了virtual,会把m_age变成一份
     */
    yangTuo.age = 18;//不会报错了
    yangTuo.Yang::age = 18;
    yangTuo.Tuo::age = 20;
    //最后age的值会是 20。
}

/**
* 多态
* 多态分为两类
* 静态多态:
* 函数重载和 运算符重载属于静态多态,复用函数名
* 动态多态:
* 派生类和虚函数实现运行时多态
* 静态多态和动态多态区别:
* 静态多态的函数地址早绑定 - 编译阶段确定函数地址
* 动态多态的函数地址晚绑定 - 运行阶段确定函数地址
*/

class DongWu {
public:
    virtual void speak() {
        cout << "动物说话" << endl;
    }
};

class Mao : public DongWu {
public:
    void speak() {
        cout << "猫说话" << endl;
    }
};

/**
 * @param dongWu
 *
 * 此时传入mao对象时,打印的是“动物说话”
 * 给基类DongWu的speak方法加上关键字virtual 变成虚函数。
 * 便可以实现动态多态,打印出来的内容也会变成 “猫说话”
 *
 * 动态多态满足条件:
 * 1、必须有继承关系
 * 2、子类重写父类的虚函数
 *
 * 动态多态的使用:
 * 父类的指针或者引用 指向子类对象,如下方法
 */
void doSpeak(DongWu *dongWu) {
    dongWu->speak();
}

void 静态多态_动态多态() {
    Mao mao;
    doSpeak(&mao);
}

/**
* 纯虚函数和抽象类
*/

/**
 * 如果一个类中含有一个纯虚函数,当前类就是抽象类
 * 抽象类不能实列化对象
 * 子类必须重写纯虚函数
 */
class Season {
public:
    //纯虚函数
    virtual void name() = 0;
};

class Spring : public Season {
public:
    void name() {
        cout << "春天" << endl;
    }
};

/**
 * c++ 11 新特性
 */
//变量类型推断
auto namea(10);
//表达式定义 变量类型
decltype(10 + 1) be;

void 纯虚函数和抽象类() {
    int a = namea + be;
    LOGD("%d", sizeof(a));

    Spring *spring = new Spring;
    spring->name();
}


/**
 * 文件读写
 */
void dealfile() {

//    ofstream ofs;
//    ofs.open("文件路径", ios::binary | ios::out);
//
//    ifstream ifs;
//    ifs.open("文件路径", ios::binary | ios::out);
}

//======================进阶 泛型编程==========================
/**
* 模板
 *  template<typename  T>
 *  函数的声明或定义
*/
template<typename T>
//typename可以用class,没啥区别
void swapNum(T &t1, T &t2) {
    T temp = t1;
    t1 = t2;
    t2 = temp;
}

/**
 * 需要注意两个点
 * 1:如果类型推断去调用,模板的类型必须一直
 * 2:如果使用类型推断,调用的时候 必须指出数据类型才能使用,
 * 指出数据类型 = 要不是自动推断或者要不就是指定好
 * 不然编译器不知道用什么类型
 */
void 模板泛型() {
    //类型自动推断
    int a = 1;
    int b = 2;
    swapNum(a, b);

    //显示指定类型
    swapNum<int>(a, b);
}

//eg:
template<class T>
void 模板需要注意第二点() {
    cout << "aaaa" << endl;
}

void 要不是自动推断或者要不就是指定好() {
//    模板需要注意第二点();//会报错
    模板需要注意第二点<int>();
}

/**
 * 普通函数和函数模板的区别:
 * 普通函数调用时可以发生自动类型转换(隐式类型转换)
 * 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
 * 如果利用显示指定类型的方式,可以发生隐式类型转换
 */
template<class T>
T add(T a, T b) {
    return a + b;
}

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

void 普通函数和函数模板的区别() {

    int a = 1;
    char b = 'b';

    //eg1:普通函数调用时可以发生自动类型转换(隐式类型转换)
    normalAdd(a, b);

    //eg2:函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
//    add(a,b);会报错

    //eg3:如果利用显示指定类型的方式,可以发生隐式类型转换
    add<int>(a, b);


}

/**
*普通函数与函数模板的调用规则
*调用规则如下:
*1.如果函数模板和普通函数都可以实现,优先调用普通函数
*2.可以通过空模板参数列表来强制调用函数模板
*3.函数模板也可以发生重载
*4.如果函数模板可以产生更好的匹配,优先调用函数模板
*/

/**
* 类模板
 * template<class T>
 * 类
*/
template<class NameType, class AgeType>
class Children {
public:
    Children(NameType name, AgeType age) {
        this->name = name;
        this->age = age;
    }

    NameType name;
    AgeType age;
};

void 类模板() {
    Children<string, int> children("fct", 1);
}


/**
 * 类模板与函数模板区别
* 类模板与函数模板区别主要有两点:
* 1.类模板没有自动类型推导的使用方式
* 2.类模板在模板参数列表中可以有默认参数
 */

template<class NameType, class AgeType>
class chongwu {
public:
    chongwu(NameType name, AgeType age) {
        this->name = name;
        this->age = age;
    }

    NameType name;
    AgeType age;
};

template<class NameType, class AgeType=int>
class chongwu2 {
public:
    chongwu2(NameType name, AgeType age) {
        this->name = name;
        this->age = age;
    }

    NameType name;
    AgeType age;
};

void 类模板与函数模板区别() {
//    chongwu chongwu("dag", 2);会报错,不能自动类型推断
    //类模板在模板参数列表中可以有默认参数
    chongwu2<string> chongwu2("dog", 2);
}

/**
 * 类模板作为对象传入函数的方式
 * 1.指定传入的类型 --- 直接显示对象的数据类型(常用方法)
 * 2.参数模板化--- 将对象中的参数变为模板进行传递
 * 3.整个类模板化--- 将这个对象类型 模板化进行传递
 */
template<class T>
class Boli {
public:
    Boli(T t) {
        this->size = t;
    }

    void showSize() {
        cout << size << endl;
    }

    T size;

};

void 指定传入的类型(Boli<int> &boli) {
    boli.showSize();
}

template<class T>
void 参数模板化(Boli<T> &boli) {
    cout << typeid(T).name() << endl;
    boli.showSize();
}


template<class T>
void 整个类模板化(T &boli) {
    cout << typeid(T).name() << endl;
    boli.showSize();
}

void 类模板作为对象传入函数的方式() {
    Boli<int> boli(2);

    指定传入的类型(boli);
    参数模板化(boli);
    整个类模板化(boli);
}

/**
 * 类模板继承
 */

template<class T>
class Roomhouse {
public:
    T name;
};

class BedRoom : public Roomhouse<string> {

};

template<class T1, class T2>
class BathRoom : public Roomhouse<T2> {
public:
    T1 size;
};

void 类模板继承() {
    BedRoom bedRoom;
    BathRoom<int, string> bathRoom;
}

/**
 * 类模板中的成员函数 类外实现
 */
template<class T>
class Cloth {
public:
    Cloth(T mark);

    void showMark();

    T mark;
};

template<class T>
Cloth<T>::Cloth(T mark) {
    this->mark = mark;
}

template<class T>
void Cloth<T>::showMark() {

}


//=======================STL==================
/**
* vector容器
*/

void printVector(int val) {
    cout << val << endl;
}

void vector容器使用() {
    vector<int> v;
    //尾插入数据
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);

    //遍历数据方法一:
    vector<int>::iterator itBegin = v.begin();//指向第一个元素
    vector<int>::iterator itEnd = v.end();//指向最后一个元素的下一个位置

    while (itBegin != itEnd) {
        cout << *itBegin << endl;
        itBegin++;
    }

    //遍历数据方法二:
    for (vector<int>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++) {
        cout << *itBegin << endl;
    }

    //遍历数据方法三:for_each算法
    for_each(v.begin(), v.end(), printVector);
}

/**
 * vertro放入自定义类型,和自定义类型指针 数据
 */
class Water {
public:
    Water(string name, int age) {
        this->name = name;
        this->age = age;
    }

    string name;
    int age;
};

void 存入自定义类型数据() {
    /**
     * 存入自定义数据
     */
    vector <Water> v;
    v.push_back(Water("a", 10));
    v.push_back(Water("b", 21));
    v.push_back(Water("c", 33));
    for (vector<Water>::iterator it = v.begin(); it != v.end(); it++) {
        //因为it是指针,解引用出来,就是 Water对象,当然也可以在直接使用 指针 ->  获得对象的属性
        cout << (*it).name << endl;
        cout << it->name << endl;
    }

    /**
     * 存入自定义指针数据
     */
    vector <Water*> vv;
    Water w1("a", 10);
    Water w2("b", 21);
    Water w3("c", 33);
    vv.push_back(&w1);
    vv.push_back(&w2);
    vv.push_back(&w3);
    for (vector<Water*>::iterator it = vv.begin(); it != vv.end(); it++) {
        //因为it是指针,解引用出来,就是 Water对象,当然也可以在直接使用 指针 ->  获得对象的属性
        cout << (*it)->name << endl;
    }

}