C++关键字、命名空间、函数重载、缺省参数、内联函数、引用

一 .C++入门

1.C++关键字

2.命名空间

3.C++输入&输出

4.缺省参数

5.函数重载

6.引用

7.内联函数

8.auto关键字

9.基于范围的for循环

10.指针空值nullptr&nullptr_t

二. 正文

1.C++关键字(C++98)

    C++98中的关键字总共用63个,如下表:

    

在这这做简单介绍,感兴趣的朋友可以参考相关资料作进一步了解。

2.命名空间

  由于在编写程序的过程中,很容易出现变量、函数和类重名的现象,这些变量、函数和类都在全局作用域中,因此会导致很多冲突。使用命名空间的目的是:对标识符的名称进行本地化,以避免命名冲突或者名字污染,命名空间的关键字就是:namespace

2.1命名空间的定义

  定义命名空间,需要用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中的即为命名空间的内容,命名空间的定义方法有三种,下面一一列出:

  a.普通的命名空间:

 1   namespace N1
 2   {
 3       //命名空间中的内容,既可以定义变量,也可以定义函数
 4
 5       int a;
 6       int Add(int left, int right)
 7       {
 8           return left + right;
 9        }
10  }

b.命名空间可以嵌套

 1 namespace N2
 2 {
 3     int a;
 4     int b;
 5     int Add(int left, int right)
 6     {
 7         return left + right;
 8     }
 9     namespace N3
10     {
11         int c;
12         int d;
13         int Sub(int left, int right)
14         {
15             return left - right;16         }
17     }
18 }

c.同一个工程中允许出现多个命名相同的命名空间,编译器最后会合成同一个命名空间中

1 namespace N1
2 {
3     int Mul(int left, int right)
4     {
5         return left * right;6     }
7 }

2.2命名空间的使用

命名空间中的成员的三种使用方法:

注意:"::"称为作用域限定符

1.加命名空间名称及作用域限定符

1 int main()
2 {
3     printf("%d ",N1:a);
4     return 0;
5 }

2.使用using将命名空间中的成员引入

1 using N1::b;
2 int main()
3 {
4     printf("%d ",b);
5     return 0;
6 }

3.使用using namespace 命名空间名称引入

1 using namespace N1
2 int main()
3 {
4     printf("%d ",b);
5     printf("%d ",a);
6     return 0;
7 }

  注意:第一种方法与第二种方法只能将作用域限定符后的变量从它所在的命名空间引入,而第三种方法将命名空间中的所有的成员都引入了。

3.C++输入&输出

先用一段程序来直观的说说C++中的输入输出的使用方法:

1 #include<iostream>
2 using namespace std;
3 int main()
4 {
5     int a=0;
6     cin>>a>>endl;
7     cout<<"hello World!"<<endl;
8     return 0;
9 }

说明:

1.使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含<iostream>头文件,以及std标准命名空间。

2.使用C++输入输出更方便,不需要增加数据格式控制,比如:整形--%d,字符--%c

 1 #include<iostream>
 2 using namespace std;
 3 int main()
 4 {
 5     int a;
 6     char c;
 7     double d;
 8     cin>>a;
 9     cin>>c>>d;
10     cout<<a<<endl;
11     cout<<d<<" "<<c<<endl; //endl在C++中的意思是换行
12     return 0;
13 }

4.缺省参数

4.1缺省参数的概念

  缺省参数是申明或者定义函数的时候为函数的参数指定默认值的操作。在调用该函数时,如果没有指定参数就使用该默认值,否则使用指定的实参。

 1 #include<iostream>
 2
 3 void TestFun(int a=0)
 4 {
 5     cout<<a<<endl;
 6 }
 7
 8 int main()
 9 {
10     TestFun();        //没有传参时,使用参数的默认值
11     TestFun(2);      //指定了参数时,使用指定的实参的值
12     return 0;
13 }

 4.2缺省参数的分类

a.全缺省参数:函数的参数列表中的形参的值都指定了默认值

1 void TestFun(int a=10, double b=0.0, char c=‘ ‘)
2 {
3     cout<<a<<endl;
4     cout<<b<<endl;
5     cout<<c<<endl;
6 }

b.半缺省参数:函数的参数列表中的形参的值只有一部分指定了默认值,而且默认值只能从右往左依次给出

1 void TestFun(int a, int b=1, double c=0.0)
2 {
3     cout<<a<<endl;
4     cout<<b<<endl;
5     cout<<c<<endl;
6 }

注意:

1.半缺省参数必须从右往左依次给出

2.缺省参数不能在声明和定义中同时给出(建议在申明中给出)

3.缺省参数必须是常量或者是全局变量

4.C语言不支持

//a.h
void TestFun(int a=10);
//a.c
void TestFun(int a=20)
{}
//如果申明和定义中同时出现,恰巧两个位置的默认值如上边代码中的一样
//则编译器就无法确定到底该用哪个缺省值。

5.函数重载

5.1函数重载的概念

  函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数类型、参数个数、参数次序)必须不相同,常用来处理功能相似但类型不同的问题。

 1 int Add(int left, int right)
 2 {
 3     return left + right;
 4 }
 5 int Add(double left, double right)
 6 {
 7     return left + right;
 8 }
 9 long Add(long left, long right)
10 {
11     return left + right;
12 }
13
14 int main()
15 {
16     Add(12,13);
17     Add(12.12,13.13);
18     Add(10L,20L);
19     reutrn 0;
20 }

注意:函数的返回值类型对于函数是否重载没有影响

5.2名字修饰

在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。

  名字修饰是一种在编译阶段,将函数、变量的名称重新改编的机制,简单来说,就是编译器为了区分各个函数,将各个函数通过某种算法,重新修饰为一个全局唯一的名称。

  C语言中的名字修饰规则非常简单,仅仅只是在函数或者变量的名字前面加了下划线。读者朋友可以通过以下代码查看编译后的函数名(即通过只申明不定义,编译时编译器报错时会显示未找到<某某函数>,某某函数就是编译后的新名字。

1 int Add(int left, int right);
2
3 int main()
4 {
5     int a=0;
6     int b=2;
7     Add(a,b);
8     return 0;
9 }

  上代码运行时报错:error LNK2019:无法解析的外部符号_Add,该函数在_main函数中被引用。

  上述Add函数只给了申明,没有给定义,因此在链接时就会报错,提示:在main函数中引用的Add函数找不到函数体。报错结果中可以看到,C语言知识简单的在函数明前添加下划线。因此当工程中存在相同的函数名的时候,就会产生冲突。读者有兴趣可以自己验证。

  由于C++要支持函数重载,命名空间等,使得其的修饰规则比较复杂,不同的编译器的实现方式可能都有差异,同样,用上述代码在VS编译环境下运行,可以看到VS编译器对C++的修饰方式:

    error LINK2019:无法解析的外部符号"double cdecl Add(int,int)"([email protected]@Z)

如果定义的函数的参数类型是double类型的,则可以看到下面的报错信息:

    error LINK2019:无法解析的外部符号"double cdecl Add(int,int)"([email protected]@Z)

通过上述的报错信息可以看出,编译器实际上在底层使用的不是Add名字,而是被重新修饰过的一个比较复杂的名字,被修饰后的名字中包含了:函数的名字以及参数类型。这就是为什么函数重载中几个同名的函数要求它的参数列表必须不同的原因。只要参数列表不同,编译器在编译时通过对函数名字进行重新修饰,将参数类型包含在最终的名字中,就可以保证名字在底层的全局唯一性。这就不会导致Link时的多重定义。

5.3 extern "C"

  有时候在C++工程中可能需要将某些函数按照C的分格来编译,在函数前面加extern "C",意思是告诉编译器将该函数按照C语言的分格进行编译。

 1 extern "C" int Add(int left, int right)
 2 {
 3     return left + right;
 4 }
 5
 6 int main()
 7 {
 8     Add(2,3);
 9     return 0;
10 }

6.引用

6.1引用概念

  引用不是定义一个新变量,而是给已存在的变量取了一个别名,编译器不会为引用变量开辟新的内存空间,它和它引用的变量公用同一块内存空间。

类型&引用变量(对象名)=引用实体

1 void TestRef()
2 {
3     int a=10;
4     int & ra=a;//定义引用变量
5     printf("%d ",a);
6     printf("%d ",ra);
7  }

注意:引用类型必须和引用实体是同种类型的。

6.2引用特性

  1.引用在定义时必须初始化

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

  3.引用一旦引用一个实体,再不能引用其他的实体

1 void TestFun()
2 {
3     int a=10;
4     //int& ra;  此语句编译时会出错
5     int& ra=a;
6     int& rra=a;
7     printf("%p %p %p",&a,&ra,&rra);
8 }

6.3常引用

 1 void TestFun()
 2 {
 3     int a=10;
 4     //int& ra=a;编译时出错,因为a为常量
 5     const int & ra=a;
 6     //int& rb= 10;编译时出错,因为10为常量
 7     const int&rb =10;
 8     double d=12.34;
 9     int& rd=d;//编译时出错,类型不同
10     const int&  rd=d;
11 }

6.4使用场景

  1.做参数

1 void reverse(int& a, int&b)
2 {
3     int tmp=a;
4     a=b;
5     b=tmp;
6 }
7 //交换两个实参的值

  2.做返回值

int& TestFun(int left, int right)
{
    int tmp=left;
    left=right;
    right=tmp;
}

  注意:如果函数返回时,离开函数作用域后,其栈上空间已经返还给操作系统,因此不能用栈上的空间作为引用类型返回。如果用引用类型返回,返回值的使用周期必须不受函数的限制(即生命周期比函数长)。

6.5传值、传引用、传地址效率比较

  以值作为参数或者函数的返回值类型,在传参和返回期间,函数不会直接传递实参或者返回值类型,而是传递实参或者返回值的一份临时拷贝,因此用值作为参数或返回值传递效率非常低,尤其是当参数或者返回值的类型非常大的时候。

  传地址时不存在拷贝,开辟临时变量的时间开销,所以效率是比较高的。但是传地址的缺点是函数的副作用会改变实参的值,数据不安全。

  引用通过代码测试效率和传地址差不多。(有兴趣的读者朋友可以用clock()函数记时,测量传地址和引用的时间,进而判断它们的效率)

6.6引用和指针的区别

  在语法概念上引用就是一个别名,没有独立的空间,和其引用实体公用同一块地址空间。但在底层实现上是有空间的,因为引用是按照指针的方式来实现的,读者可以将引用和传地址的函数代码转到汇编了解其汇编代码的实现方式,其实是一样的。

  引用和指针的区别:

  1.引用在定义是必须初始化(实例化),但指针不用

  2.引用被一个实体初始化后不能引用其他的实体,但指针却可以(int& ra=a;<===>int * const p=&a;)

  3.没用NULL引用,但有NULL指针

  4.在sizeof中的含义不同,引用结果为引用类型大小,但指针的始终是地址空间所占的字节个数(32位平台下占4个字节)

  5.引用加加是引用实体加一,但指针加加会让指针跳过一个类型的大小

  6.有多级指针,但没有多级引用

  7.访问实体不同,引用编译器自己处理,指针需要显示解引用

  8.引用比指针更安全。(对空指针解引用会出错)

7.内联函数

7.1概念

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

7.2特性

  1.inline是一种以空间换时间的做法,省去调用函数的额外开销。所以代码很长,或者有循环/递归的函数不适宜用作内联函数。

  2.inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会自动忽略掉内联。

  3.宏的优缺点:优点:增强代码的复用性,提高性能。缺点:不方便调试(预处理期间替换)、没有类型的安全检测、代码的可读性差、可维护性差、容易误用。

  4.C++中替代宏的技术:

    常量定义换用const、函数定义换用内联函数

8.auto关键字

8.1auto简介:

  早期的C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但遗憾的是没有人去使用。C++11中给了全新的含义:auto不再是存储类型的指示符,而是一个全新的类型指示符来指示编译器,auto申明的变量必须右编译器时期推演而得。

 1 int TestFun()
 2 {
 3     return 0;
 4 }
 5
 6 int main()
 7 {
 8     int a=0;
 9     auto b=a;
10     auto c=‘a‘;
11     auto d=TestFun();
12     cout<<typeid(b).name()<<endl;//typeid().name()的作用是打印比变量的类型
13     cout<<typeid(c).name()<<endl;
14     cout<<typeid(d).name()<<endl;
15     //auto e;无法通过哦编译,使用auto定义变量必须对其进行初始化,这样编译器才能
16     //推演出变量的类型;
17     return 0;
18 }

注意:使用auto关键字定义变量时必须对其初始化,在编译阶段编译器需要根据初始化的表达式来推导auto的实体类型。因此auto并不是一种类型声明,而是类型声明时的占位符,编译器在编译时会将auto替换为变量的实际的类型。

8.2auto的使用细则

  1.auto与指针和引用结合起来使用:用auto声明指针类型时,用auto与auto*没有任何区别,但用auto声明引用时必须加上&

  2.在同一行声明多个变量时,这些变量必须是相同类型的,否则编译器会报错,因为实际上编译器只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

8.3auto不能推导的场景

  1.auto不能作为函数的参数

  2.auto不能用来直接声明数组

  3.为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法

  4.auto常用与范围for循环中

  5.auto不能定义类的非静态成员变量

  6.实例化模版时不能使用auto作为模板参数

9.基于范围的for循环

1 void TestFun()
2 {
3     int array[]={1,2,3,4,5};
4     for(auto& e:array)
5         e*=2;
6     for(auto e:array)
7         cout<<e<<endl;
8  }

  for循环后的括号由冒号":"分为两部分,前面的部分是范围内用于迭代的变量,后边的部分是迭代的范围。与普通循环类似,可以用continue跳出本次循环,break跳出循环。

  范围for的使用条件:for循环的迭代范围必须是确定的,对于数组而言,就是数组中的第一个元素和最后一个元素,对于类而言,应该是提供begin和end的方法,begin和end就是for循环的迭代的范围。迭代的对象要实现++或者==的操作。

10.指针空值nullptr&nullptr_t

  NULL其实是一个宏,通常被定义为0,因此在C++中有了函数重载之后,对于NULL而言就有了歧义性,为了解决这个问题,C++11中给出了全新的nullptr表示空指针,代表一个空值指针。nullptr是有类型的,其类型是nullptr_t,仅仅可以被隐式转化为指针类型。

  注意:在使用nullptr时不需要包含头文件,因为nullptr是C++11作为新的关键字引入的。在C++11中sizeof(nullptr)与sizeof(void *)所占的字节数相同,为了提高代码的健壮性,在后续的表示空指针的地方建议使用nullptr。

原文地址:https://www.cnblogs.com/love-you1314/p/9935556.html

时间: 2024-10-29 20:04:35

C++关键字、命名空间、函数重载、缺省参数、内联函数、引用的相关文章

不可或缺 Windows Native (16) - C++: 函数重载, 缺省参数, 内联函数, 函数模板

[源码下载] 作者:webabcd 介绍不可或缺 Windows Native 之 C++ 函数重载 缺省参数 内联函数 函数模板 示例1.函数重载, 缺省参数CppFunction1.h #pragma once #include <string> using namespace std; namespace NativeDll { class CppFunction1 { public: string Demo(); }; } CppFunction1.cpp /* * 函数重载,缺省参数

第2章 重新组织函数(2):内联函数和内联临时变量

2. 内联函数(Inline Method) 2.1 动机 (1)在函数调用点插入函数本体,然后移除该函数. (2)有时遇到某些函数,其内部代码和函数名称同样清晰易读,采用内联函数可以提供代码的执行速度(因为少掉了函数调用的开销) (3)在Replace Method withd Method Object之前,将一些组织不合理的函数内联到一个大型函数,再从中提炼组织合理的小型函数时效果很好. (4)使用太多的间接层时,特别是一部分函数只是对另一个函数的简单委托时,可同去掉一些无用的间接层. 2

C++文件头,命名空间,new和delete,内联函数,引用,函数重载,构造函数和析构函数,深拷贝和浅拷贝,explict,this指针

 目  录 1       开始学习C++.............................................................................................................. 4 1.1       C++的头文件.................................................................................................

C++中对C的扩展学习新增语法——内联函数以及函数参数

内联函数以及函数参数 内联函数 使用 inline 关键字必须和函数体放在一起. 内联函数具有内部链接属性. 内联函数会被编译器在编译阶段替换到函数调用的地方. 可以把内联函数定义写到头文件中,多个cpp包含时不会引起重定义. 如果出现连接错误: 使用第三方库,没有将其库代码配置到项目,所以导致编译器找不到实现(变量定义,函数定义) 本身自己只写了声明,根本没有定义实现. 变量本身.函数本身具有内部链接属性,此函数或者变量只能在当前文件访问. 函数参数 函数参数的作用 兼容C语言中不规范的语法

深入探讨 内联函数和宏定义的区别

内联函数的执行过程与带参数宏定义很相似,但参数的处理不同.带参数的宏定义并不对参数进行运算,而是直接替换:内联函数首先是函数,这就意味着函数的很多性质都适用于内联函数,即内联函数先把参数表达式进行运算求值,然后把表达式的值传递给形式参数. 内联函数与带参数宏定义的另一个区别是,内联函数的参数类型和返回值类型在声明中都有明确的指定:而带参数宏定义的参数没有类型的概念,只有在宏展开以后,才由编译器检查语法,这就存在很多的安全隐患. 使用内联函数时,应注意以下问题: 1)内联函数的定义性声明应该出现在

C/C++之宏、内联函数和普通函数的区别

内联函数的执行过程与带参数宏定义很相似,但参数的处理不同.带参数的宏定义并不对参数进行运算,而是直接替换:内联函数首先是函数,这就意味着函数的很多性质都适用于内联函数,即内联函数先把参数表达式进行运算求值,然后把表达式的值传递给形式参数. 内联函数与带参数宏定义的另一个区别是,内联函数的参数类型和返回值类型在声明中都有明确的指定:而带参数宏定义的参数没有类型的概念,只有在宏展开以后,才由编译器检查语法,这就存在很多的安全隐患. 使用内联函数时,应注意以下问题:     1)内联函数的定义性声明应

内联函数详解

什么是内联性和外联函数 类的成员函数可以分为内联函数和外联函数.内联函数是指那些定义在类体内的成员函数,即该函数的函数体放在类体内.而说明在类体内,定义在类体外的成员函数叫外联函数.外联函数的函数体在类的实现部分. 内联函数在调用时不是像一般的函数那样要转去执行被调用函数的函数体,执行完成后再转回调用函数中,执行其后语句,而是在调用函数处用内联函数体的代码来替换,这样将会节省调用开销,提高运行速度. 内联函数与前面讲过的带参数的宏定义进行一下比较,它们的代码效率是一样的,但是内联函数要优于宏定义

C++学习笔记之——内联函数,引用

本文为原创作品,转载请注明出处 欢迎关注我的博客:http://blog.csdn.net/hit2015spring和http://www.cnblogs.com/xujianqing/ 作者:晨凫追风 一直想开始写C++的学习笔记,学习C++已经两个月了,今天开始写一下引用,内联函数,的一些概念和作用吧.那么开始吧! ????内联函数: 我们写的程序最终都是要用编译器,进行编译链接形成一段机器可以知道的二进制代码,接着存到一个内存中,这时候每一段程序代码都会有自己的一个地址,计算机按照地址增

C++ 内联函数

1.定义: 被调用函数的函数体代码直接插入到该函数被调用处, 而不是通过call语句进行. 2.方式: (1).类的定义体外: 当在类的定义体外时,需要在该成员函数的定义前面加“inline”关键字,显式地告诉编译器该函数在调用时需要“内联”处理,如: class Person { public: string GetName(); private:   string  name; }; inline string GetName() {         return name; } (2).类

内联函数 inline

(一)inline函数(摘自C++ Primer的第三版) 在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联. inline int min(int first, int secend) {/****/}; inline 函数对编译器而言必须是可见的,以便它能够在调用点内展开该函数.与非inline函数不同的是,inline函数必须在调用该函数的每个文本文件中定义.当然,对于同一程序的不同文件,如果inline函数出现的话,其定义必须相同.对于由两个文件comput