C++ 初阶 新语言入门介绍:命名空间,(全/半)缺省函数,函数重载,引用,内联,auto

Posted SuchABigBug

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 初阶 新语言入门介绍:命名空间,(全/半)缺省函数,函数重载,引用,内联,auto相关的知识,希望对你有一定的参考价值。

一、C++介绍

C++语言发展最重要的两个版本里程碑:C++98和C++11
C++98: 是第一个C++标准版本,以模版方式重写C++标准款,引入了STL(标准模版库),简而言之语言比较完善
C++11: 增加了许多特性如:正则表达、基于范围for循环、auto关键字、新容器、列表初始化、标准线程库等

C++中的63个关键字

二、命名空间(namespace)

在C++中变量名、函数和后面学到的类都大量存在,这些名称在大型项目中可能存在冲突,所以就有了namespace这个关键词,目的是对标识符的名称进行本地化,从而避免命名冲突或名字污染

我们常用的using namespace std标准库,在预处理阶段会展开

下面自定义一个命名空间,里面既可以定义变量也可以定义函数

  1. 命名空间定义
  2. 命名空间嵌套
  3. 同一个工程中允许存在多个相同的命名空间,编译器最后合成一个命名空间

三、缺省参数(全缺/半缺)

缺省参数是声明或定义函数时为函数的参数指定一个默认值,调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参

//全缺省
void TestFunc(int defaultVal=100, int defaultVal2=101, int defaultVal3=102){
    cout << defaultVal << " " << defaultVal2 << " " << defaultVal3 << endl;
}

上面代码有三个参数,调用TestFunc函数,如果不指定实参那么会采用指定的默认值

//半缺省
void TestFunc2(int defaultVal, int defaultVal2, int defaultVal3=102){
    cout << defaultVal << " " << defaultVal2 << " " << defaultVal3 << endl;
}

调用函数方式:

TestFunc(); //未指定实参
TestFunc2(10 , 11); //从左到往右依次传实参

四、函数重载

C++中允许同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列别必须满足参数个数不同,或者类型,或者顺序不同,用来处理实际功能类似数据类型不同的问题

int Add(int a, int b){
    return a+b;
}

//不同参数个数
int Add(int a, int b, int c){
    return a+b+c;
}

//不同类型
double Add(double a, int b){
    return a+b;
}

//调换顺序
int Add(int a, double b){
    return a+b;
}

我们可以看到上面的代码函数名都是一样的,参数构成函数重载

那么为什么C语言中没有,而C++中支持函数重载呢?
这就需要从程序编译过程说起,编译分为预处理、编译、汇编、链接
在链接阶段,调用的函数会重定位符号表,我们通过objdump -S FuncReload来查看C++的函数名经过了名字修饰(name Mangling)

gcc编译完后,函数名字的修饰没有发生改变,而g++编译器下,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中
上图可以看到函数名都以__z3开头,函数名再接各参数类型的首字母。
因此只要参数不同,修饰出来的名字就不一样,也就支持了重载。

五、引用

引用是给已存在变量取了一个别名就好像你叫王二蛋,在家里蛋蛋这个别名永远在妈妈口中挂着
编译器不会为引用变量开辟内存空间,引用变量和被引用的变量共用一块内存空间,我们用符号&表示

引用的符号为&,其使用方法是 类型 + & + 引用变量名称(对象名) = 引用实体; (引用实体的类型必须和&前的类型保持一致)

b变量对变量a进行引用,下图我们可以看到memory里面的地址都为同一个

int a = 10;
int& b = a;

1. 引用特征

1.引用在定义同时必须要初始化。比如在取别名的时候就需要有这个被取别名的对象。
2.一个引用实体可以有多个引用。
3.一旦引用变量成为了一个实体的引用,就不能再成为其他实体的引用。
int main()
{
    int a = 10;  
    int d = 100;
    
    //一旦写了引用,就必须有完整的实体,不能写成  int& b;  这是不允许的,即第一条特性
    int& b = a; 
    
    //a变量被引用了两次,也就是第二条特性意思
    int& c = a; 
    
    //前面c已经成了a的别名,那么c就永远只能是a的别名,只不过这里C的值变成了100(同样ab也变成100),特征三
    c = d;
    
    return 0;
}

2. 引用与指针有哪些区别?

(1)引用需要初始化,而指针没有要求。
(2)引用一旦作为一个引用实体的引用,就不能再作为其他实体的引用,但指针可以修改其所指向的对象的。
(3)引用没有独立空间,而指针有,但是引用的效率也会更高(毕竟少开辟了一大块内存空间)。
(4)对于sizeof,引用变量的大小与类型有关,指针变量的大小与类型无关。
(5)对于自加,引用加一是数值上加一,而指针加一是跳过一个类型的大小。
(6)访问实体的方式不同,指针是通过解引用访问,而引用是编译器自己处理。
(7)引用使用起来相对于指针更安全。

3. 引用使用场景

  1. 作为参数
    (1)可以减少传参拷贝(引用作用)
truct node   //某个结构体,假设很大
{
    int val;
    struct node* next;
};

//如果参数为引用,将不需要通过函数传递方式中的值传递(拷贝),提高效率
void modify(struct node& node0) 
{
    //此处省略...
}

(2)可以保护形参不被修改,既可以接收变量,又可以接收常量(常量引用作用).

int add(const int& a,const int& b)
{
  // a = 15; //会报错,这样避免被修改
  return a-b;  
}

int main()
{
  int a = 10;
  int b = 20;
  
  cout<<"变量作为实参"<<add(a,b)<<endl;
  cout<<"常量作为实参"<<add(10,20)<<endl;   //必须是常量引用,否则将无法接收实参
  return 0;
}
  1. 作为返回值

六、内联

关键词:inline
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率

如果在前面增加inline keyword将改成内联函数

这实际上是一种以空间换时间的做法,省去调用函数额外开销,因此代码太长或者循环递归函数不适宜作为内联函数。
不过也不用太担心,编译器会自动优化,如果函数体内有循环/递归等,编译器优化时会忽略掉内联

Warning:inline不建议声明和定义分离,分离会导致链接错误,因为inline被展开,就没有函数地址了,那么链接就会找不到

七、auto

auto关键字是在C++2011年以后赋予的全新含义,作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

Warning:使用auto定义变量时必须对其进行初始化,因为编译器需要根据初始化表达式来推导auto的实际类型,因此auto并非是一种类型的声明,而是一个类型声明的占位符,编译器在编译期会将auto替换为变量实际的类型

int TestAuto()
{
	return 10; 
}

int main(){
    int a = 10;
    auto b = a;
    auto c = 'a';
    auto d = TestAuto();
    cout << typeid(b).name() << endl;
    cout << typeid(c).name() << endl;
    cout << typeid(d).name() << endl;
	cout << typeid(d).name() << endl;
	
	//auto e;   <------会报错因为编译器推导不出来
}

还有不能推导的场景:

  1. auto不能作为函数的参数
  2. auto不能直接用来声明数组
void TestFor()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
		array[i] *= 2;
	for (int* p = array; p < array + sizeof(array)/sizeof(array[0]); ++p)
		cout << *p << endl; 
}

上面为C++98中遍历一个数组的方式

下面是基于范围for的新用法,冒号的前面部分是范围内用于迭代的变量,第二部分表示被迭代的范围

void TestFor()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for(auto& e : array) 
		e *= 2;
	for(auto e : array)
		cout << e << " ";
		
	return 0; 
}

创作不易,如果文章对你帮助的话,最后的最后点赞哦:)

以上是关于C++ 初阶 新语言入门介绍:命名空间,(全/半)缺省函数,函数重载,引用,内联,auto的主要内容,如果未能解决你的问题,请参考以下文章

C++初阶---C++基础入门(未写完)

C++初阶:入门总结命名空间 | 缺省参数 | 函数重载 | 引用 | 内联函数

C++初阶C++入门

C++入门篇之关键字,命名空间,输入输出和函数重载

C++ 入门超详解!

C++ 入门超详解!