3.C++的函数

版权声明:博客仅作为博主的个人笔记,未经博主允许不得转载。 https://blog.csdn.net/qq_35976351/article/details/81806629

函数

函数的参数

可变形参的函数,如果函数的参数类型相同,可以使用initialize_list的标准库类型,头文件与之同名。

一般操作:

  • initializer_list<T> lst初始化
  • initializer_list<T> lst{a,b,c}初始值,传递列表元素的副本,列表的元素是const
  • lst2(lst)拷贝或赋值一个initializer_list对象,不会拷贝列表中的元素;拷贝后,原始列表和副本共享元素。
  • lst.size()列表元素的数量
  • lst.begin()首元素的指针
  • lst.end()尾指针
#include <iostream>
#include <bits/stdc++.h>
using namespace std;

void error_msg(initializer_list<string> l){
  for(auto &p:l){
    cout<<p<<endl;
  }
}

int main(){
  error_msg({"a","b","c"});
  return 0;
}

数组作为函数的参数,直接按照数组的格式传递即可,但实际上传递的是数组的指针:

void func(int a[10], int a[3][4]) {
    // function body
}

函数的返回值

函数返回值时,是把原来的值复制一遍,单纯地返回值是返回的值的副本。不能返回局部对象的引用或者局部对象的指针,因为局部对象在函数调用结束后就被销毁了。

只有返回引用时,才是返回的左值,其余的情况都是返回的右值。返回引用的一般方式:

char &get_val(string &str, string::string_size ix) {
    return str[ix];
}

int main(){
    string s("a value");
    get_val(s,0)='A';
    cout<<s<<endl;        // 输出 A value
    return 0;
}

也可以返回初始化列表:

vector<string> process() {
    return {"A", "B", "C"};
}

C++不支持函数返回数组,所以只能通过返回函数的指针的格式进行。必须记住被定义的名字后面的数组的维数。

int (*func(int i))[10];  // 返回一个大小是10的一维整型数组

上述过程太繁琐,容易出错,在C++11中,可以使用后置声明的方式:

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

返回一个指向含有10个整型整数的数组,比如说int arr[3][10]。C++14中,甚至可以直接使用auto而不进行后置声明。

使用decltype用于指向那些明确知道的数组

int odd[] = {1, 3, 5};
int even[] = {0, 2, 4};

decltype(odd) *arrPtr(int i) {
    return (i % 2) ? &odd : &even;
}

函数重载

函数重载时,编译器区分同名重载函数的唯一标识是函数的参数,无法通过返回值区分;但是重载可以另返回值不同。

一组正确的重载:

int func(int i) {}   
char func(char j) {}

错误的重载,无法仅仅通过返回值区分

int func(int i){}
char func(int j){}

编译器无法区分顶层的const形参,但是可以区分顶层const的引用或者指针!!!

错误的重载,无法区分顶层的const形参

void Foo(const string str) {}
void Foo(string str) {}
void Foo(string*) {}
void Foo(string *const) {}

正确的重载,可以区分引用和指针:

void Foo(const string &str) {}
void Foo(string &str) {}
void Foo(string*) {}
void Foo(const string*) {}

const_cast的类型转化在参数传递的应用:

string &shorterString(string &s1, string &s2){
    auto &r=shorterString(const_cast<const string&>(s1)),
                          const_cast<const string&>(s2));
    return const_cast<string&>(r);
}

在不同的作用域中,无法进行函数重载!

特殊用途语言特性

默认形参必须放在所有的参数最后,或者默认形参的后面所有的参数都是默认形参。可以显式的传入默认形参,但是必须要按照参数的顺序,否则会报错。

内联函数inline,把函数直接复制到相应的代码处,而不是寻地址调用,适用于较短的、频繁调用的函数体。

constexpr函数,用于常量表达式的函数,函数的返回值必须是字面值,函数体只能有一个return。该关键字让编译器在编译时检查返回值是否是常量表达式。

inlineconstexpr函数都是要放到 头文件中。

函数指针

函数指针用于指向函数,函数指针的类型由返回值和形参共同决定。

定义方式:

bool lengthCompare(const string &, const string &); // 声明一个函数
bool (*pf)(const string &, const string &);         // 声明函数指针,pf必须有括号

两种等价的赋值方式:

pf = lengthCompare;
pf = &lengthCompare;

等价的调用方式:

pf('a', 'bc');
(*pf)('a', 'bc')
lengthCompare('a', 'bc');

函数指针可以进行重载,规则参考函数重载,只是把函数名换成了指针而已。

函数指针可以作为形参使用,使用方式:

// 第三个是函数指针的形参
void useBigger(const string &s1, const string &s2, bool (*pf)(const string &, const string &));

// 等价的声明
void useBigger(const string &s1, const string &s2, bool pf(const string &, const string &))

直接使用函数类型过于繁琐,可以使用using或者typedef另起别名。

typedef的方式:

//  Func和Func2是函数类型,不是函数指针
typedef bool Func(const string &, const string &);
typedef decltype(lengthCompare) Func2;

// FuncP和FuncP2是函数指针
typedef bool(*FuncP)(const string &, const string &);
typedef decltype(lengthCompare) *FuncP2;

using的使用方式,更加简介明了,推荐这种方式!

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

在函数中,可以使用后置类型推导返回函数指针:

auto f1(int) -> int(*)(int*, int);

假如知道函数的类型,可以使用decltype进行推导:

int f1(int i, int j);
char f2(char c);

decltype(f1) *getFunc(const string &s);  // 注意*,自动退到不会返回指针!

猜你喜欢

转载自blog.csdn.net/qq_35976351/article/details/81806629