重载解析
"重载解析" 是编译器从多个同名函数中,选择与当前调用最匹配的函数的过程 。是C++函数重载的核心机制。
-
创建函数列表:其中包含与被调函数名称相同的函数和模板函数。
-
筛选可行函数:使用候选函数列表创建可行函数列表。这些都是参数数目正确的函数,且实参类型能通过 C++ 允许的隐式转换,变成形参类型。
-
确定是否有最佳的可行函数。有则调用无则报错。
优先级从高到低如下
-
完全匹配(常规函数优先于模板)
-
提升转换(例如:char和short自动转换为int,float自动转换为double)(不会出现数据溢出和精度丢失)
-
标准转换(例如:int转换为char,long转换为double)(可能会出现数据溢出和精度丢失)
-
用户自定义转换(例如:类声明中定义的转换)
-
如果最高优先级的函数是多个,必然会二义性报错。(提升转换和标准转换同级之间转换参数越少优先级越高)
#include <iostream>
using namespace std;
// 函数A:3个参数,调用时需3次提升转换(char→int、float→double、short→int)
void func(int a, double b, int c) {
cout << "func(int, double, int)(3次提升转换)" << endl;
}
// 函数B:3个参数,调用时需2次提升转换(char→int、float→double,第三个参数完全匹配)
void func(int a, double b, short c) { // 第三个参数是short
cout << "func(int, double, short)(2次提升转换)" << endl;
}
int main() {
char a = 'a';
float b = 3.14f;
short c = 10; // 第三个实参是short
func(a, b, c); // B提升转化2次,A3次。调用函数B
//func(c,b,a);//AB均提升转换3次,二义性错误
return 0;
}
自定义转换
通过 static_cast 等显式转换,获得同数据大小不同数据类型的数据,使得新数据与目标函数的匹配度最高。
void customSelect(char a, float b, short c);//A函数
void customSelect(int a, double b, int c); //B函数
...
char a = 'a';
float b = 3.14f;
short c = 10;
customSelect(a, b, c);//按优先级来看与A更匹配
int a2 = static_cast<int>(a); // char→int(提升)
double b2 = static_cast<double>(b); // float→double(提升)
customSelect(a2, b2, c);//B函数提升转换,A函数标准转换,提升转换优先级高
...
内存模型和名称空间
单独编译
通常一个程序可以分为三部分。
-
头文件:包含结构声明和使用这些结构的函数的原型。
-
源代码文件:包含与结构有关的函数的代码。
-
源代码文件:包含调用与结构相关的函数的代码。
不要将函数定义或者变量声明放到头文件中。
头文件中一般包含
-
函数原型
-
使用#define或是const定义的符号常量。
-
结构声明
-
类声明
-
模板声明
-
内联函数
如果头文件名包含在尖括号里面,编译器会去存储标准头文件的文件系统里面找,如果头文件名包含在双引号里面,编译器会去当前工作目录的源代码目录里面找,如果没有找到,则在标准位置找。自己编写的头文件要使用引号而不是尖括号。
如果同一个头文件(比如coordin.h)被多次#include到同一个源文件中,会导致重复定义错误(比如结构体、宏被定义两次),编译会报错。
// 无保护的头文件 test.h
void func() { cout << "test" << endl; }
// main.cpp
#include "test.h"
#include "test.h" // 第二次包含,触发“重定义错误”
int main() { func(); return 0; }
解决方法:
-
在头文件开头写
#ifndef 标识符,意为如果这个标识符没被定义过。 -
紧接着写
#define 标识符,意为定义这个标识符。 -
把头文件的实际内容写在这两行下面。
-
后写
#endif(结束条件判断)。
//编写头文件"coordin.h"
#ifndef COORDIN_H //检查COORDIN_H是否被定义
#define COORDIN_H //定义COORDIN_H
//头文件内容
struct rect
{
double x;
double y;
};
// 极坐标结构体
struct polar
{
double distance;
double ang;
};
polar rect_to_polar(rect xypos);// 声明坐标转换函数(对外暴露接口)
#endif //结束#ifndef判断
#include "coordin.h"
#include <cmath>
#include <iostream>
polar rect_to_polar( rect xypos)
{
using namespace std;
polar answer;
answer.distance = sqrt( xypos.x * xypos.x + xypos.y * xypos.y );
answer.ang = atan2( xypos.y,xypos.x );
return answer;
}
atan2(y,x)函数返回弧度制的辐角。使用需包含<cmath> 头文件