C++ Primer 第六章 函数

news2025/2/6 9:45:10

C++ Primer 第六章 函数

  • 6.1. Function Basics
    • Parameters and Arguments
  • 6.2. Argument Passing
    • 6.2.3. const Parameters and Arguments
    • 6.2.4. Array Parameters
    • 6.2.6. Functions with Varying Parameters
      • initializer_list Parameters
      • Ellipsis Parameters
  • 6.3. Return Types and the return Statement
    • List Initializing the Return Value
    • Returning a Pointer to an Array
    • Using a Trailing Return Type
    • Using decltype
  • 6.4. Overloaded Functions
    • Defining Overloaded Functions
    • Overloading and const Parameters
  • 6.5. Features for Specialized Uses
    • 6.5.1. Default Arguments
    • Default Argument Declarations
    • 6.5.2. Inline and constexpr Functions
      • constexpr Functions
      • Put inline and constexpr Functions in Header Files
    • 6.5.3. Aids for Debugging
      • The assert Preprocessor Macro
      • The NDEBUG Preprocessor Variable
  • 6.6. Function Matching
    • Function Matching with Multiple Parameters
    • Argument Type Conversions
  • 6.7. Pointers to Functions
    • Using Function Pointers
    • Function Pointer Parameters
    • Returning a Pointer to Function
    • Using auto or decltype for Function Pointer Types

6.1. Function Basics

Parameters and Arguments

Arguments are the initializers for a function’s parameters.

Although we know which argument initializes which parameter, we have no guarantees about the order in which arguments are evaluated.

6.2. Argument Passing

6.2.3. const Parameters and Arguments

We cannot pass a const object, or a literal, or an object that requires conversion to a plain reference parameter.

6.2.4. Array Parameters

We cannot copy an array, and when we use an array it is (usually) converted to a pointer .

6.2.6. Functions with Varying Parameters

initializer_list Parameters

std::initializer_list
std::initializer_list<T>

We can write a function that takes an unknown number of arguments of a single type by using an initializer_list parameter.

An initializer_list is a library type that represents an array of values of the specified type.

This type is defined in the initializer_list header.

1

Like a vector, initializer_list is a template type.

When we define an initializer_list, we must specify the type of the elements that the list will contain:

initializer_list<string> ls; // initializer_list of strings
initializer_list<int> li; // initializer_list of ints

Unlike vector, the elements in an initializer_list are always const values; there is no way to change the value of an element in an initializer_list.

void error_msg(initializer_list<string> il)
{
for (auto beg = il.begin(); beg != il.end(); ++beg)
cout << *beg << " " ;
cout << endl;
}

When we pass a sequence of values to an initializer_list parameter, we must enclose the sequence in curly braces:

// expected, actual are strings
if (expected != actual)
	error_msg({"functionX", expected, actual});
else
	error_msg({"functionX", "okay"});

A function with an initializer_list parameter can have other parameters as well.

void error_msg(ErrCode e, initializer_list<string> il)
{
cout << e.msg() << ": ";
for (const auto &elem : il)
cout << elem << " " ;
cout << endl;
}
if (expected != actual)
error_msg(ErrCode(42), {"functionX", expected, actual});
else
error_msg(ErrCode(0), {"functionX", "okay"});

Ellipsis Parameters

Ellipsis parameters are in C++ to allow programs to interface to C code that uses a C library facility named varargs.

An ellipsis parameter may appear only as the last element in a parameter list and may take either of two forms:

void foo(parm_list, ...);
void foo(...);

6.3. Return Types and the return Statement

Calls to functions that return references are lvalues; other return types yield rvalues.

char &get_val(string &str, string::size_type ix)
{
	return str[ix]; // get_val assumes the given index is valid
}
int main()
{
string s("a value");
cout << s << endl; // prints a value
get_val(s, 0) = 'A'; // changes s[0] to A
cout << s << endl; // prints A value
return 0;
}

List Initializing the Return Value

As in any other return, the list is used to initialize the temporary that represents the function’s return.

If the list is empty, that temporary is value initialized.

vector<string> process()
{
// . . .
// expected and actual are strings
if (expected.empty())
	return {}; // return an empty vector
else if (expected == actual)
	return {"functionX", "okay"}; // return list-initialized vector
else
	return {"functionX", expected, actual};
}

Returning a Pointer to an Array

Type (*function(parameter_list))[dimension]
int (*func(int i))[10];
  • func(int) says that we can call func with an int argument.

  • (*func(int)) says we can dereference the result of that call.

  • (*func(int))[10] says that dereferencing the result of a call to func yields an array of size ten.

  • int (*func(int))[10] says the element type in that array is int.

Using a Trailing Return Type

Trailing returns can be defined for any function, but are most useful for functions with complicated return types, such as pointers (or references) to arrays.

A trailing return type follows the parameter list and is preceded by ->.

// fcn takes an int argument and returns a pointer to an array of ten ints
auto func(int i) -> int(*)[10];

Using decltype

int odd[] = {1,3,5,7,9};
int even[] = {0,2,4,6,8};
// returns a pointer to an array of five int elements
decltype(odd) *arrPtr(int i)
{
	return (i % 2) ? &odd : &even; // returns a pointer to the array
}

The return type for arrPtr uses decltype to say that the function returns a pointer to whatever type odd has.

The only tricky part is that we must remember that decltype does not automatically convert an array to its corresponding pointer type.

6.4. Overloaded Functions

Functions that have the same name but different parameter lists and that appear in the same scope are overloaded.

void print(const char *cp);
void print(const int *beg, const int *end);
void print(const int ia[], size_t size);

Defining Overloaded Functions

It is an error for two functions to differ only in terms of their return types.

// each pair declares the same function
Record lookup(const Account &acct);
Record lookup(const Account&); // parameter names are ignored
typedef Phone Telno;
Record lookup(const Phone&);
Record lookup(const Telno&); // Telno and Phone are the same type

Overloading and const Parameters

  • A parameter that has a top-level const is indistinguishable from one without a top-level const:
Record lookup(Phone);
Record lookup(const Phone); // redeclares Record lookup(Phone)
Record lookup(Phone*);
Record lookup(Phone* const); // redeclares Record lookup(Phone*) 
  • On the other hand, we can overload based on whether the parameter is a reference (or pointer) to the const or nonconst version of a given type; such consts are low-level:
// functions taking const and nonconst references or pointers
// have different parameters
// declarations for four independent, overloaded functions
Record lookup(Account&); // function that takes a reference to Account
Record lookup(const Account&); // new function that takes a const reference
Record lookup(Account*); // new function, takes a pointer to Account
Record lookup(const Account*); // new function, takes a pointer to const

6.5. Features for Specialized Uses

6.5.1. Default Arguments

typedef string::size_type sz; // typedef see § 2.5.1 (p. 67)
string screen(sz ht = 24, sz wid = 80, char backgrnd = ' ');

window = screen(, , '?'); // error: can omit only trailing arguments
window = screen('?'); // calls screen('?',80,' ')
  • If a parameter has a default argument, all the parameters that follow it must also have default arguments.

Default Argument Declarations

Although it is normal practice to declare a function once inside a header, it is legal to redeclare a function multiple times.

However, each parameter can have its default specified only once in a given scope.

Any subsequent declaration can add a default only for a parameter that has not previously had a default specified.

// no default for the height or width parameters
string screen(sz, sz, char = ' ');

we cannot change an already declared default value:

string screen(sz, sz, char = '*'); // error: redeclaration

but we can add a default argument as follows:

string screen(sz = 24, sz = 80, char); // ok: adds default

6.5.2. Inline and constexpr Functions

In an inline function, the compiled code is “in line” with the other code in the program.That is, the compiler replaces the function call with the corresponding function code.

With inline code, the program doesn’t have to jump to another location to execute the code and then jump back.

Inline functions thus run a little faster than regular functions, but they come with a memory penalty.

// inline.cpp -- using an inline function
#include <iostream>
// an inline function definition
inline double square(double x) { return x * x; }
int main()
{
using namespace std;
double a, b;
double c = 13.0;
a = square(5.0);
b = square(4.5 + 7.5); // can pass expressions
return 0;
}

Note:
The inline specification is only a request to the compiler. The compiler may choose to ignore this request.

constexpr Functions

constexpr specifier

A constexpr function is a function that can be used in a constant expression.

A constexpr function is defined like any other function but must meet certain restrictions:

  • The return type and the type of each parameter in a must be a literal type, and the function body must contain exactly one return statement:
constexpr int new_sz() { return 42; }
constexpr int foo = new_sz(); // ok: foo is a constant expression
  • In order to be able to expand the function immediately, constexpr functions are implicitly inline.

  • A constexpr function body may contain other statements so long as those statements generate no actions at run time.

  • A constexpr function is permitted to return a value that is not a constant:

// scale(arg) is a constant expression if arg is a constant expression
constexpr size_t scale(size_t cnt) { return new_sz() * cnt; }
int arr[scale(2)]; // ok: scale(2) is a constant expression
int i = 2; // i is not a constant expression
int a2[scale(i)]; // error: scale(i) is not a constant expression

Put inline and constexpr Functions in Header Files

Unlike other functions, inline and constexpr functions may be defined multiple times in the program.

As a result, inline and constexpr functions normally are defined in headers.

6.5.3. Aids for Debugging

The assert Preprocessor Macro

assert(expr);
  • assert is a preprocessor macro.

  • A preprocessor macro is a preprocessor variable that acts somewhat like an inline function.

  • The assert macro takes a single expression, which it uses as a condition:

  • It evaluates expr and if the expression is false (i.e., zero), then assert writes a message and terminates the program. If the expression is true (i.e., is nonzero), then assert does nothing.

  • The assert macro is defined in the cassert header.

  • As we’ve seen, preprocessor names are managed by the preprocessor not the compiler.

  • As a result, we use preprocessor names directly and do not provide a using declaration for them.

The NDEBUG Preprocessor Variable

The behavior of assert depends on the status of a preprocessor variable named NDEBUG.

If NDEBUG is defined, assert does nothing.

By default, NDEBUG is not defined, so, by default, assert performs a run-time check.

$ CC -D NDEBUG main.C # use /D with the Microsoft compiler

has the same effect as writing #define NDEBUG at the beginning of main.C.

void print(const int ia[], size_t size)
{
#ifndef NDEBUG
// _ _func_ _ is a local static defined by the compiler that holds the function's name
cerr << _ _func_ _ << ": array size is " << size << endl;
#endif
// ...

In addition to _ _func_ _, which the C++ compiler defines, the preprocessor defines four other names that can be useful in debugging:

_ _FILE_ _ string literal containing the name of the file
_ _LINE_ _ integer literal containing the current line number
_ _TIME_ _ string literal containing the time the file was compiled
_ _DATE_ _ string literal containing the date the file was compiled

We might use these constants to report additional information in error messages:

if (word.size() < threshold)
cerr << "Error: " << _ _FILE_ _
<< " : in function " << _ _func_ _
<< " at line " << _ _LINE_ _ << endl
<< " Compiled on " << _ _DATE_ _
<< " at " << _ _TIME_ _ << endl
<< " Word read was \"" << word
<< "\": Length too short" << endl;
Error: wdebug.cc : in function main at line 27
Compiled on Jul 11 2012 at 20:50:03
Word read was "foo": Length too short

6.6. Function Matching

void f();
void f(int);
void f(int, int);
void f(double, double = 3.14);
f(5.6); // calls void f(double, double)

Function Matching with Multiple Parameters

f(42, 2.56);

In this case, the viable functions are f(int, int) and f(double, double).

The compiler will reject this call because it is ambiguous: Each viable function is a better match than the other on one of the arguments to the call.

Note:
Casts should not be needed to call an overloaded function. The need for a cast suggests that the parameter sets are designed poorly.

Argument Type Conversions

Conversions are ranked as follows:

1. An exact match

  • The argument and parameter types are identical.
  • The argument is converted from an array or function type to the corresponding pointer type. (covers function pointers.)
  • A top-level const is added to or discarded from the argument.

2. Match through a const conversion

Record lookup(Account&); // function that takes a reference to Account
Record lookup(const Account&); // new function that takes a const reference
const Account a;
Account b;
lookup(a); // calls lookup(const Account&)
lookup(b); // calls lookup(Account&)

(1) We cannot bind a plain reference to a const object.
(2) We can use b to initialize a reference to either const or nonconst type.
However, initializing a reference to const from a nonconst object requires a conversion. Hence, the nonconst version is preferred.

3. Match through a Promotion or Arithmetic Conversion
(1) The small integral types always promote to int or to a larger integral type.

void ff(int);
void ff(short);
ff('a'); // char promotes to int; calls f(int)

(2) All the arithmetic conversions are treated as equivalent to each other.
The conversion from int to unsigned int, for example, does not take precedence over the conversion from int to double:

void manip(long);
void manip(float);
manip(3.14); // error: ambiguous call

6.7. Pointers to Functions

Using Function Pointers

When we use the name of a function as a value, the function is automatically converted to a pointer.

Function Pointer Parameters

// third parameter is a function type and is automatically treated as a pointer to function
void useBigger(const string &s1, const string &s2,
bool pf(const string &, const string &));
// equivalent declaration: explicitly define the parameter as a pointer to function
void useBigger(const string &s1, const string &s2,
bool (*pf)(const string &, const string &));

Type aliases, along with decltype, let us simplify code that uses function pointers:

// compares lengths of two strings
bool lengthCompare(const string &, const string &);
// Func and Func2 have function type
typedef bool Func(const string&, const string&);
typedef decltype(lengthCompare) Func2; // equivalent type
// FuncP and FuncP2 have pointer to function type
typedef bool(*FuncP)(const string&, const string&);
typedef decltype(lengthCompare) *FuncP2; // equivalent type

Both Func and Func2 are function types, whereas FuncP and FuncP2 are pointer types.

It is important to note that decltype returns the function type; the automatic conversion to pointer is not done.

Returning a Pointer to Function

As with arrays, we can’t return a function type but can return a pointer to a function type.

using F = int(int*, int); // F is a function type, not a pointer
using PF = int(*)(int*, int); // PF is a pointer type
PF f1(int); // ok: PF is a pointer to function; f1 returns a pointer to function
F f1(int); // error: F is a function type; f1 can't return a function
F *f1(int); // ok: explicitly specify that the return type is a pointer to function
int (*f1(int))(int*, int);
auto f1(int) -> int (*)(int*, int);

Using auto or decltype for Function Pointer Types

string::size_type sumLength(const string&, const string&);
string::size_type largerLength(const string&, const string&);
// depending on the value of its string parameter,
// getFcn returns a pointer to sumLength or to largerLength
decltype(sumLength) *getFcn(const string &);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/102944.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java多线程-线程的创建(Thread类的基本使用)

文章目录一. 线程和Thread类1. 线程和Thread类1.1 Thread类的构造方法1.2 启用线程的相关方法2. 创建第一个Java多线程程序3. 使用Runnable对象创建线程4. 使用内部类创建线程5. 使用Lambada表达式创建线程6. 多线程并发执行简单演示7. 多线程并发执行的优势二. Thread类的属性…

【专业数据】六.2020~2022年北京交通大学【新一代电子信息技术】专业复试线/分数线差/计划招生数/复试数/录取数/复试比例/录取率

文章目录 1.专业介绍2.2020-2022年国家线/复试线/分数线差2.1.数据总览2.2.数据指标2.2.1.复试分数线2.2.2.分数线差3.2020-2022年计划招生数/复试数/录取数/复试比例/录取率3.1.数据总览3.2.数据指标3.2.1.复试比例3.2.2.录取率4.参考资料欢迎订阅本专栏:《北交计算机复试经验…

【数据结构】树和二叉树

半山腰很挤&#xff0c;你得去山顶看看 目录 1.树 1.1 树的概念 1.2 树的特征 1.3 树每个结点的关系 1.4 树的表示形式 2.二叉树 2.1 二叉树的概念 2.2 特殊的二叉树 2.3 二叉树的性质 2.4 二叉树的存储 2.5 二叉树的基本操作 2.5.1 判断二叉树是否为空 2.…

JAVA类的继承和多态基础笔记(二)

1.继承的基本概念 父类中某一个属性是私有的&#xff0c;通过子类对象就不能访问父类的私有变量。 继承完之后拥有父类全部的东西&#xff0c;但是可以根据实际情况进行重写。 一般所有的类都是继承Object的&#xff0c;实现所有他的方法 像这样是重写了Object类的tostring方法…

[附源码]计算机毕业设计Python共享汽车系统(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

【Numpy基础知识】数组的创建

介绍 来源&#xff1a;Numpy官网&#xff1a;https://numpy.org/doc/stable/user/basics.html 文章目录介绍导包【1】将Python序列转换为Numpy数组【2】通过已有的Numpy数组创建函数创建数组【3】复制、连接或者改变现有数组【4】从磁盘读取数组【5】使用字符串或缓冲区从原始字…

[附源码]Nodejs计算机毕业设计久宠宠物店管理系统Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

载天冬酰胺酶磺丁基-β-/酶羟丙基-β-/天门冬酰胺酶环/EGF/维生素E乙酸酯糊精脂质体制备

下面为大家整理的科研内容是载天冬酰胺酶磺丁基-β-/酶羟丙基-β-/天门冬酰胺酶环/EGF/维生素E乙酸酯糊精脂质体制备&#xff0c;和小编一起来看&#xff01; 载天冬酰胺酶磺丁基-β-环糊精制备&#xff1a;采用逆向蒸发法制备ASDL,通过酸碱稳定性,热稳定性,抗胰蛋白酶稳定性,血…

【专业数据】七.2020~2022年北京交通大学【计算机技术】专业复试线/分数线差/计划招生数/复试数/录取数/复试比例/录取率

文章目录 1.专业介绍2.2020-2022年国家线/复试线/分数线差2.1.数据总览2.2.数据指标2.2.1.复试分数线2.2.2.分数线差3.2020-2022年计划招生数/复试数/录取数/复试比例/录取率3.1.数据总览3.2.数据指标3.2.1.复试比例3.2.2.录取率4.参考资料欢迎订阅本专栏:《北交计算机复试经验…

写前端?Python有手就行...

前端除了用jscsshtml&#xff0c;还有没有其它办法&#xff1f;其实python也可以 爬它&#xff01;&#xff08;https://jq.qq.com/?_wv1027&keSp12WR5&#xff09; 1. 安装与基本流程 安装 PyWebIO 和其他的第三方库一样使用pip install PyWebIO就行&#xff0c;没有…

云原生 | Kubernetes - 资源指标管道

目录 Metrics API 度量资源用量 CPU 内存 Metrics 服务器 对于 Kubernetes&#xff0c;Metrics API 提供了一组基本的指标&#xff0c;以支持自动伸缩和类似的用例。 该 API 提供有关节点和 Pod 的资源使用情况的信息&#xff0c; 包括 CPU 和内存的指标。如果将 Metrics …

【设计模式】适配器模式 (七)

文章目录5.2 适配器模式5.2.1 概述5.2.2 结构5.2.3 类适配器模式5.2.4 对象适配器模式5.2.5 应用场景5.2.6 JDK源码解析5.2 适配器模式 5.2.1 概述 如果去欧洲国家去旅游的话&#xff0c;他们的插座如下图最左边&#xff0c;是欧洲标准。而我们使用的插头如下图最右边的。因此…

机器学习笔记之玻尔兹曼机(一)基本介绍

机器学习笔记之玻尔兹曼机——基本介绍引言回顾&#xff1a;玻尔兹曼机的模型表示模型参数的对数似然梯度关于模型参数W\mathcal WW的对数似然梯度关于模型参数L,J\mathcal L,\mathcal JL,J的对数似然梯度引言 在受限玻尔兹曼机——模型表示(Representation)一节中以玻尔兹曼机…

五环三萜类化合物环糊精包合物前体脂质体/呋喃硫胺/6已基环糊精纳米粒制备

小编在这里为大家分享的是五环三萜类化合物环糊精包合物前体脂质体/呋喃硫胺/6已基环糊精纳米粒&#xff0c;一起来看看吧&#xff01; 五环三萜类化合物环糊精包合物前体脂质体制备方法&#xff1a; 通过环糊精将五环三萜类化合物包合提高亲水性,并以脂质体为载体进行包覆,通…

[Linux]线程概念_线程控制(线程与进程的区别与联系 | 线程创建 | 线程等待 | 线程终止 | 线程分离 | LWP)

文章目录线程概念进程和线程的关系线程的优点线程的缺点线程控制Linux线程和接口关系的认识线程创建线程ID及进程地址空间布局线程等待线程终止线程终止状态线程分离LWP和pthread_t线程概念 线程是在进程内部运行的一个执行分支&#xff08;执行流&#xff09;&#xff0c;属于…

我会用12种编程语言,但是偏爱python,看完文章你就知道原因了

刚开始学编程&#xff0c;或者学习一门新的编程语言时&#xff0c;我们编写的第一个程序往往很简单&#xff0c;而且往往这个程序就是输出一个简单的文本。在阅读本文时&#xff0c;你可能心知肚明我指的是哪种最常见的文本。 没错&#xff0c;我说的就是 Hello world。 这段文…

当中医遇上AI,贝叶斯携手昇思打造AI舌诊联合方案

中医的困局 中医迄今已有数千年历史&#xff0c;是老祖宗留给我们最宝贵的财富之一。然而&#xff0c;随着近代医学技术的发展&#xff0c;与声势浩大的西医相比&#xff0c;中医逐渐失势。 近年来&#xff0c;人口老龄化导致慢性病发病率持续增高。国家层面出台《健康中国行…

生态类型 or 生境类型?16S全长测序判断河流中细菌群落构建机理

文献标题&#xff1a; Distinct composition and assembly processes of bacterial communities in a river from the Arid area: Ecotypes or Habitat Types? 研究背景 细菌群落在河流生态系统中起着重要的作用&#xff0c;如元素循环和有机物的降解等。对河流细菌群落的扰…

基于实时迭代的数值鲁棒NMPC双模稳定预测模型(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

还在用明文存储密码吗?快来了解一下加密吧

目录 一. 数据库为什么不能明文存储密码 二. MD5到底是什么&#xff1f; 2.1 MD5概述 2.2 MD5为什么不是加密算法&#xff1f; 2.3 MD5主要特点MD5 2.4 MD5的性质 2.5 为什么用MD5存储密码不好 三. 给密码加盐再落库&#xff0c;增加破解成本 四. BCrypt算法加密解密…