chapter-6

C++ Primer第六章!

#include "stdafx.h" 
#include
#include
#include
#include          //实参数量未知,但是类型相同
#include               //调式头文件,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 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 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<(s1), const_cast(s2));
    return const_cast(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 lst;
    //initializer_list 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 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)< 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)