现在的位置: 首页 > 编程语言 > 正文

《c++ primer》第6章 函数 笔记

2019年05月18日 编程语言 ⁄ 共 4827字 ⁄ 字号 评论关闭

1.函数使用引用形参返回多个信息

给函数传入一个额外的引用形参来保存其他信息

#include <iostream>
#include <string>

using namespace std;

string::size_type find_char(const string &s, char c, string::size_type &occurs)
{
    auto ret = s.size();
    occurs = 0;
    int i = 0;

    for(decltype(ret) i = 0; i != s.size(); ++i)
    {
        if(s[i] == c)
        {
            if(ret == s.size())      //记录第一次出现的位置,只执行一次
                ret = i;
            ++occurs;
        }
    }

    return ret;
}

int main()
{
    string s;
    string::size_type occurs = 0;
    cin >> s;
    char c;
    cin >> c;
    cout << find_char(s, c, occurs) << endl;
    cout << occurs << endl;

    return 0;
    
}

2.函数参数为数组时

<1 使用标记指定数组长度

比如数组结束处添加\0..

<2使用标准库规范

void prin(const int *beg, const int *end)
{
        while(beg != end)
                ....
}

prin(begin(a), end(a));   //调用

<3 显示的传递一个数组的大小

3.指针或引用形参const

const int *i; //底层,对象是个常量

const int &j;

const int k;//顶层,地址是个常量

顶层const 作为函数的参数会被忽略,

也就是

void func(const int k);//可以传参const 也可以是非const
void func2(const int *i);
void func3(const int &i);
//把const 绑定到非const 上面就错误了
void fun(int k);
void fun2(int *k);
void fun3(int &k);
const int a = 10;
fun(a)//不报错,a是副本
fun2(&a);//报错,a是const
fun3(a);//报错,a是const

4.含有可变形参的函数

如果参数数量不定,但是参数的类型一致

可以使用c++11标准库

initializer_list

头文件#include <initializer_list>

但是注意的一点,initialzer_list里面的元素全是常量。

因为<initializer_list>含有begin 和 end, 所以可以使用范围for

//求和
#include <iostream>
#include <initializer_list>

using namespace std;

int sum(initializer_list<int> li)
{
    int sum = 0;

    //int &i ,就会报错,initializer_list里面的元素全是const
    for(const int &i : li)     //写成const说明不会改变i , 使用引用避免为副本
    {
        sum += i;
    }

    return sum;
}

int main()
{
    cout << sum({1,2,3,4,5,6,7,8,9,10}) << endl;

    return 0;
}

5.引用返回左值

#include <iostream>

using namespace std;

int &ret(int *array, int i)
{
    return array[i];
}

int main()
{
    int a[10] = {1,2,3,4,5,6,7,8,9,0};
    ret(a, 8) = 1000;                 //给返回值赋值
    for(const int &i : a)
        cout << i << endl;
}

6.什么情况下返回的引用无效,什么情况下返回的常量引用无效

返回函数内定义的对象的引用无效,修改返回的常量引用无效。

7.c++11新特性使用尾置返回类型

尾置返回类型放在函数的形参表之后,我们使用auto来代替返回类型

auto func(int i) -> int(*)[10]

或者我们知道函数返回的指针指向哪个对象,就可以使用decltype关键字声明返回类型

但是decltype并不负责把数组类型转换成对应指针,必须自己添加

#include <iostream>

using namespace std;

string (* arr(void)) [10]
{
    static string a[10] = {"1","2","3","4","5","6","7","8","9","10"};

    return &a;
}

int (* arr2(void))[10]
{
    static int a[10] = {1,2,3,4,5,6,7,8,9,0};
    return &a;
}

string (& arr3(string s))[10];

int main()
{

}

分别用类型别名,尾置返回类型,decltype来改写一个返回数组的函数

#include <iostream>

using namespace std;
using arr = string[10];


string (& arr1(string a[10]))[10];

//1.使用类型别名
arr* arr2(string a[10]);

//使用尾置返回类型
auto arr3(string a[10])->string(*)[10];

//使用decltype
string b[10];
decltype(b)* arr4(string a[10]);

int main()
{
    return 0;
}

8.const_cast 和函数重载

这个在我的另外一篇文章中也有写到。

在非const 里面调用const 版本然后去除const 的特性。

#include <iostream>

using namespace std;

const string& shortString(const string &s1, const string &s2)
{
    cout << "调用 const string &" << endl;
    return s1.size() < s2.size() ? s1 : s2;
}

string& shortString(string &s1, string &s2)
{
    cout << "调用 string &" << endl;
    auto &s = shortString(const_cast<const string&>(s1), const_cast<const string&>(s2));
    return const_cast<string &>(s);
}

int main()
{
    const string s1 = "hello";
    const string s2 = "world";
    string s3,s4;

    cin >> s3 >> s4;
    shortString(s1, s2);
    shortString(s3, s4);

    return 0;

}

9.默认实参

#include <iostream>
#include <string>

using namespace std;

typedef string::size_type st;

void scree(st hi = 20, st wi = 20, char back = 'a')
{
    cout << hi << " " << wi << " " << back << endl;
}

int main()
{
    scree(3, 3, 'a');
    scree();
}

注意:一但某个形参被赋于了默认值,它后面所有的形参都必须有默认值

char * init(int ht = 24, int wd, char bakg); //error 

调用默认实参,省略参数就行。

尽量让不太使用的实参出现在函数参数表后面

10.对于那些经常使用的函数应该指定为内敛函数
inline关键字

内敛函数可避免函数调用的开销

内敛机制用于优化规模小,流程直接,频繁调用的函数

11.constexpr修饰函数, 用于返回常量表达式

constexprt函数体内也可以有空语句,只要这些语句在运行时不执行任何操作就行。

#include <iostream>
#include <string>

using namespace std;

constexpr const string& shortString(const string &s1, const string &s2)
{
    //return s1.size() <= s2.size() ? s1 : s2;    error
    return s1;
}

int main()
{
    const string s1 = "hello";
    const string s2 = "world";
    //constexpr string s3 = "aasd";               error
    
    cout << shortString(s1, s2) << endl;

    return EXIT_SUCCESS;
}

注释的都是有错误的,constexpr函数不能在调用时计算,运行时不能执行任何操作。

12.调试帮助

assert和NDEBUG

assert(条件)  条件为真什么也不做,条件为假发出错误并打印错误

assert的行为依赖于NDEBUG预处理变量的状态。 如果定义了NDEBUG 那么assert什么也不做

定义NDEBUG能避免检查各种条件所需的运行时的开销

也可以自己使用NDEBUG编写调试代码

#include <iostream>
//#define NDEBUG                             //注意位置,NDEBUG必须写在assert.h的前面,否则不起作用
#include <assert.h>

void fun(int a = 10, int b = 20)
{
    assert(a == 9);
    std::cout << a << " " << b << std::endl;
    std::cout << __FILE__ << std::endl;
    std::cout << __LINE__ << std::endl;
    std::cout << __TIME__ << std::endl;
    std::cout << __DATE__ << std::endl;
}

int main()
{
    fun();
    return 0;
}

有#define NDEBUG 和 没有的运行结果

__FILE__存放文件名的字符串字面值

__LINE__存放当前行号的整型字面值

__TIME__存放文件编译时间的字符串字面值

__DATE__存放文件编译日期的字符串字面值

13.函数指针

#include <iostream>

using namespace std;

void func(int a, int b)
{
    cout << a << " " << b << endl;
}

int main()
{
    void (*p) (int a, int b);
    p = func;
    p(1,3);
    (*p)(1,3);
}

函数指针定义一般显得非常繁琐

所以我们可以使用typdef 和 decltype来简化

typedef bool Func(const string&, const string&);
typedef decltype(Func) *Funcp; //decltype要自己加上*,它不会自动转换成指针类型

返回指向函数的指针

要想声明一个返回函数指针的函数,最简单的方法是使用类型别名

using F = int(int *, int);       //函数类型
using FF = int(*p)(int *, int);  //函数指针类型

FF f1(int);
F* f2(int);

int(*f1(int)) (int *, int);      //也可以直接声明,f1是个有参列表,且有*说明是个指针,指针指向一个函数
auto f1(int) -> int(*)(int, int);//尾置返回类型

auto和decltype作用于函数指针类型

#include <iostream>
#include <string>

using namespace std;

int fun1(int a)
{
    int sum = 1;
    while(a-- != 0)
    {
        sum *= a;
    }

    return sum;
}

decltype(fun1)* fun3(void)
{
    cout << "调用fun1" << endl;
}

int main()
{
    fun3();

    return 0;
}

抱歉!评论已关闭.