- 函数的声明和定义都可以没有变量名
#include
#include
void n_chars(char, int)
{
printf("wer");
}
int func(int, int);
int main()
{
std::cout << func(1, 2) << std::endl;
n_chars('a', 1);
return 0;
}
int func(int a, int b)
{
return a + b;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- CPP函数指针类似于CS的委托:
#include
#include
int (*ptrFunc1)(int, int);
void (*ptrFunc2)(int, int);
double (*ptrFunc3)(int (*ptrFunc)(int, int), int, int);
int func1(int a, int b)
{
return a + b;
}
void func2(int a, int b)
{
std::cout << a + b << std::endl;
}
double fun3(int (*ptrFunc)(int, int),int num1,int num2)
{
return 2.0 * ptrFunc(num1, num2);
}
int main()
{
ptrFunc1 = func1;
std::cout << ptrFunc1(1, 2) << std::endl;
ptrFunc2 = func2;
ptrFunc2(2, 3);
ptrFunc3 = fun3;
std::cout << ptrFunc3(ptrFunc1, 2, 3);
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
3
5
10
10
- 下面代码块有关函数指针的声明中*pf(int)意味着pf()是一个返回指针的函数,而(*pf)(int)意味着pf是一个指向函数的指针。
double (*pf)(int);
double *pf(int);
- 函数指针可以创建数组:
#include
#include
const double CalAdd(double a, double b)
{
return a + b;
}
const double CalMutiply(double a, double b)
{
return a * b;
}
const double CalSubstract(double a, double b)
{
return a - b;
}
const double (*ptrForCalculate[3])(double, double) { CalAdd, CalMutiply, CalSubstract };
int main()
{
int a, b;
std::cin >> a >> b;
for (auto ptr : ptrForCalculate)
{
std::cout << ptr(a, b) << std::endl;
}
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
4 5
9
20
-1
- 使用typedef可以简化函数指针名字引用:
#include
#include
const double CalAdd(double a, double b)
{
return a + b;
}
const double CalMutiply(double a, double b)
{
return a * b;
}
const double CalSubstract(double a, double b)
{
return a - b;
}
typedef const double (*ptrForCal)(double, double);
int main()
{
ptrForCal ptrForAdd = CalAdd;
std::cout << ptrForAdd(2, 3) << std::endl;
ptrForCal ptrForMul = CalMutiply;
std::cout << ptrForMul(2, 3) << std::endl;
ptrForCal ptrForSub = CalSubstract;
std::cout << ptrForSub(2, 3) << std::endl;
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
- 引用变量必须在声明时进行初始化。
- 在函数参数传递中,
const int& a
和 const int a
在语义上是有区别的。
-
const int& a
是将参数 a
声明为一个常量引用。这意味着参数 a
是一个对传入的实参的引用,但不能通过 a
来修改实参的值。这种方式可以避免复制大对象的开销,并且保证了传入的实参不会被修改。 -
const int a
是将参数 a
声明为一个常量值。这意味着参数 a
是传入实参的一个副本,而不是对实参的引用。在函数中对 a
的修改不会影响原始的实参。 - 所以,
const int& a
和 const int a
的区别在于,前者是对实参的引用,后者是对实参的副本。选择哪种方式取决于具体的需求,如果需要避免复制大对象或者需要修改实参的值,可以使用 const int& a
,否则可以使用 const int a
。
- CPP不允许表达式函数传参时候传递给没有被const修饰的引用变量,CPP会在必要时将const引用参数声明为临时变量,(尽量在对象这种复杂的数据类型用const typename& n_elem)。
#include
#include
int Func1(const int &a, const int &b)
{
return a + b;
}
int Func2(int& a)
{
return 2 * a;
}
int main()
{
int x = 2;
std::cout << Func1(x + 2, x + 3) << std::endl;
std::cout << Func2(x + 2) << std::endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 函数返回值可以是引用变量,这样就不会把数据复制到一个新的临时的位置,效率会更高,但是引用变量尽量返回函数参数的的变量,引用尽量是自定义数据结构这种复杂的数据结构,而且返回值如果是引用类型尽量加const修饰。
- CPP可以使用模板来简化函数重载,当然模板也是可以重载的。
#include
template <typename T>
void swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
template <typename T>
void swap(T a[], T b[], int size)
{
T temp;
for (int i = 0; i < size; ++i)
{
temp = a[i];
a[i] = b[i];
b[i] = temp;
}
}
int main()
{
int a(0), b{ 1 };
swap<int>(a, b);
std::cout << a << " " << b << std::endl;
swap(a, b);
std::cout << a << " " << b << std::endl;
int arr[]{ 1,2,3,4,5 }, brr[]{ 10,9,8,7,6 };
for (auto iter : arr)
{
std::cout << iter << " ";
}
std::cout << std::endl;
for (auto iter : brr)
{
std::cout << iter << " ";
}
std::cout << std::endl;
swap<int>(arr, brr, 5);
for (auto iter : arr)
{
std::cout << iter << " ";
}
std::cout << std::endl;
for (auto iter : brr)
{
std::cout << iter << " ";
}
std::cout << std::endl;
swap(arr, brr, 5);
for (auto iter : arr)
{
std::cout << iter << " ";
}
std::cout << std::endl;
for (auto iter : brr)
{
std::cout << iter << " ";
}
std::cout << std::endl;
}
- 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
1 0
0 1
1 2 3 4 5
10 9 8 7 6
10 9 8 7 6
1 2 3 4 5
1 2 3 4 5
10 9 8 7 6
- 模板使用的时候会产生一些无法具体化解决的限制,例如无法在没有运算符重载的情况下进行a+b的处理,CPP提供了显式具体化的方法。
#include
#include
struct Vector3
{
double x;
double y;
double z;
};
template <typename T>
void Swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
template<>void Swap<Vector3>(Vector3& a, Vector3& b)
{
Swap(a.x, b.x);
Swap(a.y, b.y);
Swap(a.z, b.z);
}
int main()
{
Vector3 startPos{ 2.0,3.0,4.0 }, endPos{ 5.0,6.0,7.0 };
std::cout << startPos.x << " " << startPos.y << " " << startPos.z << std::endl;
std::cout << endPos.x << " " << endPos.y << " " << endPos.z << std::endl;
Swap(startPos, endPos);
std::cout << startPos.x << " " << startPos.y << " " << startPos.z << std::endl;
std::cout << endPos.x << " " << endPos.y << " " << endPos.z << std::endl;
}
- 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
- 对于重载函数的选择,编译器倾向于优先选择非模板函数,如果没有非模板函数,则倾向于选择从类型等各方面来说相对具体的函数,如果没有一个函数比其他函数更具体,或者没有与之相匹配的函数,则会产生错误,但是向下面的情况(第二行),编译器会倾向于选择模板函数,而不是非模板函数。
less(m,n);
less<>(m,n);
- 针对于多个不同类型模板的数据相互作用产生新的模板的数据CPP定义了decltype(expression) var,其核对数据的类型顺序如下:
- 如果expression是没有用括号括起来的标识符,则var的类型与该标识符类型相同,如num1。
- 如果expression是个函数调用,则var类型与函数返回值相同,如num2,num3,num4。
- 如果expression是一个左值,则var指向其引用,如num5。
- 如果前面的条件都不满足,则var类型与expression相同,如num6。
- 如果需要多次声明,则可以结合typedef和decltype使用,如num7。
- 如果需要使用函数可以想Add函数一样使用,其中auto类型会去设置为decltype(x+y)类型。
#include
template<typename T1,typename T2>
auto Add(T1 num1, T2 num2) -> decltype(num1 + num2)
{
return num1 + num2;
}
template<typename T1,typename T2>
auto Multiply(T1 num1, T2 num2) -> decltype(num1 * num2)
{
return num1 * num2;
}
template<typename T1, typename T2>
auto Substract(T1 num1, T2 num2) -> decltype(num1 - num2)
{
return num1 - num2;
}
int main()
{
int x = 5;
double y = 10.5;
decltype(x) num1 = x;
decltype(Add(x, y)) num2 = Add(x, y);
decltype(Multiply(x, y)) num3 = Multiply(x, y);
decltype(Substract(x, y)) num4 = Substract(x, y);
decltype((y)) num5 = y;
decltype(x + y) num6 = x + y;
typedef decltype(x + y) xpytype;
xpytype num7 = x - y;
std::cout << num5 << " " << y << std::endl;
num5 = 20.5;
std::cout << num1 << " " << num2 << " " << num3 << " " << num4 << " " << num5
<< " " << num6 << " " << num7 << " " << y << std::endl;
}
- 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
10.5 10.5
5 15.5 52.5 -5.5 20.5 15.5 -5.5 20.5