C++之引用&重载


1.引用(reference )的概念:
     引用是一个目标的别名;目标可以是变量或对象;
2.声明引用的符号为&,引用开始必须初始化;(将引用与一个目标进行绑定);
3.操作引用就是操作目标本身,反之亦然;
4.一个目标可以有多个引用;(就像一个人可以有多个别名一样)
5.一个引用不能同时绑定多个目标;
6.有指针的引用,例如:int *&t_p1 = t_p2;

7.没有数组的引用,没有void引用;但是可以有引用的数组

8.引用的类型必须和目标的类型一样;
9.常引用(const引用):作用不能通过const引用来修改被绑定目标的值;
int t_a = 200;
int t_b = 300;
const int &t_c = t_a;
//t_c = 400; is error , t_c read-only reference
  t_a = 400;

10.引用作为函数的参数的好处:减少拷贝,提高效率;

11.引用作为函数的返回值的好处:减少一次拷贝,提高效率;注意当函数的返回值为引用类型时,不要将一个临时变量返回出去;

12.内联函数:1~5行的代码量的小函数适合作为内联函数;原理就是代码替换
好处:提高代码的执行效率,以时间换空间;
内联函数的声明和定义必须放在一个文件里inline关键字是建议C++编译器将该函数搞为内联函数,但没有决定权;当函数里面有循环语句,复杂的条件语句,递归等,则C++编译器无视inline关键字,将该函数作为普通函数处理;

13.函数重载:满足函数重载的条件,有相同的函数名,不同的形参列表;与函数的返回值无关;如果该函数有默认参数,则重载该函数的时候,需要特别注意;

14.递归函数:自己调用自己的函数,注意必须要有退出函数的条件判断;

15.函数的默认参数:函数可以有自己的默认参数,例如int add(int t_a = 10,int t_b = 20,int t_c = 30, int t_d = 40);
如果这样调用add(),则参数全部用的是默认值10,20,30,40;
如果是这样调用add(50),则后面3个参数用默认的20,30,40,依次类推;注意我们给函数增加默认参数时,必须从右往左添加,例如int add(int t_a,int t_b,int t_c,int t_d = 10)是正确的,而int add(int t_a = 30,int t_b,int t_c,int t_d)是错误的,编译不过,因为当传递实参时,编译器会自左向右与形参进行匹配。例如add(1,2,3)这样传参的话,则t_a=1,t_b=2,t_c=3,那t_d就没有值了,那这种情况下就必须传递4个参数,而这样又违背了默认参数的初衷,初衷是可以传递3个参数的;所以编译器不允许程序员这么做,因为这么做函数默认参数就毫无意义了。

16.关于函数传参的总结:基本类型(int,char,double),枚举类型一般用值传递,结构/类的对象一般用引用或指针传递,数组类型一般用指针传递;

17.形参是引用传递时,一般将形参设置为const类型的引用,这样的好处是防止在函数中误操作,将实参的值修改了;




练习:
     
设计一个函数,函数的返回值为引用,返回两个字符串中长度最大的字符串;
const string& maxString(const string &t_str1, const string &t_str2)
{
    return t_str1.length() > t_str2.length()  ?  t_str1 : t_str2;
}



错误示例:
1.声明引用时没有初始化,在qt编译器下,有如下警报:

D:\QQPCmgr\Desktop\C++_Prj\Reference\main.cpp:10: 错误:'t_c' declared as reference but not initialized

在Linux下g++编译器的错误提示:
reference.cpp:9:7: error: ‘t_c’ declared as reference but not initialized


引用就是某一个变量的别名,引用的地址就是原变量的地址,引用的值就是原变量的值

不能建立引用的数组,例如:int & ref[3] = { 2, 3, 5}; //声明ref引用的数组是错误的

但是可以建立数组的引用:例如:int arr[3]; int (&tef)[3] = arr; //这是这是正确的

为什么数组中的元素不能是引用?

c++中,引用可以说只是某个变量的别名,所谓别名,是和指针类型区分开的:
     指针类型也可以指向某个变量,但指针类型本身也是一个变量,而引用实际上不是一个变量。更本质来说,可以理解为引用没有自身的地址,不占用内存空间(这里为了简化问题可以这样考虑)。因此,声明引用数组没有办法分配空间,因为根本就没有空间可以分配给引用。所以不能声明和定义引用数组



函数重载(overload):将语义,功能相似的几个函数用同一个名字来表示

易用性
构造函数需要重载机制,c++规定构造函数与类同名,且只能有一个名字

规则:
由函数接口(参数,返回值)区别重载函数,显然,返回值无法让编译器和程序员知道哪个函数被调用,因为c/c++中返回值有时可悲忽略!

假设某个c函数如下:

void foo(int x, int y);
     该函数在c编译器编译后在库中的名字为_foo,而c++编译器则会产生_foo_int_int之类的名字用来支持函数重载和类型安全连接。由于编译后的名字不同,故然c++不能直接调用c函数。
提供了一个c连接交换指定符号extern “C”

注意:
并不是两个函数的名字相同就构成函数重载,全局函数和成员函数同名不算重载,不在同一作用域!
全局函数被调用是要加上域作用符“::”

隐式类型转换会导致重载函数产生二义性


成员函数被重载的特征:
     1.相同的范围(在同一类中)
     2.函数名字相同
     3.参数不同
     4.virtual关键字可有可无

覆盖是指派生类函数覆盖基类函数,特征是:
1)不同的范围(分别位于派生类与基类);
2)函数名字相同;
3)参数相同;
4)基类函数必须有virtual 关键字。


代码示例:

//comdef.h(在include文件夹里,makefile中要包含路径)

#ifndef _COMDEF_H_
#define _COMDEF_H_

#ifdef _cplusplus
extern "C"
{
#endif

	extern void mySwap(int *a, int *b);

#ifdef _cplusplus
}
#endif

#include <cmath>

#define PI acos(-1.0)


#endif



Makefile文件:
GOAL := overload_implicit

objs := ${GOAL}.o 

CFLAGS := -I${shell pwd}/include

CPP := g++

${GOAL} : ${objs}
	g++ $^ -o $@ -lm

export CFLAGS CPP

%.o : %.cpp
	${CPP} ${CFLAGS} -Wall -fpermissive -c $^ -o $@

.PHONY: clean
clean:
	rm -rf ${GOAL} *.


//<strong><span style="font-size: 19px;"></span></strong>overload_implicit.cpp

#include <iostream>

using namespace std;

void output(int n);
void output(float n);

void output(int n)
{
	cout << "output int: " << n << endl;
}

void output(float n)
{
	cout << "output float: " << n << endl;
}

int main(void)
{
	int x = 1;
	float y = 1.0;

	output(x);
	output(y);

	output(1);

	return 0;
}

//overload_swap.cpp

#include <iostream>
#include <string>
#include <cstring>
#include "comdef.h"

using namespace std;

double g_area;

void Print()
{
	cout << "global function" << endl;
}

class A
{
public:
	void Print()
	{
		cout << "member function\n";
	}
};

void mySwap(int *a, int *b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

void mySwap(int &t_a, int &t_b)
{
	int tmp = t_a;
	t_a = t_b;
	t_b = tmp;
}

const string& maxString(const string &t_str1, const string &t_str2)
{
	return t_str1.length() > t_str2.length() ? t_str1 : t_str2;
}

double &getArea(double t_r)
{
	g_area = PI * t_r * t_r;

	return g_area;
}

int main(void)
{
	cout << "pi = " << PI << endl;

	int t_a = 100, t_b = 200;

	cout << "t_a = " << t_a << ", t_b = " << t_b << endl;

#if 0
	cout << "point swap\n";
	mySwap(&t_a, &t_b);

	cout << "t_a = " << t_a << ", t_b = " << t_b << endl;
#endif

	cout << "reference swap\n";
	mySwap(t_a, t_b);
	cout << "t_a = " << t_a << ", t_b = " << t_b << endl;

	double t_r = 10.0;

	double &t_area = getArea(t_r);

	cout << "area: " << t_area << endl;

	string t_str1 = "hello";
	string t_str2 = "world";

	cout << "The Max string 'hello' and 'word' is : " << maxString(t_str1, t_str2) << endl;

	cout << "=============================\n";

	::Print();

	return 0;
}

//reference.cpp

#include <iostream>
#include <string>

using namespace std;

struct animal
{
	string m_name;
	int m_weight;
	int m_age;
};

void getAnimalInfo(const animal &t_animal)
{
	cout << "animal name: " << t_animal.m_name << endl;
	cout << "animal weight: " << t_animal.m_weight << endl;
	cout << "animal age: " << t_animal.m_age << endl;
}

void setAnimalInfo(animal &t_animal)
{
	cout << "Please input the animal name: \n";
	cin >> t_animal.m_name;
	cout << "Please input the animal weight: \n";
	cin >> t_animal.m_weight;
	cout << "Please input the animal age: \n";
	cin >> t_animal.m_age;
}

void setAnimalInfo(animal &t_animal, const string &t_name, int t_weight, int t_age)
{
	t_animal.m_name = t_name;
	t_animal.m_weight = t_weight;
	t_animal.m_age = t_age;
}

void setAnimalInfo(animal &t_destAnimal, const animal &t_srcAnimal)
{
	t_destAnimal.m_name = t_srcAnimal.m_name;
	t_destAnimal.m_weight = t_srcAnimal.m_weight;
	t_destAnimal.m_age = t_srcAnimal.m_age;
}

int main(int argc, char *argv[])
{
	int t_a = 200, t_b = 300;
	
	const int &t_c = t_a;

	t_a = t_b;

	cout << "&t_a = " << &t_a << "	t_a = " << t_a << endl;
	cout << "&t_c = " << &t_c << "	t_c = " << t_c << endl;

	animal t_animal = {"Tiger", 200, 5};
	getAnimalInfo(t_animal);
	setAnimalInfo(t_animal, "Dog", 100, 10);
	getAnimalInfo(t_animal);

	return 0;
}






#ifndef FUN2_H
#define FUN2_H
 
 
//函数重载
//1.函数名一样 2.函数的形参列表不一样 3.与函数的返回值无关
void Swap(int *t_p1,int *t_p2);

void Swap(int &t_x,int &t_y);
 
 
void Swap(int &t_x,int &t_y,bool t_b);
 
 
//增加函数的默认参数,必须从右往左添加
//函数传参时,实参匹配形参的顺序是从左往右的
int add(int t_a,int t_b,int t_c,int t_d = 4);

#endif // FUN2_H












  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值