C++小知识点(一)------C++ primer plus中文版(第六版)

C++小知识点(一)------C++ primer plus中文版(第六版),第1张

1、内联函数

用相应的函数代码替换函数调用。
优点:运行速度更快;
缺点:代价是占有更多内存。调用函数结束之后会释放,而内联函数不会,将一直占据内存。
因此:函数代码较少时,优先选择内联函数。

使用方法:函数声明或者函数定义前加上关键字inline,通常做法是省略函数原型(声明),将整个定义放在原本提供原型的地方。
inline int sum(int a,int b)
{
	return a+b;
}

定义位于类声明中的函数都将自动成为内联函数,无须inline标识。

2、引用

2.1、什么是引用
引用变量:是一种特殊的变量,被认为是一个变量的别名,因此引用并不分配独立的内存空间,它与目标变量公用其内存空间。
引用的声明方法:类型标识符 &引用名 = 目标变量名(该变量可以在栈区或者堆区,但不能是常量区数据);

注意:引用必须初始化,初始化之后不可更改!!!!
1、&在此不是求地址运算,而是起标识作用。
2、引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名,以免造成混淆。
3、不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名

int value1 = 100;
int &ref = value1;
int temp = 50;
ref = temp;			//因为ref是value1的别名,因此此语句相当于:value1 = temp;

引用的本质:指针常量
上述等价于:int * const ref = &value1;

2.2、引用的主要用途
引用变量的主要用途是用作函数的形参,为处理大型结构提供方便的途径。

1、	最经典的就是交换数值,类似于指针传递
	void swap ( int& x,int& y )
	{     
	    int temp;  
	    temp=x;
	    x=y;
	    y=temp;
	}
	这种情况下会修改原始值原始值。

2、	希望程序传递参数信息,但是不进行修改,可以使用常量引用
	int func(const int &temp);
	如果在函数中修改了temp,会产生报错信息

3、	引用是变量的别名,不可以将常量做参数
	double ref_fun1(double &ra)					//但是如果加上const,C++才允许这样做
	{
		return ra * ra;
	}
	double ref_fun2(const double &ra)			//但是如果加上const,C++才允许这样做
	{
		return ra * ra;
	}
	int main()
	{
		using namespace std;
		double x = 3.0;
		cout << ref_fun1(x) << endl;			//允许
		cout << ref_fun1(x+3.0) << endl;		//不允许
		cout << ref_fun2(x+3.0) << endl;		//允许,此时传递给ref_fun2是常量,符合const double&
		return 0;
	}

2.3、引用做函数返回值

使得函数返回的是对象,而不是拷贝值

1、	不要返回临时变量(局部变量)的引用:因为局部变量在函数调用结束后消亡
	int &func(void)
	{
		int s_temp = 10;
		return s_temp;
	}
	int main() {
	int &ref = test01();
	cout << ref << endl;			//输出10
	cout << ref << endl;			//输出乱码值

2、	解决方法:返回一个作为参数传递给函数的引用
	int &func(int & target,const int & source)
	{
		target = source
		return target;
	}

3//如果函数做左值,那么必须返回引用
	int &func()
	{
		static int temp = 100;
		return temp;
	}
	int main()
	{
		int &ref = func();
		cout << ref << endl;			//输出100
		func() = 1000;
		cout << ref << endl;			//输出1000
	}
3、函数高级用法

3.1、默认参数

函数调用中省略实参时,自动使用的一个值,即形参列表中可以有默认值。

1、	语法:返回值类型 函数名(参数 = 默认值);		//默认值添加从右到左
eg: int func(int a, int b = 10, int c = 20)
	{
		return a+b;
	}
	//函数调用
	cout << func(10) << endl;			//输出40
	cout << func(10,20) << endl;		//输出50
	cout << func(10,20,30) << endl;		//输出60
	
2、上述函数直接放在主函数前,直接调用,若将函数声明和函数定义分开,则函数声明有默认值,函数定义就不能有默认值
	int func(int a, int b = 10, int c = 20);		//函数声明
	func(10,20,30);									//函数调用
	int func(int a, int b, int c)					//函数定义
	{
		return a+b;
	}

3.2、函数重载

与函数默认值的区别:
默认参数:使用不同数目的参数调用同一个函数;
函数重载:能够使用多个同名的函数,提高复用性;

C++根据上下文来确定使用函数重载的版本

函数重载满足的条件:
* 1、同一个作用域下
* 2、函数名称相同
* 3、函数参数:类型不同、个数不同、顺序不同(函数特征标,而不是变量名)

注意事项

1、	类型引用和类型本身视为同一个特征标
	int func(int a);
	int func(int &a);
	cout << func(b) << endl;			
	编译器无法区分上述两个函数
	
2、	区分const和非const变量
	版本一:
	void func_str(char *str)					函数一
	void func_str(const char *str)				函数二
	char p1[] = "We are Chinese";
	const char p2[] = "I'm from Hubei";
	func_str(p1);								调用函数一
	func_str(p2);								调用函数二

	版本二:
	void func(int temp);						函数三
	void func(const int temp);					函数四
	int a = 10;
	func(a);									调用函数三	
	func(20);									调用函数四
	
3、	函数返回值类型不作为重载的条件
	void func(double a ,int b)
	{
		cout << "func (double a ,int b)的调用!" << endl;
	}
	double func(double a ,int b)
	{
		cout << "double func (double a ,int b)的调用!" << endl;
		return a+b;
	}
	编译器无法区分仅按返回值类型区分的函数;

	4、函数重载遇到默认参数
	void func2(int a, int b = 10)
	{
		cout << "func2(int a, int b = 10) 调用" << endl;
	}
	void func2(int a)
	{
		cout << "func2(int a) 调用" << endl;
	}
	func2(20);									产生歧义,需要避免

3.3、函数模板

1、什么时候使用函数模板?
需要使用多个不同类型的同一种算法时,使用模板更好。(函数模板建议放在头文件中,使得多个文件可以使用该模板)

2、什么是函数模板?
函数模板是通用的函数描述,使用泛型来定义函数,其中的泛型可以使用具体的类型进行替换。
允许以任意类型的方式来定义函数,

3、具体语法:

template <typename Anytype>				//后面没有分号;
/*其中template 和 typename 是必须的,且template可以使用class替换*/
void func(Anytype par1, Anytype par2)
{
	//operation
	函数模板不创建任何函数,只是告诉编译器如何定义函数,编译器根据传入的类型再去创建相应的函数实体
}

4、具体实例:

交换两个数值
template <typename Anytype>	
void Swap(Anytype &par1, Anytype &par2)
{
	Anytype temp;
	temp = par1;
	par1 = par2;
	par2 = temp;
}
int main()
{
	int a = 10,b = 20;
	Swap(a,b);
}

5、小知识点:函数模板的模板参数并非必须是模板参数类型

template <typename Anytype>	
void func(Anytype par1, Anytype par2, int m)		这里的m就是指定int类型,而不是Anytype
{
	//operation
	函数模板不创建任何函数,只是告诉编译器如何定义函数,编译器根据传入的类型再去创建相应的函数实体
}

3.4、函数模板重载

1、为什么需要函数模板重载?
需要对多个不同类型使用不同算法时,可以使用函数模板重载,和函数重载条件一样,被重载的模板特征标必须不同。

template <typename Anytype>	
void Swap(Anytype &par1, Anytype &par2)
{
	Anytype temp;
	temp = par1;
	par1 = par2;
	par2 = temp;
}

template <typename Anytype>	
void Swap(Anytype par1[], Anytype par2[], int m)
{
	Anytype temp;
	for(int i=0;i<m;i++)
	{
		temp = par1[i];
		par1 = par2[i];
		par2 = temp;
	}
}

3.5、函数模板局限性

函数模板不是万能的,很有可能无法处理某些类型(比如数组赋值,结构比大小等等),这需要我们
1、事先定义好,以免产生歧义
2、为特定类型提供具体化的模板定义,也叫显示具体化

显示具体化相关标准如下:

1、对于给定的函数名,可以有非模板函数、模板函数和显式具体化模板函数以及它们的重载版本。
2、显式具体化的原型和定义应以 template<>打头,并通过名称来指出类型。
3、非模板函数 > 显示具体化 > 常规模板函数(优先级)

上述第二点中,名称是指:该类型名与定义的类型名要一致

举例:

1void Swap(int par1, int par2);											非模板函数
2template <typename Anytype>void Swap(Anytype &par1, Anytype &par2);		模板函数
3template <> void Swap<T_struct >(T_struct &par1, T_struct &par2);		显示具体化

struct T_struct
{
	string name;
	int age;
};

int main()
{
	int a = 10,b = 20;
	Swap(a,b);							调用非模板函数(如果没有非模板函数,调用模板函数)
	
	T_struct struct_a = { "fhl",26 };
	T_struct struct_b = { "xwy",24 };
	Swap(struct_a, struct_b);			调用显示具体化
}

3.6、函数模板实例化

1、什么是函数模板实例化?(分为隐式实例化和显示实例化)
隐式实例化:函数模板本身不会生成函数定义,但根据传入的特定类型会生成函数定义,得到的是模板实例;

template<typename Anytype> void Swap(Anytype &par1, Anytype &par2);

显示实例化:直接命令编译器创建特定的实例;用<>指示类型,声明前加上template

template void Swap<int>(int&par1, int&par2);

显示具体化

template<> void Swap<int>(int&par1, int&par2);
==(等价于)
template<> void Swap(int&par1, int&par2);

3.7、函数模板的使用

由上述可以看出,函数模板很灵活,可以自动匹配,但是如果想直接调用模板该怎么做呢?

template <typename Anytype> Anytype func(Anytype par1, Anytype par2)
{
	return (par1 > par2) ? par1 : par2;
}

int func(int a, int b)
{
	return a>b?a:b;
}

int main()
{
	int m = 10,n = 20;
	int result;
	result = func(m,n);					调用非函数模板(根据优先级)
	result = func<>(m,n);				调用函数模板,这里的<>指出编译器应该选择函数模板,而不是非模板函数
	return 0;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/707220.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-24
下一篇 2022-04-24

发表评论

登录后才能评论

评论列表(0条)

保存