[day02]引用高级、类型相关的操作、enum、new/delete重载、大数运算、函数模板与自动变量、inline

1.引用高级

一维数组的引用

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int(& ra)[5] = a;
    for (auto data : ra) {
        cout << data << " " << endl;
    }

    system("pause");
    return 0;
}

二维数组的引用

int main()
{
    int a[2][3] = { 1, 2, 3, 4, 5, 6 };
    // int a[2] = {1, 2} --> int (&ra)[2] = a;
    // int a[2][3] = ... --> int (&ra)[2][3] = a;
    int(&ra)[2][3] = a;

    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            cout << ra[i][j] << endl;
        }
    }

    system("pause");
    return 0;
}

引用函数指针

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

int sub(int a, int b)
{
    return a - b;
}

int multi(int a, int b)
{
    return a * b;
}

// 修改函数指针的值,通过传递函数指针的引用
void change1(int(* &r)(int, int))
{
    r = multi;
}

// 修改并返回函数指针的引用
int(* & change2(int (* &r)(int, int)))(int, int)
{
    r = sub;
    return r;
}

// 引用函数指针
int main()
{
    // 函数指针
    int(*pAdd)(int, int) = add;
    cout << pAdd(1, 2) << endl;
    // 函数指针的引用
    int(*&rAdd)(int, int) = pAdd;
    //int(*&&rAdd)(int, int) = &add; // 右值的引用
    cout << rAdd(1, 2) << endl;
    // 直接修改引用的值
    rAdd = sub; // 改变引用的值
    // rAdd,pAdd都成了sub函数的地址
    cout << rAdd(1, 2) << endl; 
    cout << pAdd(1, 2) << endl;
    // 通过函数修改引用
    change1(rAdd); // 不带返回值
    cout << rAdd(1, 2) << endl;
    cout << pAdd(1, 2) << endl;
    cout << change2(rAdd)(1, 2) << endl;
    cout << pAdd(1, 2) << endl;

    system("pause");
    return 0;
}

引用数组是不合法的

int main()
{
    // 引用数组是不合法的
    // 即数组不能用来存放引用
    int a = 1, b = 2, c = 3;
    // int &r[3] = { a, b, c }; //引用数组不合法
    int *p[3] = { &a, &b, &c }; //指针数组合法

    system("pause");
    return 0;
}

sizeof测引用的大小

struct mystruct {
    double &rd;
};

// sizeof 测引用的大小
// 当单独测引用的时候,会去测引用所引用的对象实体
// 只有测结构体的时候才准确,说明引用就是使用指针实现
// 引用变量占4个字节
int main()
{
    double d = 10.3;
    double &rd = d;

    cout << sizeof(d) << endl; // 8
    cout << sizeof(rd) << endl; // 8
    cout << sizeof(mystruct) << endl; // 4

    system("pause");
    return 0;
}

右值引用做函数参数

int getdata(int &&num) // 节约内存拷贝的开销
{
    num += 10;
    return num;
}

// 右值引用做函数参数
int main()
{
    int a = 1;
    int b = 2;
    
    cout << getdata(a + b) << endl;

    system("pause");
    return 0;
}

C++11左值转换成右值

// C++11左值转换成右值 std::move()
int main()
{
    int a = 1;
    int b = 2;

    cout << getdata(move(a)) << endl;

    system("pause");
    return 0;
}

常量引用

// 常量引用
int main()
{
    char str[4]("abc");
    const char(&rstr)[4] = str;
    //rstr[1] = 'B'; // 错误

    system("pause");
    return 0;
}

常引用函数指针

// 常引用函数指针
int main9()
{
    int(*pAdd)(int, int) = add;
    int(* const &rAdd)(int, int) = pAdd;

    // rAdd = sub; // 无法修改引用

    system("pause");
    return 0;
}
函数返回引用做左值例子
#include <iostream>
#include <cstdlib>

int &func()
{
    static int a = 10;
    return a;
}

int main(void)
{
    std::cout << func() << std::endl; // 10
    func() = 11;
    std::cout << func() << std::endl; // 11

    system("pause");
    return 0;
}
使用字面量对常引用初始化
int main(void)
{
    //int &ra = 10; //无法从“int”转换为“int &”
    const int &ra = 10; // OK
    std::cout << ra << std::endl;
    std::cout << &ra << std::endl;

    system("pause");
    return 0;
}
注:1.当使用常量(字面量)对const引用进行初始化时,C++编译器会为常量值分配空间,并将引用名作为这段空间的别名
     2.使用常量对const引用初始化后将生成一个只读变量

2.类型相关的操作

获取变量的类型

typeid(var).name()

根据一个变量的类型构造一个变量

decltype(var) varname;

3.enum

C语言中的enum(弱类型)

#include <stdio.h>
#include <stdlib.h>

enum color {red, yellow, blue, white};

int main()
{
    // 定义一个enum变量
    enum color mycolor = red; // 定义变量也必须写全前面的enum关键字
    mycolor = 10; // C语言弱类型,可以随便赋值
    printf("%d\n", mycolor);
    mycolor = 'A';
    printf("%d\n", mycolor);
    system("pause");
    return 0;
}

C++中的enum(强类型)

#include <iostream>
#include <cstdlib>
#include <cstdio>

// 限定类型为char
enum color : char{red='A', blue, yellow, white};

int main()
{
    color mycolor; // 定义变量可以不需要enum关键字
    //mycolor = 'A';
    //mycolor = 1; //强类型,两者都失败
    //可以使用以下两种方式赋值
    mycolor = color::red;
    mycolor = red;
    printf("%d, %c\n", mycolor, mycolor);
    system("pause");
    return 0;
}

4.new/delete重载

实现对全局局部的new/delete重载

#include <iostream>
#include <cstdlib>

// 全局new的重载
void *operator new (size_t size)
{
    void *p = NULL;
    if (size != 0) 
        p = malloc(size);
    std::cout << "全局new" << std::endl;
    return p;
}

// 全局delete重载
void operator delete (void *p)
{
    if (p != NULL)
        free(p);
    std::cout << "全局delete" << std::endl;
}

// 全局new[]的重载
void *operator new[](size_t size)
{
    std::cout << "全局new[]的重载" << std::endl;
    return operator new (size);
}

// 全局delete[]的重载
void operator delete[](void *p)
{
    std::cout << "全局delete[]的重载" << std::endl;
    return operator delete(p);
}

class MyClass {
public:
    int var;
    MyClass() {
        std::cout << "构造函数" << std::endl;
    }

    ~MyClass() {
        std::cout << "析构函数" << std::endl;
    }

    // 局部new
    static void *operator new (size_t size){
        std::cout << "局部new" << std::endl;
        MyClass *p = ::new MyClass;
        return p;
    }

    // 局部delete
    static void operator delete (void *p) {
        std::cout << "局部delete" << std::endl;
        ::delete p;
    }

    // 局部new[]的重载
    void *operator new[](size_t size)
    {
        std::cout << "局部new[]的重载" << std::endl;
        return operator new (size);
    }

    // 局部delete[]的重载
    void operator delete[](void *p)
    {
        std::cout << "局部delete[]的重载" << std::endl;
        return operator delete(p);
    }

};

int main(void)
{
    //int *p = new int[10];
    //delete []p;

    MyClass *myClass = new MyClass[5];
    delete myClass;

    system("pause");
    return 0;
}

new/delete调用顺序

 

5.大数运算

大数加法

void ptBigAdd01(const char * const inStr1, const char * const inStr2, char * const outStr)
{
    int len1 = strlen(inStr1);
    int len2 = strlen(inStr2);
    int lenMax = len1 > len2 ? len1 : len2;

    int *inNum1 = (int *)malloc(sizeof(int) * (lenMax+1));
    int *inNum2 = (int *)malloc(sizeof(int) * len2);
    int i, j, k;

    memset(inNum1, 0, sizeof(int)* (lenMax + 1));
    memset(inNum2, 0, sizeof(int)* len2);

    if (len1 > len2) {
        for (i = len1 - 1, j = 0; i >= 0; i--, j++)
            inNum1[j] = inStr1[i] - 48;

        for (i = len2 - 1, j = 0; i >= 0; i--, j++)
            inNum2[j] = inStr2[i] - 48;
    }
    else {
        for (i = len2 - 1, j = 0; i >= 0; i--, j++)
            inNum1[j] = inStr2[i] - 48;

        for (i = len1 - 1, j = 0; i >= 0; i--, j++)
            inNum2[j] = inStr1[i] - 48;
    }

    for (i = 0; i<len1 + len2 - lenMax; i++) {
        inNum1[i] += inNum2[i];

        if (inNum1[i] >= 10) {
            inNum1[i] -= 10;
            inNum1[i + 1] ++;
        }
    }

    for (i = lenMax; inNum1[i] == 0; i--);

    // The result is 0
    if (i == -1)
        printf("0");

    for (j = i, k=0; j >= 0; j--, k++) {
        //printf("%d", inNum1[j]);
        outStr[k] = inNum1[j] + 48;
    }

    free(inNum1);
    free(inNum2);
}

大数减法

void ptBigSub(const char * const inStr1, const char * const inStr2, char *const outStr)
{
    int len_min = strlen(inStr1);
    int len_max = strlen(inStr2);
    int last_j = 0;     //最关键的错位
    while (len_min > 0)
    {
        int dd1 = inStr1[len_min - 1] - '0';
        int dd2 = inStr2[len_max - 1] - '0';
        if (last_j) dd2 = dd2 - 1;
        last_j = dd2 >= dd1 ? 0 : 1;
        dd2 = dd2 >= dd1 ? dd2 : dd2 + 10;
        outStr[len_max] = (dd2 - dd1) + '0';
        len_max--;
        len_min--;
    }
    while (len_max > 0)
    {
        int dd2 = (outStr[len_max - 1] - '0');
        if (last_j) dd2 = dd2 - 1;
        last_j = dd2 >= 0 ? 0 : 1;
        dd2 = dd2 >= 0 ? dd2 : dd2 + 10;
        outStr[len_max] = dd2 + '0';
        len_max--;
    }
    if (last_j)
        outStr[0] = '1';
    else
        outStr[0] = '0';
}

大数乘法

void ptBigMulti(const char * const inStr1, const char * const inStr2, char *const outStr)
{
    int len1 = strlen(inStr1);
    int len2 = strlen(inStr2);

    int *res = (int *)malloc(sizeof(int)* (len1 + len2));
    int i, j, k;
    memset(res, 0, sizeof(int)* (len1 + len2));

    for (i = 0; i < len1; i++) {
        for (j = 0; j < len2; j++) {
            res[i + j + 1] += (inStr1[i] - 48) * (inStr2[j] - 48);
        }
    }

    for (i = len1 + len2 - 1; i >= 0; i--) {
        if (res[i] >= 10) {
            res[i - 1] += res[i] / 10;
            res[i] %= 10;
        }
    }

    for (i = 0; res[i] == 0; i++);

    for (j = i, k=0; j < len1 + len2; j++, k++) {
        outStr[k] = res[j] + 48;
    }
    free(res);
}

6.函数模板与自动变量

求任意类型数组的最大值

template<typename T>
T getMax(const T * const arr, const int n)
{
    T maxVal(arr[0]);

    for (int i = 1; i < n; i++) {
        if (arr[i] > maxVal)
            maxVal = arr[i];
    }

    return maxVal;
}

// 函数模板,求任意类型数组的最大值
int main(void)
{
    int arr[5] = { 3, 1, 2, 4, 8 };
    std::cout << getMax(arr, 5) << std::endl;

    system("pause");
    return 0;
}

求可变参数的和

// 可变参
// 必须至少要指定一个模板类型的形参变量
// NT getSum(int count, ...)这样是不行的
template<typename NT>
NT getSum(int count, NT data, ...)
{
    NT sum(0);
    va_list arg_ptr;
    va_start(arg_ptr, count);
    for (int i = 0; i < count; i++) {
        sum += va_arg(arg_ptr, NT);
    }
    va_end(arg_ptr);
    return sum;
}

//函数模板,求可变参数的和
int main(void)
{
    std::cout << getSum(5, 1, 2, 3, 4, 5) << std::endl;

    system("pause");
    return 0;
}

根据实际推导出类型

// 一般来说以下两者(typename,class)没区别
//template<typename T1, typename T2>
template<class T1, class T2>
auto getMulti(T1 a, T2 b)->decltype(a * b)
{
    return a * b;
}

// 根据实际推导出类型
int main(void)
{
    std::cout << typeid(getMulti(1.1, 2)).name() << std::endl;

    system("pause");
    return 0;
}

注:函数参数不能用auto

7.inline

inline函数的限制

(1) 不能有递归

(2) 不能包含静态数据

(3) 不能包含循环

(4) 不能包含switch和goto语句

(5) 不能包含数组

注:若一个内联函数定义不满足以上限制,则编译系统把它当作普通函数对待。

posted @ 2015-05-13 14:36  IFPELSET  阅读(289)  评论(0)    收藏  举报