+ 1.函数定义
+ 2.函数原型
+ 3.调用函数
库函数是已经定义和编译好的函数
void functionName(parameterList)
{
statement(s)
return; // optional
}
//parameterList指定传递给函数的参数类型和数量;return;可选返回语句标记了函数的结尾,否则函数将在右花括号处结束
typeName functionName(parameterList)
{
statements
return value; // value is type cast to type typeName
}
将值返回给调用函数,值可以是常量、变量、表达式,其结果必须是typeName类型或可以被转换为typeName;函数将转换后的值返回给函数。
函数返回值的过程:在函数执行到return语句(返回函数)时,将返回值复制到指定的CPU寄存器或内存单元中;随后,调用函数查看该内存单元;要求返回函数和调用函数必须就该内存单元中存储的数据类型达成一致。
注意事项:
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
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;
}
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;
}
函数定义*************************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
函数原型将函数返回值的类型以及参数的类型和数量告诉编译器。
编译器也可以通过函数定义知道这些信息,但是这样效率很低。(也可以将函数定义在使用该函数之前,但是程序员喜欢将main()函数放在最前面,因为main()显示了整个程序的框架)
函数头+分号
极大地降低程序出错的几率,原型确保以下几点
静态类型检查(static type checking):在编译阶段进行的原型化,静态类型检查可捕获许多运行阶段非常难以捕获的错误
将数值参数传递给函数,函数将其赋值给一个新的变量。原始数据表示实参(argument),复制数据表示形参(parameter)。形参变化不影响实参。
在函数中声明的变量,函数执行时;计算机为其分配内存,函数结束时,计算机释放其内存。局部变量有助于保证数据的完整性,因为函数的局部变量在其他函数中不能使用。局部变量也称自动变量,因为他们是在程序执行过程中自动被分配和释放的。
void fifi(float a, float b) // declare each variable separately
void fufu(float a, b) // NOT acceptable
传递常规变量时,将使用值传递,函数使用常规变量的拷贝;但传递数组时,函数将使用原来的数组。
int sum_arr(int arr[], int n) // arr = array name, n = size
上面这个函数原型说明,如果将一个数组名(数组的位置,包含的元素种类)传递给arr,则arr指向数组的第一个元素并且可以访问原数组的元素;这种方式比使用值传递提高了执行速度,但是,容易不小心修改了数组中的元素。
1.方法1 输入参数两个,一个是数组的首地址,另一个是数组的长度
int sum_arr(int arr[], int n);
2.方法2 输入参数两个,一个是数组的首地址,另一个是数组的末尾地址+1
int sum_arr(const int * begin, const int * end);
为什么不使用sizeof(arr)来确定数组的长度呢?原因是arr本身是一个指针,sizeof(arr)得到的是指针的大小而不是数组的大小,所以为了函数适用于各个长度的数组,需要传递数组的长度参数
int sum_arr(const int arr[], int n) // arr = array name, n = size
给指针arr定义为const类型,则在函数中不能使用它修改它指向的数组的值.
//此处不能使用const,因为const不适用于二级指针
int sum(int ar2[][4], int size);
int sum(int (*ar2)[4], int size);//这两个的含义是一样的
ar2[r][c] == *(*(ar2 + r) + c) // same thing
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
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;
}
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;
}
函数与二维数组*******************************************************
sumdata = 60
D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 17852)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
unsigned int c_in_str(const char str[], char ch);
unsigned int c_in_str(const char* str, char ch);
要将数组作为输出参数时,不允许输出在函数中定义的普通数组,因为在函数中定义的数组是临时变量,在函数调用结束时会释放其存储空间,再次访问时会出现问题。而应当在函数中定义new数组,这样系统不会自动释放数组存储空间。
char* buildstr(char c, int n);//此函数中使用了动态内存分配,分配内存的首地址返回
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
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;
}
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;
}
函数与字符串*********************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
结构体可以直接作为输入、输出参数,因为结构体相当于是一个独立的数据类型。
当结构体元素较多时,程序员倾向于使用按引用传递而不是按值传递,因为这样可以加快程序运行时间。
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
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";
}
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
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);
}
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;
}
函数与结构体*********************************************************
时间结构体***************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
将字符串类当作独立的类型即可(如int,char等等)。
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
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类看作是独立的数据类型即可
}
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;
}
函数与字符串类*******************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
给函数传递指针时,可能需要更改指针所指对象元素的值,或者是为了节省运行时间。
直接给函数传递对象时,不会更改原始对象元素的值。
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
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);
}
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;
}
函数与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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
函数地址就是存储其机器语言代码的内存的开始地址。
一定要区分传递的是函数地址还是函数返回值。
//如果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.定义指针
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函数
有两种方式,并且存在争议,但是都是合法的。
double pam(int);//函数原型
double (*pf)(int);//定义函数指针
pf = pam; //pf函数指针指向函数pam地址
double x = pam(4); //使用函数名调用函数
double y = (*pf)(5); //使用函数指针调用函数
//也可以直接这样使用
double y = pf(5); //使用函数指针调用函数
在这个代码下,estimate()函数可以调用不同的函数执行不同的操作(前提是调用的函数的参数和返回值一致)。
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
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;
}
函数指针简单应用***********************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
就扯来扯去还是指针的问题,就各种指针的指针哈哈哈。
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
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;
}
函数指针数组应用***********************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
//这样用也是可以的,就很快乐哈哈哈哈
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
编译过程的最终产品是可执行程序(由一组机器怨言指令组成)。在程序编译时,CPU会为代码分配特定的存储空间,但不存储普通函数指令,调用普通函数就是跳到相应的存储位置执行指令,然后再跳回程序之前跳转的位置执行指令;内联函数就是在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方,调用内联函数时不用再跳来跳去,可以缩短程序执行时间,但是增加了系统存储压力。如果程序再10个不同的地方调用同一个内联函数,则该程序将包含该函数代码的10个副本。
应该有选择地使用内联函数。如果执行函数代码的时间比处理函数调用机制的时间长,则节省的时间将只占整个过程的很小一部分。如果代码执行时间很短,则内联调用就可以节省非内联调用使用的大部分时间。所以,如果函数不是两三句能描述完,就不建议写成内联函数。
函数过大或递归函数时,程序不允许将该函数写成内联函数。

使用C语言的宏执行了类似函数的功能,应考虑将他们转换为C++内联函数。
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
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;
}
内联函数********************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
引用变量定义:时已定义的变量的别名。
引用变量的作用:主要用途时用作函数的形参,将引用变量用作参数,函数将使用原始数据,而不是其副本。
int rats;
int & rodents = rats; //创建一个引用变量并成为rats的别名,此处的&表示引用变量
cout <<", rodents address = " << &rodents << endl;//此处的&表示地址
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
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;
}
可以观察到变量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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
必须在声明引用时将其初始化,而不能像指针一样先声明后赋值。
//这种方式是正确的
int rats = 101;
int & rodents = rats; // rodents a reference
//下面这种方式就是错误的
int rat;
int & rodent;
rodent = rat; //会报错
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
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;
}
引用变量********************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
引用变量被用作函数参数,使得函数中的变量名成为调用程序中变量的别名,这种传递参数的方法叫做按引用传递。
值传递、引用传递二者的区别如下:


交换两数字变量的值的三种方法对比,事实证明值传递无法交换两数字变量的值,但引用方式传递和指针可以交换两数字变量的值。
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
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;
}
引用变量********************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
对于使用传递的值而不作修改的函数:
对于修改调用函数中数据的函数:
不允许引用右值。
//如果是值传递,那么下面的调用方式都是允许的
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是一个临时变量
什么是左值和右值?
什么时候创建临时变量?前提是参数为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
临时变量生命周期:只在函数调用期间存在,此后编译器便可随意将其删除。
什么使用使用临时变量?
在不修改实参的情况下可以使用临时变量,但是在需要修改实参的情况下不能使用临时变量,因为临时变量会阻止修改实参。
如果参数是基本数值类型并且不需要改变实参的值,建议不使用按引用传递的方式。如果参数是结构体、对象等需要占用大空间的输入参数,可以使用引用传递,但是在不改变实参的值时,建议使用const类型形参以保护实参不被修改。
double refcube(const double &ra);
使用const有如下好处:
不要返回一个指向临时变量的引用,因为临时变量在函数执行完毕后将不复存在;避免返回临时变量的方法是:
如果使用引用变量,那么一定要注意和引用变量相关的赋值语句会改变真实变量的值。
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
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;
}
引用变量********************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
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
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;
}
引用变量********************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
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
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;
}
引用变量********************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
默认参数就是当函数调用中省略了实参时自动使用的值。
如何设置默认值?必须通过函数原型设置默认值,函数定义还是和普通函数定义一样没有默认值。
char * left(const char * str, int n = 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
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
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;
}
默认参数********************************************************
default_argument Hello********************************
Enter a string:
Jasmine
Jasm
J
default_argument Bye*********************************
D:\Prj\_C++Self\_27Functions\Debug\_27Functions.exe (进程 16692)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
输入参数列表不同。
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 这是允许的
C++根据上下文来确定重载函数的版本。
名称修饰,根据函数类型中指定的形参类型对每个函数名进行加密。
//未经修饰的函数原型
long MyFunctionFoo(int, float);
//修饰后的函数原型---编译器内部
?MyFunctionFoo@@YAXH
对原始名称进行的表面看来无意义的修饰将对函数参数和类型进行编码,添加的一组符号随函数的参数而异,修饰时使用的约定随编译器而异。
就是当调用函数时,实参的类型和各重载函数的参数列表类型不同时,C++会使用强制类型转换的方法,这样可能会匹配多个重载函数,从而出现模糊调用的问题。因此,当你使用重载函数时,你需要确保你在函数调用中使用了正确的参数类型。
有些看起来不同的参数列表也不被允许使用重载函数
//这两个就是不被允许的,由于两者在调用cude(x)编译时,编译器无法区分,因此编译器认为变量和相对于的引用变量是相同的。
double cube(double x);
double cube(double & x);
左值引用与右值引用:
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.
函数重载区分常量和非常量:
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 *);
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
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;
}
函数重载********************************************************
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。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
见C++ template。
可变参数模板让程序员能够创建 可接受可变数量的参数 的模板函数和模板类。
C++11提供了一个用省略号表示的元运算符(meta-operator),让程序员能够声明表示模板参数包的标识符,模板参数包实际上是一个类型列表。通用,它还让程序员能够声明表示函数参数包的标识符,而函数参数包基本上时一个值列表。
template<typename... Args> // Args is a template parameter pack
void show_list1(Args... args) // args is a function parameter pack
{
...
}
Args是一个模板参数包,而args是一个函数参数包。与其他参数一样,可将这些参数包的名称指定为任何复合C++标识符规则的名称。Args与T的区别在于,T与一种类型匹配,而Args与任意数量(包括零)的类型匹配。
函数参数包args包含的值列表和模板参数包Args包含的类型列表匹配——无论是类型还是数量。
函数如何访问函数和模板参数包的内容?索引功能不适用。可将省略号放在函数参数包的右边,将参数包展开。但是它存在缺陷?
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()
}
表示法args…展开为一个函数参数列表,该函数调用与原始函数调用相同,因此它将适用相同的参数不断调用自己,导致无限递归。
将函数参数包展开,对列表中的第一项进行处理,再将余下的内容传递给递归调用,依此类推,直到列表为空。
template<typename T, typename... Args>
void show_list3(T value, Args... args)
代码
/*
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;
}
运行结果
14, 2.71828
7.38905, !, 7, Mr. String objects!
D:\Prj\_C++Self\_37Variadic_Templates\x64\Debug\_37Variadic_Templates.exe (进程 14728)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .
此为本人读C++ Primer总结的笔记,如有错误或知识缺口,请在评论区告知。如本文有在实践中帮到您,是本人的荣幸。