• cpp primer plus笔记06-函数


    1. 函数的声明和定义都可以没有变量名
      #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
    2. 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);//等于(*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
      
      • 1
      • 2
      • 3
      • 4
    3. 下面代码块有关函数指针的声明中*pf(int)意味着pf()是一个返回指针的函数,而(*pf)(int)意味着pf是一个指向函数的指针。
      double (*pf)(int);
      double *pf(int);
      
      • 1
      • 2
    4. 函数指针可以创建数组:
      #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
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
    5. 使用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
    6. 引用变量必须在声明时进行初始化。
    7. 在函数参数传递中,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
    8. 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;//ok
      	std::cout << Func2(x + 2) << std::endl;//should not compile,don`t do it!
      	return 0;
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    9. 函数返回值可以是引用变量,这样就不会把数据复制到一个新的临时的位置,效率会更高,但是引用变量尽量返回函数参数的的变量,引用尽量是自定义数据结构这种复杂的数据结构,而且返回值如果是引用类型尽量加const修饰。
    10. 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
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
    11. 模板使用的时候会产生一些无法具体化解决的限制,例如无法在没有运算符重载的情况下进行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
    12. 对于重载函数的选择,编译器倾向于优先选择非模板函数,如果没有非模板函数,则倾向于选择从类型等各方面来说相对具体的函数,如果没有一个函数比其他函数更具体,或者没有与之相匹配的函数,则会产生错误,但是向下面的情况(第二行),编译器会倾向于选择模板函数,而不是非模板函数。
      less(m,n);
      less<>(m,n);
      
      • 1
      • 2
    13. 针对于多个不同类型模板的数据相互作用产生新的模板的数据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
      
      • 1
      • 2
  • 相关阅读:
    漏刻有时数据可视化Echarts组件开发(42)渐变色的应用
    信息学奥赛一本通 1262:【例9.6】挖地雷 动态规划基本型
    如何在2.2.1版Aduino IDE中开发ESP32
    SHELL中sed总结
    【人工智能】强化学习笔记(持续更新)
    Playwright 组件测试入门
    英国增加了新的化合物半导体集群
    JMeter 安装教程(详细安装教程)
    使用ADS进行serdes仿真时,Tx_Diff中EQ的设置对发送端波形的影响。
    『LeetCode|每日一题』---->最小路径和
  • 原文地址:https://blog.csdn.net/LEVIATHANq/article/details/133648640