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;
    }
    
  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;
    }
    
    
    3
    5
    10
    10
    
  3. 下面代码块有关函数指针的声明中*pf(int)意味着pf()是一个返回指针的函数,而(*pf)(int)意味着pf是一个指向函数的指针。
    double (*pf)(int);
    double *pf(int);
    
  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;
    }
    
    
    4 5
    9
    20
    -1
    
    
  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;
    	}
    
  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;
    }
    
    
  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 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
    
    
  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;
    }
    
    
  12. 对于重载函数的选择,编译器倾向于优先选择非模板函数,如果没有非模板函数,则倾向于选择从类型等各方面来说相对具体的函数,如果没有一个函数比其他函数更具体,或者没有与之相匹配的函数,则会产生错误,但是向下面的情况(第二行),编译器会倾向于选择模板函数,而不是非模板函数。
    less(m,n);
    less<>(m,n);
    
  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;
    }
    
    10.5 10.5
    5 15.5 52.5 -5.5 20.5 15.5 -5.5 20.5
    

你可能感兴趣的:(c++,笔记,c++)