【C++】第二篇:(namespace)(引用)(缺省参数)(函数重载)(内联函数)

C++基础

在这里插入图片描述

命名空间(namespace)

namespace的作用:为了解决C语言中命名冲突的问题,C++引进了namespace,在不同的namespace中命名可以相同,使用的时候注意要用namespace的名字+域作用符::使用namespace中的东西,在你的命名空间里你可以任意返回你的想象写代码,不用担心变量名和别人相同了。可能平时最常用的就是标准库中的函数了,所以有时候避免麻烦通常会在引完头文件后加上using namespace std其实这就是在用标准库中的函数,它的namespace叫做std,所以在后面使用的时候,我们就可以不用std::这样使用标准库中的东西了,而是直接使用函数,例如用了using namespace stdcout << end;,如果提前说明就必须std::cout << std::endl;

namespace的使用方式

上面介绍命名空间的时候,已经介绍了两种了,其实用三种方式
1)使用整个命名空间在开头加上using namespace std。这要在后面就可以直接在使用std中的东西了
优点: 在后面使用namespace中的东西很方便了
缺点: 破坏了原来namespace存在的意义,namespace的作用就是避免命名冲突,如果直接使用using namespace std的话,不就是将所有的成员全部展开,这样如果用重复的变量或对象就又有命名冲突的问题了

2)指定命名空间using std::cout,如果加上这句话,在后面就可以使用cout了,但是使用其他的namespace中的东西了。
3)不提前说明任何空间,用::出自己想用的namespace的东西,例如:std::cout
优点: 最大程度上防止了命名冲突的问题
缺点: 使用起来相对麻烦

三中方法各有优缺点,所以可以可以根据不同的场景结合使用

引用(&)

引用就是在给另一个变量取一个别名,如int& b = a这样就是在说b是a的小名,其实b和a就是一个东西。

&使用的注意事项

1)引用使用必须初始化,不能空引用

int& a;// 错误
int& a = b;// 正确

2)一个变量可以有多个引用

int& b = a;
int& c = a;
int& d = a;
// b, c, d都是a的小名

3)一个变量一旦使用引用,就能作为其他变量的引用了

int a = 10;
int b = 20;
int& c = a;// c是a的引用
c = d;// 将c修改成d
本质及和指针的区别

本质: 引用看起来是传地址,其实本质还是传地址
说明:
1)在语法上引用只是给一个空间取了一个别名,并没有开辟一个新的空间
2)从实际的汇编实现的角度,引用的底层也是有一个类似指针的东西存放变量的地址

和指针的区别:

指针是通过指向一个变量后,间接的操作变量,并且指针可以不初始化或者初始化为空,引用本身就是变量的别名可以直接操作变量本身。

不同点:
1)引用必须初始化,指针不一定要初始化
2)引用不能有空引用,指针可以初始化为nullptr
3)引用只能初始化为一个变量的别名后,就不能在作为其他变量的引用了,指针可以在任何时候指向任何统一类型的变量
4)引用的大小取决于他所引用的变量的大小,指针的大小是固定的在32位系统下就是个字节
5)没有多级引用,有多级指针
6)引用更加安全,指针的使用不方便更危险
7)引用的+1就死变量+1,指针的+1就是向前走指针类型的大小
8)使用引用的时候直接使用变量,指针需要先解引用才能使用

传值和传引用的效率比较

当传数值的时候,无论是传函数参数还是以返回值的形式传回来的时候,并不是将参数本身传回来,而是传递回来一份临时的拷贝而已,所以当变量的临时拷贝很大的时候,开销就会很大,这时候传引用的效率就就会比传值的效率大很多。

常引用

const修饰的变量,必须要用const引用起别名,但是反过来普通变量的可以用const的引用起别名,最重要的是在不同的类型的变量中,可以互相起别名,但是要用const修饰,可以认为在不同类型的变量发生隐式转换的时候,产生的临时变量具有const的性质

const int a = 10;
int& b = a;// 错误 ,可以说是访问的权限变大了
const int& b = a;// 正确

int a = 10;
const int& b = a;// 正确,访问的权限变小了

int a = 10;
double& b = a;//错误
const double& b = a;// 正确,临时变量具有常性

缺省参数

通过函数声明或者函数定义的时候指定好参数的值(注意必须二选一,不能都指定值)在函数调用的时候,可以更灵活的使用函数本身

全缺省
int Add(int a = 10, int b = 10) 
{
	return a + b;
}

int main ()
{
	std::cout << Add();
	std::cout << Add(10);
	std::cout << Add(10, 20);
	return 0;
}
半缺省

函数的参数的值不是全部指定,但是如果只是指定一部分参数的值,必须要从右向左连续的指定

int Add(int a, int b, int c = 10)// 正确
{
	return a + b + c;
}

int Add(int a, int b = 10, int c = 10)// 正确
{
	return a + b + c;
}

int Add(int a = 10, int b, int c = 10)// 错误
{
	return a + b + c;
}
int Add(int a, int b, int c = 10)
{
	return a + b + c;
}

int main ()
{
	std::cout << Add();// 错误
	std::cout << Add(10);// 错误
	std::cout << Add(10, 20);// 正确
	std::cout << Add(10, 20, 30);// 正确
	return 0;
}

函数重载

函数重载就是 函数名相同,但是参数不同(参数可以是参数的个数不同或者是参数的类型不同,或者是参数不同类型的顺序不同)注意:函数重载和返回值的类型无关可以实现不同的函数但看起来使用的是相同的函数

int Add(int a, int b)// 函数1
{
	return a + b;
}

double Add(double a, double b)// 函数2
{
	return a + b;
}

string Add(string a, string b)// 函数3
{
	return a + b;
}

int main ()
{
	std::cout << Add(1, 2);// 调用函数1
	std::cout << Add(1.1, 2.2);// 调用函数2
	std::cout << Add("hello", "world");// 调用函数3
	return 0;
}

这样就是函数重载了,虽然是调用不同的函数,但是使用起来的使用确认为是同一个函数,这是C++比起C语言的一个重大的突破。

为什么C语言不支持函数重载,C++支持?C++底层是如何支持重载函数的?

因为源文件在经过C++编译器的预处理编译和汇编后,函数的地址会放在目标文件中,并会加上函函数名修饰,会将函数的参数和其他一些东西和函数名绑定然后存放在目标文件的符号表中加以区分不同的函数,这样就可以使用函数重载,而C语言没有函数名修饰,只是将函数名单独放在目标文件的符号表中,所以如果还是函数参数变化但是函数名没有发生改变的话,就会有两个相同的函数名被放在符号表中,这时编译器就会认为是函数重定义了,所以C语言就没有函数重载

extern’C’的作用是什么?

在某种场合下,C语言和C++会用同一个函数,但是C++存放函数地址的时候会有函数名修饰而C语言没有函数名修饰,如果是C++编译后将函数名修饰过后的函数名和函数地址放在符号表中,C语言的程序在调用的时候,其实只是在找函数名就会找不到经过修饰的函数名,这样的话就会调用不到函数,所以就有了extern"C",它的作用就是强制性的不让C++编译的时候用函数名修饰,而是用C语言风格的不加修饰的方式存放函数名到符号表中,这样C语言在调用的时候就可以找到函数名和函数地址了

内联函数

内联函数的作用

inline用来修饰一个韩式,编译的时候会在函数调用的地方展开,没有压栈的行为,

内联函数和C语言中的宏函数的区别?

1)宏不支持调试,但是内联函数可以像普通函数一样调试
2)宏函数语法复杂写起来容易出错,但是内联函数协防和普通函数类似
3)宏函数没有安全检查,可能会有类型的不匹配检查不出来,但是内联函数可以像函数一样支持检查类型的匹配问题

**拓展:**内联函数更像是为了解决宏的函数定义问题而提出来的解决方案,而宏还可以定义变量所以在C++中尽量还是用const,enum代替宏的作用(出自《Effective C++》)

所有的函数都可以用inline修饰吗?

在一些有函数中有循环或递归或有过多的代码,就不适合用inline,内联函数只是一个申请,如果不符合条件编译器就会忽略inline的存在,因为如果是复杂的函数在调用的地方展开的话会增加代码的长度并且会增加可执行文件的大小会占更多的内存,这样会造成一定程度的浪费

应用的场景

在频繁调用小函数的地方可以使用,(即函数中没有循环没有递归,没有过多的代码)

琐碎的小语法

nullptr

C++11中,推出nullptr代替了原来的NULL,NULL其实就是宏定义#define NULL 0其实就是0,但是nullptr是(void*)0这才是真正意义上的空指针

auto

可以自定义类型推导

int a = 0;
auto b = a;// b 就是int

vector<map<strng, double>> v;
auto t = v;// t的类型就是vector<map<strng, double>>
// 在后面这种情况下,就显示出了auto的优势

范围for循环

int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < 10; i ++)
	std::cout << a[i];

// 等价于
for (int n : a )// 从数组a中拿出元素n
	std::cout << n;
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hyzhang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值