• C++函数总结,看这一篇就够了


    7 C++函数

    7.1 使用C++函数步骤

    + 1.函数定义
    + 2.函数原型
    + 3.调用函数
    
    • 1
    • 2
    • 3

    库函数是已经定义和编译好的函数

    7.2 函数定义

    7.2.1 没有返回值的函数

    void functionName(parameterList)
    {
        statement(s)
        return; // optional
    }
    //parameterList指定传递给函数的参数类型和数量;return;可选返回语句标记了函数的结尾,否则函数将在右花括号处结束
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    7.2.2 有返回值的参数

    typeName functionName(parameterList)
    {
        statements
        return value; // value is type cast to type typeName
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    将值返回给调用函数,值可以是常量、变量、表达式,其结果必须是typeName类型或可以被转换为typeName;函数将转换后的值返回给函数。
    函数返回值的过程:在函数执行到return语句(返回函数)时,将返回值复制到指定的CPU寄存器或内存单元中;随后,调用函数查看该内存单元;要求返回函数和调用函数必须就该内存单元中存储的数据类型达成一致。
    注意事项:

    • 1.函数返回值不能是数组
    • 2.函数在执行返回语句后结束,如果函数包括多条返回语句,则函数在执行遇到的第一条语句后结束。

    7.2.3 代码

    function_definition.h

    #pragma once
    #ifndef _FUNCTION_DEFINITION_H
    #define _FUNCTION_DEFINITION_H
    
    // function prototypes
    int fill_array(double ar[], int limit);
    void show_array(const double begin[], const double end[]);
    void revalue(double r, double ar[], int n);
    void function_definition(void);
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    function_definition.cpp

    #include
    #include"function_definition.h"
    using namespace std;
    void function_definition(void)
    {
    	const int Max = 5;
    	double properties[Max];
    	int size = fill_array(properties, Max);
    	show_array(properties, properties + size);
    	if (size > 0)
    	{
    		cout << "Enter revaluation factor: ";
    		double factor;
    		while (!(cin >> factor)) // bad input
    		{
    			cin.clear();
    			while (cin.get() != '\n')
    				continue;
    			cout << "Bad input; Please enter a number: ";
    		}
    		revalue(factor, properties, size);
    		show_array(properties, properties + size);
    	}
    	while (cin.get() != '\n');
    }
    
    int fill_array(double ar[], int limit)
    {
    	using namespace std;
    	double temp;
    	int i;
    
    	for (i = 0; i < limit; i++)
    	{
    		cout << "Enter value #" << (i + 1) << ": ";
    		cin >> temp;
    		if (!cin) // bad input
    		{
    			cin.clear();
    			while (cin.get() != '\n')
    				continue;
    			cout << "Bad input; input process terminated.\n";
    			break;
    		}
    		else if (temp < 0) // signal to terminate
    			break;
    		ar[i] = temp;
    	}
    	return i;
    }
    // the following function can use, but not alter,
    // the array whose address is ar
    void show_array(const double begin[], const double end[])
    {
    	using namespace std;
    	const double* temp = begin;
    	while (begin != end)
    	{
    		cout << "Property #" << begin - temp + 1 << ": $";
    		cout << *begin << endl;
    		begin++;
    	}
    }
    // multiplies each element of ar[] by r
    void revalue(double r, double ar[], int n)
    {
    	for (int i = 0; i < n; i++)
    		ar[i] *= r;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    
    #include 
    #include"function_definition.h"
    
    int main()
    {
    	using namespace std;
    	cout << "函数定义*************************************************************" << endl;
    	function_definition();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.2.4 运行结果

    函数定义*************************************************************
    Enter value #1: 99
    Enter value #2: 88
    Enter value #3: 55
    Enter value #4: 44
    Enter value #5: 33
    Property #1: $99
    Property #2: $88
    Property #3: $55
    Property #4: $44
    Property #5: $33
    Enter revaluation factor: 9.99
    Property #1: $989.01
    Property #2: $879.12
    Property #3: $549.45
    Property #4: $439.56
    Property #5: $329.67
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 17636)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    7.3 函数原型

    7.3.1 为什么需要函数原型?

    函数原型将函数返回值的类型以及参数的类型和数量告诉编译器。
    编译器也可以通过函数定义知道这些信息,但是这样效率很低。(也可以将函数定义在使用该函数之前,但是程序员喜欢将main()函数放在最前面,因为main()显示了整个程序的框架)

    7.3.2 原型语法

    函数头+分号
    
    • 1

    7.3.3 注意事项

    • 1.函数原型不需要提供变量名,有类型列表足够(但是提供有意义的变量名更容易理解)
    • 2.在原型的参数列表中,可以包括变量名,也可以不包括;原型中的变量名相当于占位符,因此不必与函数定义中的变量名相同。
    • 3.C++中,原型是必不可少的
    • 4.在C++中,括号为空与在括号中使用关键字void是等效的—意味着函数没有参数
    • 5.在C++中,不指定参数列表是应使用省略号:void say_hi();—通常,仅当与接受可变参数的C函数交互时才需要这样做

    7.3.4 原型的功能

    极大地降低程序出错的几率,原型确保以下几点

    • 1.编译器正确处理函数返回值
    • 2.编译器检查使用的参数数目是否正确
    • 3.编译器检查使用的参数原型是否正确,如果不正确,则转换为正确的原型(允许自动转换时)。

    静态类型检查(static type checking):在编译阶段进行的原型化,静态类型检查可捕获许多运行阶段非常难以捕获的错误

    7.4 函数参数与按值传递

    7.4.1 按值传递

    将数值参数传递给函数,函数将其赋值给一个新的变量。原始数据表示实参(argument),复制数据表示形参(parameter)。形参变化不影响实参。

    7.4.2 局部变量

    在函数中声明的变量,函数执行时;计算机为其分配内存,函数结束时,计算机释放其内存。局部变量有助于保证数据的完整性,因为函数的局部变量在其他函数中不能使用。局部变量也称自动变量,因为他们是在程序执行过程中自动被分配和释放的。

    7.4.3 多个参数

    void fifi(float a, float b) // declare each variable separately
    void fufu(float a, b) // NOT acceptable
    
    • 1
    • 2

    7.5 函数和数组

    7.5.1 将数组作为函数输入参数传递

    传递常规变量时,将使用值传递,函数使用常规变量的拷贝;但传递数组时,函数将使用原来的数组。

    int sum_arr(int arr[], int n) // arr = array name, n = size
    
    • 1

    上面这个函数原型说明,如果将一个数组名(数组的位置,包含的元素种类)传递给arr,则arr指向数组的第一个元素并且可以访问原数组的元素;这种方式比使用值传递提高了执行速度,但是,容易不小心修改了数组中的元素。

    7.5.2 如何告诉函数数组中有多少元素

    • 1.方法1 输入参数两个,一个是数组的首地址,另一个是数组的长度

      • int sum_arr(int arr[], int n);
        
        • 1
    • 2.方法2 输入参数两个,一个是数组的首地址,另一个是数组的末尾地址+1

      • int sum_arr(const int * begin, const int * end);
        
        • 1

    为什么不使用sizeof(arr)来确定数组的长度呢?原因是arr本身是一个指针,sizeof(arr)得到的是指针的大小而不是数组的大小,所以为了函数适用于各个长度的数组,需要传递数组的长度参数

    7.5.3 使用const指针保护函数

    int sum_arr(const int arr[], int n) // arr = array name, n = size
    
    • 1

    给指针arr定义为const类型,则在函数中不能使用它修改它指向的数组的值.

    7.6 函数与二维数组

    7.6.1 将二维数组名作为参数传递给函数

    //此处不能使用const,因为const不适用于二级指针
    int sum(int ar2[][4], int size);
    int sum(int (*ar2)[4], int size);//这两个的含义是一样的
    
    • 1
    • 2
    • 3

    7.6.2 获取二维数组的元素

    ar2[r][c] == *(*(ar2 + r) + c) // same thing
    
    • 1

    7.6.3 代码

    function_two_demensional_array.h

    #pragma once
    #ifndef _FUNCTION_TWO_ARRAY_H
    #define _FUNCTION_TWO_ARRAY_H
    #include 
    
    int sum(int ar2[][4], int size);
    void function_two_demensional_array(void);
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    function_two_demensional_array.cpp

    #include "function_two_demensional_array.h"
    
    void function_two_demensional_array(void)
    {
    	int data[3][4] = { {1,2,3,4}, {9,8,7,6}, {2,4,6,8} };
    	int sumdata = sum(data, 3);
    	std::cout << "sumdata = " << sumdata << std::endl;
    }
    
    int sum(int ar2[][4], int size)
    {
    	int total = 0;
    	for (int r = 0; r < size; r++)
    		for (int c = 0; c < 4; c++)
    			total += ar2[r][c];
    	return total;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    
    #include 
    #include "function_two_demensional_array.h"
    
    int main()
    {
    	using namespace std;
    	cout << "函数与二维数组*******************************************************" << endl;
    	function_two_demensional_array();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.6.4 运行结果

    函数与二维数组*******************************************************
    sumdata = 60
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 17852)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    7.7 函数与字符串

    7.7.1 将字符串作为函数参数

    unsigned int c_in_str(const char str[], char ch);
    unsigned int c_in_str(const char* str, char ch);
    
    • 1
    • 2

    7.7.2 函数返回字符串,返回首地址

    要将数组作为输出参数时,不允许输出在函数中定义的普通数组,因为在函数中定义的数组是临时变量,在函数调用结束时会释放其存储空间,再次访问时会出现问题。而应当在函数中定义new数组,这样系统不会自动释放数组存储空间。

    char* buildstr(char c, int n);//此函数中使用了动态内存分配,分配内存的首地址返回
    
    • 1

    7.7.3 代码

    function_with_string.h

    #pragma once
    #ifndef _FUNCTION_WITH_STRING_H
    #define _FUNCTION_WITH_STRING_H
    #include 
    void function_with_string(void);
    unsigned int c_in_str(const char* str, char ch);
    char* buildstr(char c, int n);
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    function_with_string.cpp

    # include "function_with_string.h"
    
    void function_with_string(void)
    {
    	char mmm[15] = "minimum"; // string in an array
    // some systems require preceding char with static to
    // enable array initialization
    	const char* wail = "ululate"; // wail points to string
    	unsigned int ms = c_in_str(mmm, 'm');
    	unsigned int us = c_in_str(wail, 'u');
    	std::cout << ms << " m characters in " << mmm << std::endl;
    	std::cout << us << " u characters in " << wail << std::endl;
    	int times;
    	char ch;
    	std::cout << "Enter a character: ";
    	std::cin >> ch;
    	std::cout << "Enter an integer: ";
    	std::cin >> times;
    	char* ps = buildstr(ch, times);
    	std::cout << ps << std::endl;
    	delete[] ps; // free memory
    	ps = buildstr('+', 20); // reuse pointer
    	std::cout << ps << "-DONE-" << ps << std::endl;
    	delete[] ps; // free memory
    }
    
    // this function counts the number of ch characters
    // in the string str
    // unsigned int c_in_str(const char str[], char ch) // also okay
    unsigned int c_in_str(const char* str, char ch)
    {
    	unsigned int count = 0;
    	while (*str) // quit when *str is '\0',因为C字符串以'\0'结尾
    	{
    		if (*str == ch)
    			count++;
    		str++; // move pointer to next char
    	}
    	return count;
    }
    
    // builds string made of n c characters
    char* buildstr(char c, int n)
    {
    	char* pstr = new char[n + 1];
    	pstr[n] = '\0'; // terminate string
    	while (n-- > 0)
    		pstr[n] = c; // fill rest of string
    	return pstr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    
    #include 
    #include "function_with_string.h"
    
    int main()
    {
    	using namespace std;
    	cout << "函数与字符串*********************************************************" << endl;
    	function_with_string();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.7.4 运行结果

    函数与字符串*********************************************************
    3 m characters in minimum
    2 u characters in ululate
    Enter a character: a
    Enter an integer: 99
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    ++++++++++++++++++++-DONE-++++++++++++++++++++
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 9792)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7.8 函数与结构体

    7.8.1 简介

    结构体可以直接作为输入、输出参数,因为结构体相当于是一个独立的数据类型。
    当结构体元素较多时,程序员倾向于使用按引用传递而不是按值传递,因为这样可以加快程序运行时间。

    7.8.2 代码

    function_time_structure.h

    #pragma once
    #ifndef _FUNCTION_TIME_STRUCTURE_H
    #define _FUNCTION_TIME_STRUCTURE_H
    #include
    //函数与结构体  关于时间结构体
    struct travel_time
    {
    	int hours;
    	int mins;
    };
    const int Mins_per_hr = 60;
    void function_time_structure(void);
    travel_time sum(travel_time t1, travel_time t2);
    void show_time(travel_time t);
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    function_time_structure.cpp

    #include "function_time_structure.h"
    
    void function_time_structure(void)
    {
    	//这一段是关于时间结构体的测试
    	travel_time day1 = { 5, 45 }; // 5 hrs, 45 min
    	travel_time day2 = { 4, 55 }; // 4 hrs, 55 min
    	travel_time trip = sum(day1, day2);
    	std::cout << "Two-day total: ";
    	show_time(trip);
    	travel_time day3 = { 4, 32 };
    	std::cout << "Three-day total: ";
    	show_time(sum(trip, day3));
    }
    travel_time sum(travel_time t1, travel_time t2)
    {
    	travel_time total = { 0,0 };
    	total.mins = (t1.mins + t2.mins) % Mins_per_hr;
    	total.hours = t1.hours + t2.hours +
    		(t1.mins + t2.mins) / Mins_per_hr;
    	return total;
    }
    void show_time(travel_time t)
    {
    	using namespace std;
    	cout << t.hours << " hours, "
    		<< t.mins << " minutes\n";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    function_location_structure.h

    #pragma once
    #ifndef _FUNCTION_LOCATION_STRUCTURE_H
    #define _FUNCTION_LOCATION_STRUCTURE_H
    #include 
    //函数与结构体  关于位置结构体(直角坐标系和极坐标系)
    // structure declarations
    struct polar
    {
    	double distance; // distance from origin
    	double angle; // direction from origin
    };
    struct rect
    {
    	double x; // horizontal distance from origin
    	double y; // vertical distance from origin
    };
    // prototypes
    void function_location_structure(void);
    void function_location_structure_pointer(void);
    polar rect_to_polar(rect xypos);
    void show_polar(polar dapos);
    // 向函数传递结构体指针
    void rect_to_polar(const rect* pxy, polar* pda);
    void show_polar(const polar* pda);
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    function_location_structure.cpp

    #include "function_location_structure.h"
    void function_location_structure(void)
    {
    	rect rplace = { 0,0 };
    	polar pplace = { 0,0 };
    	std::cout << "Enter the x and y values: ";
    	while (std::cin >> rplace.x >> rplace.y) // slick use of cin
    	{
    		pplace = rect_to_polar(rplace);
    		show_polar(pplace);
    		std::cout << "Next two numbers (q to quit): ";
    	}
    	std::cin.clear();
    	while (std::cin.get() != '\n');
    }
    void function_location_structure_pointer(void)
    {
    	rect rplace = { 0,0 };
    	polar pplace = { 0,0 };
    	std::cout << "Enter the x and y values: ";
    	while (std::cin >> rplace.x >> rplace.y)
    	{
    		rect_to_polar(&rplace, &pplace); // pass addresses
    		show_polar(&pplace); // pass address
    		std::cout << "Next two numbers (q to quit): ";
    	}
    	std::cin.clear();
    	while (std::cin.get() != '\n');
    }
    
    //关于坐标系结构体的函数
    // convert rectangular to polar coordinates
    polar rect_to_polar(rect xypos)
    {
    	using namespace std;
    	polar answer = { 0,0 };
    	answer.distance =
    		sqrt(xypos.x * xypos.x + xypos.y * xypos.y);
    	answer.angle = atan2(xypos.y, xypos.x);//sqrt和atan2都是cmath中的函数,然后atan也是一个函数,但是它无法辨别180度之内或之外的角度
    	return answer; // returns a polar structure
    }
    // show polar coordinates, converting angle to degrees
    void show_polar(polar dapos)
    {
    	using namespace std;
    	const double Rad_to_deg = 57.29577951;
    	cout << "distance = " << dapos.distance;
    	cout << ", angle = " << dapos.angle * Rad_to_deg;
    	cout << " degrees\n";
    }
    //向函数传递结构体指针
    // show polar coordinates, converting angle to degrees
    void show_polar(const polar* pda)
    {
    	using namespace std;
    	const double Rad_to_deg = 57.29577951;
    	cout << "distance = " << pda->distance;
    	cout << ", angle = " << pda->angle * Rad_to_deg;
    	cout << " degrees\n";
    }
    // convert rectangular to polar coordinates
    void rect_to_polar(const rect* pxy, polar* pda)
    {
    	using namespace std;
    	pda->distance =
    		sqrt(pxy->x * pxy->x + pxy->y * pxy->y);
    	pda->angle = atan2(pxy->y, pxy->x);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    
    #include 
    #include "function_time_structure.h"
    #include "function_location_structure.h"
    
    int main()
    {
    	using namespace std;	
    	cout << "函数与结构体*********************************************************" << endl;
    	cout << "时间结构体***************************************************" << endl;
    	function_time_structure();
    	cout << "坐标结构体***************************************************" << endl;
    	function_location_structure();
    	cout << "坐标结构体传递结构体指针*************************************" << endl;
    	function_location_structure_pointer();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    7.8.3 运行结果

    函数与结构体*********************************************************
    时间结构体***************************************************
    Two-day total: 10 hours, 40 minutes
    Three-day total: 15 hours, 12 minutes
    坐标结构体***************************************************
    Enter the x and y values: 88 99
    distance = 132.458, angle = 48.3665 degrees
    Next two numbers (q to quit): 99 88
    distance = 132.458, angle = 41.6335 degrees
    Next two numbers (q to quit): q
    坐标结构体传递结构体指针*************************************
    Enter the x and y values: 88 99
    distance = 132.458, angle = 48.3665 degrees
    Next two numbers (q to quit): 99 88
    distance = 132.458, angle = 41.6335 degrees
    Next two numbers (q to quit): q
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 13764)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    7.9 函数与字符串类

    7.9.1 简介

    将字符串类当作独立的类型即可(如int,char等等)。

    7.9.2 代码

    function_with_string_obj.h

    #pragma once
    #ifndef _FUNCTION_STRING_H
    #define _FUNCTION_STRING_H
    #include
    
    void display(const std::string sa[], int n);
    void function_with_string_obj(void);
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    function_with_string_obj.cpp

    #include 
    #include "function_with_string_obj.h"
    
    void display(const std::string sa[], int n)
    {
    	for (int i = 0; i < n; i++)
    		std::cout << i + 1 << ": " << sa[i] << std::endl;
    }
    void function_with_string_obj(void)
    {
    	const int SIZE = 5;
    	std::string list[SIZE]; // an array holding 5 string object
    	std::cout << "Enter your " << SIZE << " favorite astronomical sights:\n";
    	for (int i = 0; i < SIZE; i++)
    	{
    		std::cout << i + 1 << ": ";
    		getline(std::cin, list[i]);
    	}
    	std::cout << "Your list:\n";
    	display(list, SIZE);//函数与string类,将string类看作是独立的数据类型即可
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    
    #include 
    #include "function_with_string_obj.h"
    
    int main()
    {
    	using namespace std;
    	cout << "函数与字符串类*******************************************************" << endl;
    	function_with_string_obj();/*
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.9.3 运行结果

    函数与字符串类*******************************************************
    Enter your 5 favorite astronomical sights:
    1: lala
    2: lili
    3: lolo
    4: lulu
    5: popo
    Your list:
    1: lala
    2: lili
    3: lolo
    4: lulu
    5: popo
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 10416)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.10 函数和Array类

    7.10.1 简介

    给函数传递指针时,可能需要更改指针所指对象元素的值,或者是为了节省运行时间。
    直接给函数传递对象时,不会更改原始对象元素的值。

    7.10.2 代码

    function_with_array.h

    #pragma once
    #ifndef _FUNCTION_WITH_ARRAY_H
    #define _FUNCTION_WITH_ARRAY_H
    #include 
    #include 
    #include 
    // constant data
    const int Seasons = 4;
    const std::array<std::string, Seasons> Snames = { "Spring", "Summer", "Fall", "Winter" };
    // function to modify array object
    void fill(std::array<double, Seasons>* pa);
    // function that uses array object without modifying it
    void show(std::array<double, Seasons> da); 
    void function_with_array(void);
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    function_with_array.cpp

    #include 
    #include "function_with_array.h"
    
    void fill(std::array<double, Seasons>* pa)
    //有缺点就是没有做输入检查,而且使用指针使得调用函数更加复杂。
    {
    	using namespace std;
    	for (int i = 0; i < Seasons; i++)
    	{
    		cout << "Enter " << Snames[i] << " expenses: ";
    		cin >> (*pa)[i];
    	}
    }
    
    //缺点就是直接传递了对象,而且对象存储较多数据,会减慢程序的执行速度。
    void show(std::array<double, Seasons> da)
    {
    	using namespace std;
    	double total = 0.0;
    	cout << "\nEXPENSES\n";
    	for (int i = 0; i < Seasons; i++)
    	{
    		cout << Snames[i] << ": $" << da[i] << endl;
    		total += da[i];
    	}
    	cout << "Total Expenses: $" << total << endl;
    }
    
    void function_with_array(void)
    {
    	std::array<double, Seasons> expenses;
    	fill(&expenses);
    	show(expenses);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    
    #include 
    #include "function_with_array.h"
    
    int main()
    {
    	using namespace std;
    	cout << "函数与array*******************************************************" << endl;
    	function_with_array();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    7.10.3 运行结果

    函数与array*******************************************************
    Enter Spring expenses: 99
    Enter Summer expenses: 88
    Enter Fall expenses: 77
    Enter Winter expenses: 66
    
    EXPENSES
    Spring: $99
    Summer: $88
    Fall: $77
    Winter: $66
    Total Expenses: $330
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 10004)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    7.11 函数指针

    函数地址就是存储其机器语言代码的内存的开始地址。

    7.11.1 函数指针的基础知识

    7.11.1.1 获取函数地址

    一定要区分传递的是函数地址还是函数返回值。

    //如果think()是一个函数,那么think就是其地址。
    //这一句就是process()触发函数think()。
    process(think); // passes address of think() to process()
    //这一句就是先执行think()函数,然后将其返回值传递给thought()函数,再执行thought()函数
    thought(think()); // passes return value of think() to thought()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    7.11.1.2 声明函数指针

    声明函数指针是,必须指定指针指向的函数类型(返回值类型和参数类型)

    //1.定义指针
    double pam(int); // prototype
    //正确的函数指针声明:pf指向一个int类型作为参数,double类型作为返回值的函数
    double (*pf)(int);
    //括号的优先级高于*,因此一定要使用括号,如下所示:
    double (*pf)(int); // 这是个函数指针
    double *pf(int); // pf()是个函数,返回值为double *
    //2.绑定指针和函数
    double pam(int);
    double (*pf)(int);
    //pf和pam的输入参数和输出参数都要求匹配,如不匹配会报错
    pf = pam; // pf指针现在指向pam函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    7.11.1.3 使用函数指针调用函数

    有两种方式,并且存在争议,但是都是合法的。

    double pam(int);//函数原型
    double (*pf)(int);//定义函数指针
    pf = pam; //pf函数指针指向函数pam地址
    double x = pam(4); //使用函数名调用函数
    double y = (*pf)(5); //使用函数指针调用函数
    //也可以直接这样使用
    double y = pf(5); //使用函数指针调用函数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    7.11.2 函数指针简单应用

    在这个代码下,estimate()函数可以调用不同的函数执行不同的操作(前提是调用的函数的参数和返回值一致)。

    7.11.2.1 代码

    function_pointer.h

    #pragma once
    #ifndef _FUNCTION_POINTER_H_
    #define _FUNCTION_POINTER_H_
    #include 
    using std::cout;
    using std::cin;
    double betsy(int lns)
    {
        return 0.05 * lns;
    }
    double pam(int lns)
    {
        return 0.03 * lns + 0.0004 * lns * lns;
    }
    void estimate(int lines, double (*pf)(int))
    {
        using namespace std;
        cout << lines << " lines will take ";
        cout << (*pf)(lines) << " hour(s)\n";
    }
    
    void function_pointer(void)
    {
        int code;
        cout << "How many lines of code do you need? ";
        cin >> code;
        cout << "Here's Betsy's estimate:\n";
        estimate(code, betsy);
        cout << "Here's Pam's estimate:\n";
        estimate(code, pam);
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    
    #include 
    #include "function_pointer.h"
    
    int main()
    {
    	using namespace std;
    	cout << "函数指针简单应用***********************************************" << endl;
    	function_pointer();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    7.11.2.2 运行结果
    函数指针简单应用***********************************************
    How many lines of code do you need? 3
    Here's Betsy's estimate:
    3 lines will take 0.15 hour(s)
    Here's Pam's estimate:
    3 lines will take 0.0936 hour(s)
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 13012)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    7.11.3 函数指针数组举例

    就扯来扯去还是指针的问题,就各种指针的指针哈哈哈。

    7.11.3.1 代码

    function_pointer_array.h

    #pragma once
    #ifndef _FUNCTION_POINTER_ARRAY_H_
    #define _FUNCTION_POINTER_ARRAY_H_
    #include 
    using std::cout;
    using std::cin;
    using std::endl;
    // some rather dull functions
    const double* f1(const double* ar, int n)
    {
        return ar;
    }
    const double* f2(const double ar[], int n)
    {
        return ar + 1;
    }
    const double* f3(const double ar[], int n)
    {
        return ar + 2;
    }
    
    void function_pointer_array(void)
    {
    	double av[3] = { 1112.3, 1542.6, 2227.9 };//这是一个数组
    	const double* (*p1)(const double*, int) = f1;//这是一个函数指针指向了函数fl
    	//auto的原理就是根据后面的值,来自己推测前面的类型是什么
    	auto p2 = f2; //auto只能用于单值初始化,不能用于多值初始化
    	//也可以使用这个(但是繁琐): const double *(*p2)(const double *, int) = f2;
    	cout << "Using pointers to functions:\n";
    	cout << " Address Value\n";
    	cout << (*p1)(av, 3) << ": " << *(*p1)(av, 3) << endl;//返回值地址:返回值地址存储的第一个数据
    	cout << p2(av, 3) << ": " << *p2(av, 3) << endl;//返回值地址:返回值地址存储的第一个数据
    	//这是一个函数指针数组,存储了三个函数地址f1,f2,f3
    	const double* (*pa[3])(const double*, int) = { f1,f2,f3 };
    	//pb是一个指针,存储着pa数组的首地址
    	auto pb = pa;
    	//可以使用以下代码替换(但是不推荐):const double *(**pb)(const double *, int) = pa;
    	cout << "\n使用函数指针数组:\n";
    	cout << " Address Value\n";
    	for (int i = 0; i < 3; i++)
    		cout << pa[i](av, 3) << ": " << *pa[i](av, 3) << endl;//返回值地址:返回值地址存储的第一个数据
    	cout << "\n使用函数指针数组的指针\n";
    	cout << " Address Value\n";
    	for (int i = 0; i < 3; i++)
    		cout << pb[i](av, 3) << ": " << *pb[i](av, 3) << endl;//返回值地址:返回值地址存储的第一个数据
    	//函数指针数组的指针
    	cout << "\n使用函数指针数组的数组类型:\n";
    	cout << " Address Value\n";
    	auto pc = &pa;
    	//可以使用以下代码替换(但是不推荐):const double *(*(*pc)[3])(const double *, int) = &pa;
    	cout << (*pc)[0](av, 3) << ": " << *(*pc)[0](av, 3) << endl;//返回值地址:返回值地址存储的第一个数据
    	const double* (*(*pd)[3])(const double*, int) = &pa;
    	const double* pdb = (*pd)[1](av, 3);
    	cout << pdb << ": " << *pdb << endl;//返回值地址:返回值地址存储的第一个数据
    	cout << (*(*pd)[2])(av, 3) << ": " << *(*(*pd)[2])(av, 3) << endl;
    }
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    
    #include 
    #include "function_pointer_array.h"
    
    int main()
    {
    	using namespace std;
    	cout << "函数指针数组应用***********************************************" << endl;
    	function_pointer_array();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    7.11.3.2 运行结果
    函数指针数组应用***********************************************
    Using pointers to functions:
     Address Value
    010FFCCC: 1112.3
    010FFCD4: 1542.6
    
    使用函数指针数组:
     Address Value
    010FFCCC: 1112.3
    010FFCD4: 1542.6
    010FFCDC: 2227.9
    
    使用函数指针数组的指针
     Address Value
    010FFCCC: 1112.3
    010FFCD4: 1542.6
    010FFCDC: 2227.9
    
    使用函数指针数组的数组类型:
     Address Value
    010FFCCC: 1112.3
    010FFCD4: 1542.6
    010FFCDC: 2227.9
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 18280)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    7.11.4 函数指针别名

    //这样用也是可以的,就很快乐哈哈哈哈
    typedef const double *(*p_fun)(const double *, int); // p_fun是一个别名
    p_fun p1 = f1; // p1 points to the f1() function
    p_fun pa[3] = {f1,f2,f3}; // pa an array of 3 function pointers
    p_fun (*pd)[3] = &pa; // pd points to an array of 3 function pointers
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7.12 内联函数

    7.12.1 简介

    编译过程的最终产品是可执行程序(由一组机器怨言指令组成)。在程序编译时,CPU会为代码分配特定的存储空间,但不存储普通函数指令,调用普通函数就是跳到相应的存储位置执行指令,然后再跳回程序之前跳转的位置执行指令;内联函数就是在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方,调用内联函数时不用再跳来跳去,可以缩短程序执行时间,但是增加了系统存储压力。如果程序再10个不同的地方调用同一个内联函数,则该程序将包含该函数代码的10个副本。

    应该有选择地使用内联函数。如果执行函数代码的时间比处理函数调用机制的时间长,则节省的时间将只占整个过程的很小一部分。如果代码执行时间很短,则内联调用就可以节省非内联调用使用的大部分时间。所以,如果函数不是两三句能描述完,就不建议写成内联函数。

    函数过大或递归函数时,程序不允许将该函数写成内联函数。

    img

    7.12.2 内联与宏

    使用C语言的宏执行了类似函数的功能,应考虑将他们转换为C++内联函数。

    7.12.3 举例

    7.12.2.1 代码

    inline_functions.h

    #pragma once
    #ifndef __INLINE_FUNCTIONS_H_
    #define __INLINE_FUNCTIONS_H_
    #define SQUARE(X) (X*X)
    #include
    using std::cout;
    using std::endl;
    inline double square(double x) { return x * x; }
    void inline_functions(void)
    {
    	cout << "inline_functions Hello**********************************" << endl;
    	double a, b;
    	double c = 13.0;
    	a = square(5.0);
    	b = square(4.5 + 7.5); // can pass expressions
    	cout << "a = " << a << ", b = " << b << "\n";
    	cout << "c = " << c;
    	cout << ", c squared = " << square(c++) << "\n";
    	cout << "Now c = " << c << "\n";
    	cout << "inline_functions Bye***********************************" << endl;
    }
    
    void define_function(void)
    {
    	cout << "define_func Hello**************************************" << endl;
    	double c = 9.9;
    	double a = SQUARE(5.0);//is replaced by a = 5.0 * 5.0;
    	cout << "a = " << a << endl;
    	double b = SQUARE(4.5 + 7.5);//is replaced by b = 4.5 + 7.5 * 4.5 + 7.5;
    	cout << "b = " << b << endl;
    	double d = SQUARE(c++);//is replaced by d = c++ * c++;
    	cout << "d = " << d << endl;
    	cout << "define_func Bye***************************************" << endl;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    #include "inline_functions.h"
    
    int main()
    {
    	using namespace std;
    	cout << "内联函数********************************************************" << endl;
    	inline_functions();
    	cout << "内联与宏********************************************************" << endl;
    	define_function();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    7.12.2.2 运行结果
    内联函数********************************************************
    inline_functions Hello**********************************
    a = 25, b = 144
    c = 13, c squared = 169
    Now c = 14
    inline_functions Bye***********************************
    内联与宏********************************************************
    define_func Hello**************************************
    a = 25
    b = 45.75
    d = 98.01
    define_func Bye***************************************
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 13516)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    7.13 引用变量

    引用变量定义:时已定义的变量的别名。

    引用变量的作用:主要用途时用作函数的形参,将引用变量用作参数,函数将使用原始数据,而不是其副本。

    7.13.1 创建引用变量

    7.13.1.1 语法
    7.13.1.1.1 简介
    int rats;
    int & rodents = rats; //创建一个引用变量并成为rats的别名,此处的&表示引用变量
    cout <<", rodents address = " << &rodents << endl;//此处的&表示地址
    
    • 1
    • 2
    • 3
    7.13.1.1.2 代码

    Reference_Variables.h

    #pragma once
    #ifndef _REFERENCE_VARIABLES_H_
    #define _REFERENCE_VARIABLES_H_
    #include
    using std::cout;
    using std::endl;
    void create_reference_variables(void)
    {
        cout << "create_reference_variables Hello**************************" << endl;
        int rats = 101;
        //下面这句就是如何定义引用变量
        int& rodents = rats; // rodents is a reference
        cout << "rats = " << rats;
        cout << ", rodents = " << rodents << endl;
        rodents++;
        cout << "rats = " << rats;
        cout << ", rodents = " << rodents << endl;
        // some implementations require type casting the following
        // addresses to type unsigned
        cout << "rats address = " << &rats;
        cout << ", rodents address = " << &rodents << endl;
        cout << "create_reference_variables Bye****************************" << endl;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    #include "Reference_Variables.h"
    
    int main()
    {
    	using namespace std;
    	cout << "引用变量********************************************************" << endl;
    	create_reference_variables();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    7.13.1.1.3 运行结果

    可以观察到变量rats和指向rats的引用变量rodents的地址和值都一样。

    引用变量********************************************************
    create_reference_variables Hello**************************
    rats = 101, rodents = 101
    rats = 102, rodents = 102
    rats address = 008FFA4C, rodents address = 008FFA4C
    create_reference_variables Bye****************************
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 14232)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    7.13.1.2 引用变量陷阱
    7.13.1.2.1 简介

    必须在声明引用时将其初始化,而不能像指针一样先声明后赋值。

    //这种方式是正确的
    int rats = 101;
    int & rodents = rats; // rodents a reference
    
    //下面这种方式就是错误的
    int rat;
    int & rodent;
    rodent = rat; //会报错
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    7.13.1.2.2 代码

    Reference_Variables.h

    #pragma once
    #ifndef _REFERENCE_VARIABLES_H_
    #define _REFERENCE_VARIABLES_H_
    #include
    using std::cout;
    using std::endl;
    void reference_variables_joke(void)
    {
        cout << "reference_variables_joke Hello**************************" << endl;
        int rats = 101;
        int& rodents = rats; // rodents is a reference
        cout << "rats = " << rats;
        cout << ", rodents = " << rodents << endl;
        cout << "rats address = " << &rats;
        cout << ", rodents address = " << &rodents << endl;
        int bunnies = 50;
        rodents = bunnies; // can we change the reference?这一句将rats的值改为了bunnies的值
        cout << "bunnies = " << bunnies;
        cout << ", rats = " << rats;
        cout << ", rodents = " << rodents << endl;
        cout << "bunnies address = " << &bunnies;
        cout << ", rodents address = " << &rodents << endl;
        cout << "reference_variables_joke Bye****************************" << endl;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    #include "Reference_Variables.h"
    
    int main()
    {
    	using namespace std;
    	cout << "引用变量********************************************************" << endl;
    	reference_variables_joke();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    7.13.1.2.3 运行结果
    引用变量********************************************************
    reference_variables_joke Hello**************************
    rats = 101, rodents = 101
    rats address = 008FFA4C, rodents address = 008FFA4C
    bunnies = 50, rats = 50, rodents = 50
    bunnies address = 008FFA34, rodents address = 008FFA4C
    reference_variables_joke Bye****************************
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 14232)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7.13.2 引用变量用作函数参数

    7.13.2.1 按值传递与按引用传递

    引用变量被用作函数参数,使得函数中的变量名成为调用程序中变量的别名,这种传递参数的方法叫做按引用传递。

    值传递、引用传递二者的区别如下:

    img

    img

    7.13.2.2 值传递、按引用传递、按指针传递对比
    7.13.2.2.1 简介

    交换两数字变量的值的三种方法对比,事实证明值传递无法交换两数字变量的值,但引用方式传递和指针可以交换两数字变量的值。

    7.13.2.2.2 代码

    Reference_Variables.h

    #pragma once
    #ifndef _REFERENCE_VARIABLES_H_
    #define _REFERENCE_VARIABLES_H_
    #include
    using std::cout;
    using std::endl;
    
    //按值传递、按引用传递、按指针传递对比,例子是交换两数字的值
    void swapr(int& a, int& b) //使用引用
    {
        int temp;
        temp = a;
        a = b;
        b = temp;
    }
    void swapp(int* p, int* q) //使用指针
    {
        int temp;
        temp = *p; 
        *p = *q;
        *q = temp;
    }
    void swapv(int a, int b) //按值传递
    {
        int temp;
        temp = a;
        a = b;
        b = temp;
    }
    void Comparison_parameter_delivery()
    {
        cout << "Comparison_parameter_delivery Hello**************************" << endl;
        int wallet1 = 300;
        int wallet2 = 350;
        cout << "wallet1 = $" << wallet1;
        cout << " wallet2 = $" << wallet2 << endl;
        cout << "Using references to swap contents:\n";
        swapr(wallet1, wallet2); // pass variables
        cout << "wallet1 = $" << wallet1;
        cout << " wallet2 = $" << wallet2 << endl;
        cout << "Using pointers to swap contents again:\n";
        swapp(&wallet1, &wallet2); // pass addresses of variables
        cout << "wallet1 = $" << wallet1;
        cout << " wallet2 = $" << wallet2 << endl;
        cout << "Trying to use passing by value:\n";
        swapv(wallet1, wallet2); // pass values of variables
        cout << "wallet1 = $" << wallet1;
        cout << " wallet2 = $" << wallet2 << endl;
        cout << "Comparison_parameter_delivery Bye****************************" << endl;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    #include "Reference_Variables.h"
    
    int main()
    {
    	using namespace std;
    	cout << "引用变量********************************************************" << endl;
    	Comparison_parameter_delivery();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    7.13.2.2.3 运行结果
    引用变量********************************************************
    Comparison_parameter_delivery Hello**************************
    wallet1 = $300 wallet2 = $350
    Using references to swap contents:
    wallet1 = $350 wallet2 = $300
    Using pointers to swap contents again:
    wallet1 = $300 wallet2 = $350
    Trying to use passing by value:
    wallet1 = $300 wallet2 = $350
    Comparison_parameter_delivery Bye****************************
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 14232)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    7.13.2.3 何时使用按值传递、指针、引用

    对于使用传递的值而不作修改的函数:

    • 如果数据对象很小,如内置数据类型或小型结构,则按值传递;
    • 如果数据对象是数组,则使用指针,并将指针声明为指向const的指针;
    • 如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率,节省复制结构所需的时间和空间。
    • 如果数据对象是类对象,则使用const引用。

    对于修改调用函数中数据的函数:

    • 如果数据对象很小,是内置数据类型,则使用指针;
    • 如果数据对象是数组,只能使用指针;
    • 如果数据对象是结构,引用或指针;
    • 如果数据对象是类对象,则使用引用。

    7.13.3 引用的属性和特别之处

    7.13.3.1 引用方式传递比值传递更严格

    不允许引用右值。

    //如果是值传递,那么下面的调用方式都是允许的
    double z = cube(x + 2.0); // evaluate x + 2.0, pass value
    z = cube(8.0); // pass the value 8.0
    int k = 10;
    z = cube(k); // convert value of k to double, pass value
    double yo[3] = { 2.2, 3.3, 4.4};
    z = cube (yo[2]); // pass the value 4.4
    
    //但是如果是引用方式传递
    double z = refcube(x + 3.0); // should not compile
    //这种调用方式是不允许的,原因是x+3.0是一个临时变量
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    7.13.3.2 临时变量

    什么是左值和右值?

    • 左值:在C++11中可以取地址的、有名字的就是左值
    • 右值:不能取地址的、没有名字的就是右值

    什么时候创建临时变量?前提是参数为const引用时。

    • 实参的类型正确,但不是左值。
    • 实参的类型不正确,但可以转换为正确的类型。
    double c5 = refcube(edge); // ra is temporary variable
    double c6 = refcube(7.0); // ra is temporary variable
    double c7 = refcube(side + 10.0); // ra is temporary variable
    
    • 1
    • 2
    • 3

    临时变量生命周期:只在函数调用期间存在,此后编译器便可随意将其删除。

    什么使用使用临时变量?

    在不修改实参的情况下可以使用临时变量,但是在需要修改实参的情况下不能使用临时变量,因为临时变量会阻止修改实参。

    7.13.3.3 const

    如果参数是基本数值类型并且不需要改变实参的值,建议不使用按引用传递的方式。如果参数是结构体、对象等需要占用大空间的输入参数,可以使用引用传递,但是在不改变实参的值时,建议使用const类型形参以保护实参不被修改。

    double refcube(const double &ra);
    
    • 1

    使用const有如下好处:

    • 可以避免无意中修改数据的编程错误
    • 使函数能够处理const和非const实参,否则将只能接收非const实参
    • 使函数能够正确生成并使用临时变量
    7.13.3.4 返回引用

    不要返回一个指向临时变量的引用,因为临时变量在函数执行完毕后将不复存在;避免返回临时变量的方法是:

    • 返回一个作为参数传递给函数的引用
    • 使用new来分配内存空间,没有delete前变量都在
    7.13.3.5 不小心更改实参举例代码

    如果使用引用变量,那么一定要注意和引用变量相关的赋值语句会改变真实变量的值。

    Reference_Variables.h

    #pragma once
    #ifndef _REFERENCE_VARIABLES_H_
    #define _REFERENCE_VARIABLES_H_
    #include
    using std::cout;
    using std::endl;
    //一不小心修改实参
    double cube(double a)
    {
        a *= a * a;
        return a;
    }
    double refcube(double& ra)
    {
        ra *= ra * ra;
        return ra;
    }
    void Modify_reference_arguments()
    {
        cout << "Modify_reference_arguments Hello**************************" << endl;
        double x = 3.0;
        cout << cube(x);
        cout << " = cube of " << x << endl;
        cout << refcube(x);
        cout << " = cube of " << x << endl;
        cout << "Modify_reference_arguments Bye****************************" << endl;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    #include "Reference_Variables.h"
    
    int main()
    {
    	using namespace std;
    	cout << "引用变量********************************************************" << endl;
    	Modify_reference_arguments();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    7.13.3.6 运行结果
    引用变量********************************************************
    Modify_reference_arguments Hello**************************
    27 = cube of 3
    27 = cube of 27
    Modify_reference_arguments Bye****************************
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 14668)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    7.13.4 引用变量用于结构体

    7.13.4.1 代码

    Reference_Variables.h

    #pragma once
    #ifndef _REFERENCE_VARIABLES_H_
    #define _REFERENCE_VARIABLES_H_
    #include
    using std::cout;
    using std::endl;
    //引用变量用于结构体
    struct free_throws
    {
        std::string name;
        int made;
        int attempts;
        float percent;
    };
    //显示结构体内容,使用const的原因是因为不修改实参
    void display(const free_throws& ft)
    {
        using std::cout;
        cout << "Name: " << ft.name << '\n';
        cout << " Made: " << ft.made << '\t';
        cout << "Attempts: " << ft.attempts << '\t';
        cout << "Percent: " << ft.percent << '\n';
    }
    //设置结构体percent元素的值
    void set_pc(free_throws& ft)
    {
        if (ft.attempts != 0)
            ft.percent = 100.0f * float(ft.made) / float(ft.attempts);
        else
            ft.percent = 0;
    }
    //两个结构体相加,返回引用实际上返回的是被引用的变量的别名
    free_throws& accumulate(free_throws& target, const free_throws& source)
    {
        target.attempts += source.attempts;
        target.made += source.made;
        set_pc(target);
        return target;
    }
    
    void reference_structure(void)
    {
        cout << "reference_structure Hello**************************" << endl;
        // partial initializations – remaining members set to 0
        free_throws one = { "Ifelsa Branch", 13, 14 };
        free_throws two = { "Andor Knott", 10, 16 };
        free_throws three = { "Minnie Max", 7, 9 };
        free_throws four = { "Whily Looper", 5, 9 };
        free_throws five = { "Long Long", 6, 14 };
        free_throws team = { "Throwgoods", 0, 0 };
        // no initialization
        free_throws dup;
        set_pc(one);
        display(one);
        accumulate(team, one);
        display(team);
        //将返回值作为参数
        display(accumulate(team, two));
        accumulate(accumulate(team, three), four);
        display(team);
        //返回值赋值给变量
        dup = accumulate(team, five);
        std::cout << "Displaying team:\n";
        display(team);
        std::cout << "Displaying dup after assignment:\n";
        display(dup);
        set_pc(four);
        //不建议的赋值
        accumulate(dup, five) = four;//这里将four赋值给dup了
        std::cout << "Displaying dup after ill-advised assignment:\n";
        display(dup);
        cout << "reference_structure Bye****************************" << endl;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    #include "Reference_Variables.h"
    int main()
    {
    	using namespace std;
    	cout << "引用变量********************************************************" << endl;
    	reference_structure();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    7.13.4.2 运行结果
    引用变量********************************************************
    reference_structure Hello**************************
    Name: Ifelsa Branch
     Made: 13       Attempts: 14    Percent: 92.8571
    Name: Throwgoods
     Made: 13       Attempts: 14    Percent: 92.8571
    Name: Throwgoods
     Made: 23       Attempts: 30    Percent: 76.6667
    Name: Throwgoods
     Made: 35       Attempts: 48    Percent: 72.9167
    Displaying team:
    Name: Throwgoods
     Made: 41       Attempts: 62    Percent: 66.129
    Displaying dup after assignment:
    Name: Throwgoods
     Made: 41       Attempts: 62    Percent: 66.129
    Displaying dup after ill-advised assignment:
    Name: Whily Looper
     Made: 5        Attempts: 9     Percent: 55.5556
    reference_structure Bye****************************
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 18420)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    7.13.5 引用变量应用于对象

    7.13.5.1 代码

    Reference_Variables.h

    #pragma once
    #ifndef _REFERENCE_VARIABLES_H_
    #define _REFERENCE_VARIABLES_H_
    #include
    #include 
    using std::string;
    using std::cout;
    using std::endl;
    using std::cin;
    string version1(const string& s1, const string& s2)
    {
        string temp;
        temp = s2 + s1 + s2;
        return temp;
    }
    const string& version2(string& s1, const string& s2) // has side effect
    {
        s1 = s2 + s1 + s2;
        // safe to return reference passed to function
        return s1;
    }
    const string& version3(string& s1, const string& s2) // bad design
    {
        string temp;
        temp = s2 + s1 + s2;
        return temp;//返回了临时变量,会出错
    }
    void reference_object(void)
    {
        cout << "reference_object Hello*****************************" << endl;
        string input;
        string copy;
        string result;
        cout << "Enter a string: ";
        getline(cin, input);
        copy = input;
        cout << "Your string as entered: " << input << endl;
        result = version1(input, "***");//按值传递
        cout << "Your string enhanced: " << result << endl;
        cout << "Your original string: " << input << endl;//原值没改变
        result = version2(input, "###");//按引用传递
        cout << "Your string enhanced: " << result << endl;
        cout << "Your original string: " << input << endl;//原值被改变了
        cout << "Resetting original string.\n";
        input = copy;
        /*result = version3(input, "@@@");
        cout << "Your string enhanced: " << result << endl;
        cout << "Your original string: " << input << endl;*/
        cout << "reference_object Bye*******************************" << endl;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    #include "Reference_Variables.h"
    
    int main()
    {
    	using namespace std;
    	cout << "引用变量********************************************************" << endl;
    	reference_object();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    7.13.5.2 运行结果
    引用变量********************************************************
    reference_object Hello*****************************
    Enter a string: Jasmine
    Your string as entered: Jasmine
    Your string enhanced: ***Jasmine***
    Your original string: Jasmine
    Your string enhanced: ###Jasmine###
    Your original string: ###Jasmine###
    Resetting original string.
    reference_object Bye*******************************
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 17228)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    7.14 默认参数

    7.14.1 简介

    默认参数就是当函数调用中省略了实参时自动使用的值。

    如何设置默认值?必须通过函数原型设置默认值,函数定义还是和普通函数定义一样没有默认值。

    char * left(const char * str, int n = 1);
    
    • 1

    注意事项:

    • 对于带参数列表的函数,必须从右往左添加默认值;要为某个参数设置默认值,必须为它右边的所有参数提供默认值。
    • 实参按从左到右的顺序一次被赋值给相应的形参,而不能跳过任何参数。
    int harpo(int n, int m = 4, int j = 5); // VALID
    int chico(int n, int m = 6, int j); // INVALID
    int groucho(int k = 1, int m = 2, int n = 3); // VALID
    beeps = harpo(3, ,8); // invalid, doesn't set m to 4
    
    • 1
    • 2
    • 3
    • 4

    7.14.2 代码

    default_argument.h

    #pragma once
    #ifndef _DEFAULT_ARGUMENT_H_
    #define _DEFAULT_ARGUMENT_H_
    #include
    #include 
    using std::string;
    using std::cout;
    using std::endl;
    using std::cin;
    const int ArSize = 80;
    char* left(const char* str, int n = 1);//设置默认值
    
    //默认参数
    char* left(const char* str, int n)
    {
        if (n < 0)
            n = 0;
        int m = 0;
        while (m <= n && str[m] != '\0')
            m++;
        char* p = new char[m + 1];//此处是为了减少分配的存储空间,因为传递来的字符串长度可能小于n
       /* int len = strlen(str);
        n = (n < len) ? n : len; 
        char* p = new char[n + 1];*///也可以使用这种方式,但是这种方式strlen()函数可能占用很多时间,因此上面的方式既节约时间也节约空间
        int i;
        for (i = 0; i < m; i++)
            p[i] = str[i]; // copy characters
        p[m] = '\0'; //将最后一位设置为'\0'
        return p;
    }
    void default_argument(void)
    {
        cout << "default_argument Hello********************************" << endl;
        char sample[ArSize];
        cout << "Enter a string:\n";
        cin.get(sample, ArSize);
        char* ps = left(sample, 4);
        cout << ps << endl;
        delete[] ps; // free old string
        ps = left(sample);
        cout << ps << endl;
        delete[] ps; // free new string
        cout << "default_argument Bye*********************************" << endl;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    #include "default_argument.h"
    
    int main()
    {
    	using namespace std;
    	cout << "默认参数********************************************************" << endl;
    	default_argument();
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    7.14.3 运行结果

    默认参数********************************************************
    default_argument Hello********************************
    Enter a string:
    Jasmine
    Jasm
    J
    default_argument Bye*********************************
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 16692)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7.15 函数重载

    7.15.1 定义及注意事项

    7.15.1.1 定义

    输入参数列表不同。

    C++让程序员能够定义两个函数名相同的函数,前提是两函数有不同的参数;参数的不同可以提现在参数数量不同或参数类型不同或数量和类型都不同。

    注意事项:是函数参数列表,而不是函数类型 使能了函数重载

    long gronk(int n, float m); // same signatures,
    double gronk(int n, float m); // hence not allowed  这是不允许的
    
    //可以有不同的返回类型,但是要求参数也不同才可被重载
    long gronk(int n, float m); // different signatures,
    double gronk(float n, float m); // hence allowed  这是允许的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    7.15.1.2 C++如何区分重载函数

    C++根据上下文来确定重载函数的版本。

    名称修饰,根据函数类型中指定的形参类型对每个函数名进行加密。

    //未经修饰的函数原型
    long MyFunctionFoo(int, float);
    //修饰后的函数原型---编译器内部
    ?MyFunctionFoo@@YAXH
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    对原始名称进行的表面看来无意义的修饰将对函数参数和类型进行编码,添加的一组符号随函数的参数而异,修饰时使用的约定随编译器而异。

    7.15.1.3 模糊调用

    就是当调用函数时,实参的类型和各重载函数的参数列表类型不同时,C++会使用强制类型转换的方法,这样可能会匹配多个重载函数,从而出现模糊调用的问题。因此,当你使用重载函数时,你需要确保你在函数调用中使用了正确的参数类型。

    7.15.1.4 重载引用参数

    有些看起来不同的参数列表也不被允许使用重载函数

    //这两个就是不被允许的,由于两者在调用cude(x)编译时,编译器无法区分,因此编译器认为变量和相对于的引用变量是相同的。
    double cube(double x);
    double cube(double & x);
    
    • 1
    • 2
    • 3

    左值引用与右值引用:

    void sink(double & r1); //满足左值引用
    void sank(const double & r2); //匹配可修改的或左值或右值(右值的话要生成临时变量)
    void sunk(double && r3); //匹配右值引用
    
    Note how r2 can match the same sort of arguments that r1 and r3 match. This raises the 
    question of what happens when you overload a function on these three types of parameters. 
    The answer is that the more exact match is made.
        
    void staff(double & rs); // matches modifiable lvalue
    voit staff(const double & rcs); // matches rvalue, const lvalue
    void stove(double & r1); // matches modifiable lvalue
    void stove(const double & r2); // matches const lvalue
    void stove(double && r3); // matches rvalue
    
    double x = 55.5;
    const double y = 32.0;
    stove(x); // calls stove(double &)
    stove(y); // calls stove(const double &)
    stove(x+y); // calls stove(double &&)
    If, say, you omit the stove(double &&) function, then stove(x+y) will call the
    stove(const double &) function instead.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    函数重载区分常量和非常量:

    void dribble(char * bits); // overloaded
    void dribble (const char *cbits); // overloaded
    void dabble(char * bits); // not overloaded
    void drivel(const char * bits); // not overloaded
    
    const char p1[20] = "How's the weather?";
    char p2[20] = "How's business?";
    dribble(p1); // dribble(const char *);
    dribble(p2); // dribble(char *);
    dabble(p1); // no match
    dabble(p2); // dabble(char *);
    drivel(p1); // drivel(const char *);
    drivel(p2); // drivel(const char *);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    7.15.2 代码举例

    Function_Overloading.h

    #pragma once
    #ifndef _FUNCTION_OVERLOADING_H_
    #define _FUNCTION_OVERLOADING_H_
    #include
    using std::string;
    using std::cout;
    using std::endl;
    unsigned long left(unsigned long num, unsigned ct);
    char* left(const char* str, int n = 1);
    
    //返回数字num的左ct位数字
    unsigned long left(unsigned long num, unsigned ct)
    {
        unsigned digits = 1;
        unsigned long n = num;
        if (ct == 0 || num == 0)
            return 0; // return 0 if no digits
        while (n /= 10)
            digits++;//数字num有多少位
        if (digits > ct)
        {
            ct = digits - ct;
            while (ct--)
                num /= 10;
            return num; //返回num的左ct位数字
        }
        else //如果ct >= digits
            return num; //返回整个数字
    }
    //返回str的前n位组成的字符串
    char* left(const char* str, int n)
    {
        if (n < 0)
            n = 0;
        int m = 0;
        while (m <= n && str[m] != '\0')
            m++;
        char* p = new char[m + 1];//此处是为了减少分配的存储空间,因为传递来的字符串长度可能小于n
        int i;
        for (i = 0; i < m; i++)
            p[i] = str[i]; // copy characters
        p[m] = '\0'; //将最后一位设置为'\0'
        return p;
    }
    
    void function_overloading(void)
    {
        cout << "function_overloading Hello********************************" << endl;
        const char* trip = "Hawaii!!"; // test value
        unsigned long n = 12345678; // test value
        int i;
        char* temp;
        for (i = 1; i < 10; i++)
        {
            cout << left(n, i) << endl;
            temp = left(trip, i);
            cout << temp << endl;
            delete[] temp; // point to temporary storage
        }
        cout << "function_overloading Bye*********************************" << endl;
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    main.cpp

    /*
    Project name :			_27Functions
    Last modified Date:		2022年5月7日16点05分
    Last Version:			V1.0
    Descriptions:			函数
    */
    #include "Function_Overloading.h"
    
    int main()
    {
    	using namespace std;
    	cout << "函数重载********************************************************" << endl;
    	function_overloading();
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    7.15.3 运行结果

    函数重载********************************************************
    function_overloading Hello********************************
    1
    Ha
    12
    Haw
    123
    Hawa
    1234
    Hawai
    12345
    Hawaii
    123456
    Hawaii!
    1234567
    Hawaii!!
    12345678
    Hawaii!!
    12345678
    Hawaii!!
    function_overloading Bye*********************************
    
    D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 19532)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    7.16 函数模板

    见C++ template。

    7.17 可变参数模板

    可变参数模板让程序员能够创建 可接受可变数量的参数 的模板函数和模板类。

    7.17.1 模板和函数参数包

    C++11提供了一个用省略号表示的元运算符(meta-operator),让程序员能够声明表示模板参数包的标识符,模板参数包实际上是一个类型列表。通用,它还让程序员能够声明表示函数参数包的标识符,而函数参数包基本上时一个值列表。

    template<typename... Args> // Args is a template parameter pack
    void show_list1(Args... args) // args is a function parameter pack
    {
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Args是一个模板参数包,而args是一个函数参数包。与其他参数一样,可将这些参数包的名称指定为任何复合C++标识符规则的名称。Args与T的区别在于,T与一种类型匹配,而Args与任意数量(包括零)的类型匹配。

    函数参数包args包含的值列表和模板参数包Args包含的类型列表匹配——无论是类型还是数量。

    7.17.2 展开参数包

    函数如何访问函数和模板参数包的内容?索引功能不适用。可将省略号放在函数参数包的右边,将参数包展开。但是它存在缺陷?

    template<typename... Args> // Args is a template parameter pack
    void show_list1(Args... args) // args is a function parameter pack
    {
    	show_list1(args...); // passes unpacked args to show_list1()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    表示法args…展开为一个函数参数列表,该函数调用与原始函数调用相同,因此它将适用相同的参数不断调用自己,导致无限递归。

    7.17.3 在可变参数模板中使用递归

    将函数参数包展开,对列表中的第一项进行处理,再将余下的内容传递给递归调用,依此类推,直到列表为空。

    template<typename T, typename... Args>
    void show_list3(T value, Args... args)
    
    • 1
    • 2

    7.17.4 举例

    代码

    /*
    Project name :			_37Variadic_Templates
    Last modified Date:		2022年5月24日11点36分
    Last Version:			V1.0
    Descriptions:			可变参数模板
    */
    #include 
    #include 
    // definition for 0 parameters
    void show_list() {}
    // definition for 1 parameter
    template<typename T>
    void show_list(const T& value)
    {
    	std::cout << value << '\n';
    }
    
    // definition for 2 or more parameters
    template<typename T, typename... Args>
    void show_list(const T& value, const Args&... args)
    {
    	std::cout << value << ", ";
    	show_list(args...);
    }
    int main()
    {
    	int n = 14;
    	double x = 2.71828;
    	std::string mr = "Mr. String objects!";
    	show_list(n, x);
    	show_list(x * x, '!', 7, mr);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    运行结果

    14, 2.71828
    7.38905, !, 7, Mr. String objects!
    
    D:\Prj\_C++Self\_37Variadic_Templates\x64\Debug\_37Variadic_Templates.exe (进程 14728)已退出,代码为 0。
    要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
    按任意键关闭此窗口. . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    README

    此为本人读C++ Primer总结的笔记,如有错误或知识缺口,请在评论区告知。如本文有在实践中帮到您,是本人的荣幸。

  • 相关阅读:
    GGTalk 开源即时通讯系统源码剖析之:服务端全局缓存
    C语言之练习题
    asp读取sqlserver2019返回的json
    动手学深度学习——第五次学
    3i平台体验性能加持,13600KF+B760M+撼与科技A770 TITAN装机体验
    【亲妈教学】配置Gzip压缩,含前后端步骤
    python爬虫+django新闻推荐系统可视化分析
    FlinkSql中的聚合查询
    python中的logging的使用
    自定义线程池拒绝策略
  • 原文地址:https://blog.csdn.net/weixin_44410704/article/details/127792883