chapter-6

作者: 峡迩 | 来源:发表于2017-07-03 22:05 被阅读0次

    C++ Primer第六章!

    #include "stdafx.h" 
    #include<iostream>
    #include<string>
    #include<vector>
    #include<initializer_list>          //实参数量未知,但是类型相同
    #include<cassert>               //调式头文件,assert和NDEBUG
    
    using namespace std;
    int fact_sample(int val)
    {
        int ret = 1;
        while (val > 1)
        {
            ret = ret*val;
            --val;
        }
        return ret;
    }
    int fact_iterator(int val)
    {
        int tmp = val;
        if(val>1)
            return tmp*fact_iterator(--val);            //此处不能使用val*fact_iterator(--val),val的值会改变,造成表达式逻辑错误!
        else
        {
            return val;
        }
    }
    
    int factorial(int val)
    {
        if (val>1)
            return val*fact_iterator(val-1);            //同int fact_iterator(int val)。
        else
        {
            return 1;
        }
    }
    
    int fact_for(int val)
    {
        int ret = 1;
        for (int i = 1; i <= val; ++i)
        {
            ret = ret*i;
        }
        return ret;
    }
    
    size_t count_calls()
    {
        static size_t ctr = 0;                      //局部静态对象,直到程序终止才被销毁
        return ++ctr;
    }
    void reference_fun(int &val)
    {
        --val;
    }
    void p_fun(int *ip)
    {
        *ip = *ip - 1;
    }
    
    bool isShorter(const string &s1, const string &s2)          //比较两个string对象的长度,string可能非常长,建议使用引用!
    {                                                           //有的类型不支持拷贝(iostream,其同时也不支持const),则只能通过引用传递!
        return s1.size() < s2.size();
    }
    
    void print_arry(const int *arry)                            //等价于const int[],const int[10].不允许拷贝数组,但是形参还是可以写成数组形式,其实质是const int*
    {
        cout << arry[0] << endl;
    }
    
    void print_char(const char *cp)
    {
        if (cp)
            while (*cp)
                cout << *cp++;
    }
    
    void print_iter(const int *beg, const int *end)
    {
        while (beg != end)
            cout << *beg++ << endl;
    }
    
    void print_count(const int ia[], size_t size)
    {
        for (size_t i = 0; i != size; ++i)
        {
            cout << ia[i] << endl;
        }
    }
    
    void print_reference(int(&arr)[2])
    {
        for (auto elem : arr)
            cout << elem << endl;
    }
    
    void print_mulit_ptr(int(*matptr)[2],int rowsize)       //指向含有10个整数的数组的指针。而int *matptr[10]表示10个指针构成的数组
    // 等价于void print_mulit_ptr(intmatptr[][2],int rowsize)
    {
        for (int i = 0; i < rowsize; ++i)
        {
            auto *beg = begin(*matptr);                     //由于已知数组的大小,也可以直接使用。
            while (beg!=end(*matptr))
            {
                cout << *beg << "+";
                ++beg;
            }
            cout << endl;
            ++matptr;
        }
    }
    
    void print_msg(initializer_list<string> lst)
    {
        for (auto beg = lst.begin(); beg != lst.end(); ++beg)       //可以使用范围for循环处理其中的元素
            cout << *beg << " ";
        cout << endl;
    }
    
    const string &shortString(const string &s1, const string &s2)
    {
        return s1.size() <= s2.size() ? s1 : s2;
    }
    
    void print_ret()
    {
        return;
    }
    
    char &get_value(string &str, string::size_type ix)
    {
        return str[ix];
    }
    
    vector<string> process_return()
    {
        return { "aaa","bbb","ccc" };           //也可以返回renturn {};返回指定类型空vector
    }
    
    int odd[2] = { 13,14 };
    int even[2] = { 52,93 };
    decltype(odd) *arrptr(int i)
    {
        return (i % 2) ? &odd : &even;          //int (*p)[2]=&odd;指向10个整数的数组的定义。
    }
    
    void print_overload()
    {
        cout << "Test" << endl;;
    }
    void print_overload(const char *cp)
    {
        cout<<*cp<<endl;
    }
    void print_overload(const char *cp,string::size_type sz)
    {
        for (unsigned int i = 0; i < sz; ++i)
        {
            cout << cp[i];
        }
        cout << endl;                               //最好不在函数中定义输出的格式。
    }
    
    const string &shorterString(const string &s1, const string &s2)
    {
        return s1.size() < s2.size() ? s1 : s2;
    }
    string &shorterString(string &s1, string &s2)
    {
        auto &r = shorterString(const_cast<const string&>(s1), const_cast<const string&>(s2));
        return const_cast<string&>(r);
    }
    
    using sz = string::size_type;// size_t是全局定义的类型;size_type是STL类中定义的类型属性,用以保存任意string和vector类对象的长度!数组下表是size_t,而容器是size_type!
    string screen(sz ht = 24, sz wid = 80, char background = ' ')       //一旦某个形参被赋予了默认值,他后面的所有形参都必须有默认值。
    {
        return " ";                                                             //如果进行多次声明默认实参函数,则函数的后续声明只能为没有默认实参的形参添加默认值,且该形参右侧所有形参都必须有默认值!
    }
    
    inline const int &max_numbers(const int &a, const int &b)
    {
        return a < b ? b : a;
    }
    
    constexpr size_t arr_count(size_t cnt)
    {
        return 10 * cnt;
    }
    
    int addb(const int &a, const int &b)
    {
        return(a + b);
    }
    int(*p_addb)(const int &a, const int &b);       //p_addb指向函数的指针,其中该函数的两个参数为const int的引用,返回值为int。
    
    void  print_addb(ostream &os, int(*print_addb)(const int &a, const int &b),const int a=3,const int b=4)
    {
        os << (*p_addb)(a,b) << endl;
    }
    
    int main()
    {
        int j_sample = fact_sample(5);              //调用函数,实参可以隐式转换为形参!(形参初始化的机理和变量初始化一样)
        cout << j_sample << endl;                   //函数的返回类型不能是数组和函数,但可以是指向数组或函数的指针
        int j_iterator = fact_iterator(5);          //在头文件中放函数声明,在源文件中包含头文件,并定义函数。
        cout << j_iterator << endl;
        int j_for = fact_for(5);
        cout << j_for << endl;
    
        int j_reference = 5;
        reference_fun(j_reference);                 //引用传递,形参初始化的机理和变量初始化一样
        cout << j_reference << endl;
    
        int j_p = 5;                                //指针传递,形参初始化的机理和变量初始化一样
        p_fun(&j_p);
        cout << j_p << endl;
    
        //void fcn(const int i){}
        //void fcn(int i){}             两个函数是一样的,在形参拷贝初始化时,忽略了它的顶层const,因此给函数形参是一样的!
        //C++允许通过字面值初始化常量引用,而不允许初始化普通引用!
    
        int i_arry[10] = { 0,1,2,3 };
        print_arry(i_arry);
    
        //使用数组时确保不会越界,常见3种常用的技术
        
        //数组本身包含一个结束标记,例如C风格字符串
        char *p_char = "abc";
        print_char(p_char);
    
        //begin和end函数
        int j_arry[2] = { 1,2 };
        print_iter(begin(j_arry), end(j_arry));
    
        //显示传递一个数组大小
        int j_count[2] = { 9,8 };
        print_count(j_count, end(j_count) - begin(j_count));
    
        //数组引用形参
        int j_refer[2] = { 7,6};
        print_reference(j_refer);
    
        //传递多维数组
        int j_mulit_arry[2][2] = { 1,2,3,4 };
        print_mulit_ptr(j_mulit_arry, 2);
        
        //可变形参的函数,1、如果实参类型相同可以使用initializer_list;2、可变参数模版?
        //initializer_list<T> lst;
        //initializer_list<T> lst{a,b,c};   lst对象中的元素永远是常量值,即abc为const。
        //lst2=lst;                         拷贝或赋值一个initializer_list对象不会拷贝列表中的元素,原始列表和副本共享元素。
        //lst.size();
        //lst.begin();                      返回指向lst中首元素的指针。
        //lst.end();
        print_msg({ "aa","bb","cc" });      //向initializer_list形参中传递一个值的序列,必须把序列放在一对花括号内。
    
        //返回return
        //无返回值函数,可以使用return语句提前退出函数
        print_ret();
    
        //有返回值函数,返回类型应与函数类型一致。返回一个值的方式和初始化一个变量或形参的方式完全一样!
        string s_short1 = "aaa", s_short2 = "bbbb";
        cout << shortString(s_short1, s_short2) << endl;
    
        //返回局部变量时,则返回的是局部变量的副本(未命名临时变量)。请一定不要返回局部对象的引用或指针!!!
    
        //引用返回值,返回引用的函数得到左值,其他返回类型得到右值
        string s_value("aaaaa");
        get_value(s_value, 2) = 'B';
        cout << s_value << endl;
    
        //列表初始化返回值
        vector<string> err_msg_return = process_return();
    
        //主函数main的返回值
        //mian函数的返回值可以看作状态指示器,返回0表示执行成功,返回其他值表示失败。
        //cstdlib中定义了两个预处理变量,EXIT_FAILURE,EXIT_SUCCESS。
    
        //递归,函数调用自身,递归函数
        cout << factorial(5) << endl;
    
        // 返回数组指针
        using arrT = int[2];    //等价于typedef int arrT[10]
        //arrT* func(int i),等价于int (*func(int i))[10],也可以使用C++新规定:位置返回类型
        //auto func(int i) -> int(*)[10];
        //如果已知函数返回的指针将指向哪个数组,可以使用decltype推断
        int i_decl = 2;
        int (*out_decl)[2] = arrptr(i_decl);
        for (int i = 0; i < 2; ++i)
        {
            cout << (*out_decl)[i] << " ";          //int (*p)[2]=&odd;p为指针,指向10个整数的数组。
        }
        cout << endl;
    
        //重载函数,在形参数量或类型上有所不同。尽量只重载那些确实非常相似的操作
        const char *p_overload = "abcdefg";
        print_overload();
        print_overload(p_overload);
        print_overload(p_overload, 3);
        //顶层const形参,函数等价。底层const,函数可重载。顶层const只决定了在函数体内是否可以改变形参值,而不影响传入的实参。
        //int lookup(int),int lookup(const int);    int lookup(int*),int lookup(int *const),顶层const等价
        //int lookup(int&),int lookup(const int&);  int lookup(int*),int lookup(const int*),如果形参是某种类型的指针或引用,则通过区分其指向的是常量对象还是非常量对象可以实现函数重载(底层const)。
    
        //const_cast和重载
        //shorterString,有什么特别作用吗?当使用非常量实参,想得到非常量的引用时,此时使用shorterString,定义2个重载函数。同时,重载函数应该避免强制类型转换!
    
        //默认实参,调用含有默认实参的函数,可以包含该实参,也可以省略该实参。
        string window;
        window = screen();
        window = screen(255, 255, '+');
        //window=screen(,,'+')  错误行为,在设计默认实参函数时,尽量让使用默认值的形参放在后面,不适用默认值的形参放在前面!
        
        //默认实参初始值含义?
    
        //内联函数,适用于节省开销、流程直接、频繁调用的函数
        int inline_a = 3, inline_b = 5;
        cout << max_numbers(inline_a, inline_b)<<endl;              //等价于cout<<(a < b ? b : a)<<endl;
        
        //constexpr函数,函数的返回类型和所有形参的类型都得是字面值类型(内置类型、引用、指针),而函数体中必须有且只有一条return语句。
        int arr_constexpr1[arr_count(2)];
        size_t i_constexpr = 2;
        //int arr_constexpr2[arr_count(i_constexpr)];           arr_count返回值不为常量表达式。
    
        //调试帮助,assert和NDEBUG
        assert(3 > 2);                                          //如果表达式为假,则输出信息并终止程序,可以用#define语句定义NDEBUG语句,关闭调式状态!
    
        //函数指针,指向函数而非对象
        int a_func = 1, b_func = 2;
        p_addb = addb;                                          //等价于p_addb=&addb.另外可以为p_addb赋值nullptr,表示没有指向任何一个函数。
        cout << addb(a_func, b_func) << endl;
        cout << p_addb(a_func, b_func) << endl;
        cout << (*p_addb)(a_func, b_func) << endl;              //等价于上面调用语句
        //使用函数指针作为形参, 将函数作为实参
        print_addb(cout, addb);
        print_addb(cout, addb,1,9);
        //返回指向函数的指针
        using F = int(int);
        using PF = int(*)(int);
        //PF f1(int),f1返回指向函数的指针
        //F *f1(int),f1返回指向函数的指针
        //auto f1(int)->int(*)(int),返回指向函数的指针。
        //也可以使用decltype推断函数的类型,得到形如F形式,接着声明函数。
    
        cin.ignore();
    
        return 0;
    }
    
    

    //函数包含返回类型声明、函数名、形参、实参、函数体等等部分,另外可以对函数进行重载。
    //内联函数可以避免常见的函数调用开销!
    //省略符形参是什么鬼?

    相关文章

      网友评论

          本文标题:chapter-6

          本文链接:https://www.haomeiwen.com/subject/kkehcxtx.html