目录

  • 什么是c++
    • 一、c++关键字
    • 二、c++的命名空间
    • 三、 缺省参数
    • 四、函数重载
    • 五、引用
    • 六、内联函数
    • 七、auto关键字
    • 八、 基于范围的for循环
    • 九、指针空值nullptr(C++11)

什么是c++

C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度
的抽象和建模时,C语言则不合适。为了解决软件危机, 20世纪80年代, 计算机界提出了OOP(object
oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。
1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语
言。为了表达该语言与C语言的渊源关系,命名为C++。因此:C++是基于C语言而产生的,它既可以进行C语
言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程
序设计。

一、c++关键字

在这里我们可以先了解一下

二、c++的命名空间

或许很多人都知道在编写一个cpp程序时要加入 using namespace std ;
但你知道这究竟是为什么嘛?
———在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

//命名空间的定义
//1. 定义命名空间首先用关键字namespace,在关键字后面加上名称,再加一对{}即可
namespace n1  //n1 为命名空间的名称
{int a = 0;  //命名空间中可以定义函数,也可定以变量int add(int a, int b){return a + b;}
}//2. 命名空间可以嵌套
namespace n2
{namespace n3{}
}//3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
namespace n1
{int Mul(int left, int right){return left * right;}
}

注意:一个命名空间定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间当中

命名空间的使用

#include <iostream>
namespace N
{int a = 10;int b = 20;int add(int left, int right){return left + right;}int sub(int left, int right){return left - right;}
}
//定义了如上的空间N1 ,使用它一共有三种方式int main()
{//printf("%d", a);//直接使用编译器会报错
}//1.0 加命名空间名称及作用域限定符
int main()
{printf("%d ", N::a);printf("%d ", N::b);
}//2.0 使用using将命名空间中成员引入
using N::b;
int main()
{printf("%d ", N::a);printf("%d ", b);
}// 3.0  使用using namespace 命名空间名称引入
using namespace N;
int main()
{printf("%d ", a);printf("%d ", b);int c=add(1, 2);printf("%d ", c);int d=sub(4, 3);printf("%d ", d);
}

c++中的输入和输出

//c++中如何实现hello world
#include <iostream>
using namespace std;
int main()
{cout << "hello,world" << endl;return 0;
}

相比c语言来说我们发现c++的输出方式更为简单
说明:

  1. 使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空
    间。
    注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件
    即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文
    件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用
    +std的方式
  2. 使用C++输入输出更方便,不需增加数据格式控制,比如:整形–%d,字符–%c
#include <iostream>
using namespace std;
int main()
{int a;double b;char c;cin >> a;cin >> b >> c;cout << a << "  " << b << " " << c << endl;return 0;
}

运行结果如下

想必到达这里就会明白为什么要用using namespace std;这一串话了(这段话告诉编译器我们要用名字空间std中的函数或者对象)
但是日后当我们在写成熟的代码的时候,一般不建议将标准命名空间全部打开,而是需要用库里的什么就打开什么。这就有效的防止了命名冲突

例如写一个hello world
第一种就是上面提到的
不安全但是简单

#include <iostream>
using namespace std;
int main()
{cout << "hello,world" << endl;return 0;
}

第二种,用哪个,提前打开那个对象
安全,推荐使用

#include <iostream>
using std::cout;
using std::endl;
int mian()
{cout << "hello world" << endl;
}

第三种,什么时候用什么时候打开std
安全,但是较为复杂

#include <iostream>
int main()
{std::cout << "hello world" << std::endl;
}

三、 缺省参数

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

缺省参数又分为全缺省与半缺省

1.0全缺省

#include<iostream>
using namespace std;
void fun (int a = 10, int b = 20, int c = 30)
{cout << "a= " << a << endl;cout << "b= " << b << endl;cout << "c= " << c << endl<<endl;
}
int main()
{fun();// 不传参就用默认的fun(1,2,3);  //传了就用传了的fun(1);fun(1, 2);
}
运行结果如下


2.0 半缺省参数

#include<iostream>
using namespace std;
void fun2 (int a , int b , int c=30 )
{cout << "a= " << a << endl;cout << "b= " << b << endl;cout << "c= " << c << endl<<endl;
}
int main()
{fun2(1,2);  // 没传就用默认值fun2(1, 2, 3);}

但要注意:

  1. 半缺省参数必须从右往左依次来给出,不能间隔着给
    eg:



    这三种写法都是错误的
  2. 缺省参数不能在函数声明和定义中同时出现
    eg:
//a.h
void TestFunc(int a = 10);
// a.c
void TestFunc(int a = 20)
{}
// 注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那
个缺省值

3.缺省值必须是常量或者全局变量
4.C语言不支持(编译器不支持)

缺省函数的作用就是为了是函数调用更加灵活

四、函数重载

函数重载的概念::是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的

形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题

#include<iostream>
using namespace std;
int Add(int left, int right)
{   return left + right;
}
char Add(char left,char right)
{return left + right;
}
double Add(double left, double right)
{return left + right;
}
long Add(long left, long right)
{return left + right;
}
int main()
{cout<<Add(10, 20)<<endl;cout<<Add(10.0, 20.0)<<endl;cout<<Add(10L, 20L)<<endl;cout<<Add('1', '2')<<endl;return 0;
}

结果如下

注意:这两个函数就不构成运算符重载,因为参数的类型,个数都一样

short Add(short left, short right)
{return left+right;
}
int Add(short left, short right){return left+right;}

下面两个函数构成重载吗?

void TestFunc(int a = 10) {cout<<"void TestFunc(int)"<<endl; }
void TestFunc(int a) {cout<<"void TestFunc(int)"<<endl; }

答案:不构成,他俩类型相同,只是缺省参数不同`

学习了函数重载,我们不禁联想到为什么c++支持函数重载,而C语言不支持函数重载呢?
在这里仅简单提一下,简单来说是因为C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。

**

extern “C”

**
有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译。比如:tcmalloc是google用C++实现的一个项目,他提供tcmallc()和tcfree两个接口来使用,但如果是C项目就没办法使用,那么他就使用extern “C”来解决。

extern "C" int Add(int left, int right);
int main()
{Add(1,2);
return 0;
}

五、引用

引用的概念:引用不是定义一个新的变量,而是给已知的变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的的变量共用同一块内存空间。 (通俗来说,引用就是取别名)
就比如:比如:李逵,在家称为"铁牛",江湖上人称"黑旋风”。

int main()
{int a = 10;//&在类型后面,就是引用的意思int& b = a;// b就是a的引用(别名)b = 20;int& c = b;//c就是b的引用c = 30;}


通过监视我们可以看出完全符合引用的概念。

引用的作用
1.0 我们最熟悉的也就是交换两个值

void swap(int* a, int* b) //C语言中的交换需要指针(形参的改变不影响实参的改变)
{int tmp = *a;*a = *b;*b = tmp;
}void swap(int& a, int& b)
{int r = a;a = b;b = r;}
int main()
{int a = 10;int b = 20;swap(a,b);swap(&a, &b);
}
  • 引用特性
  1. 引用在定义时必须初始化
  2. 一个变量可以有多个引用
  3. 引用一旦引用一个实体,再不能引用其他实体
int main()
{//一个变量可以有多个别名int a = 0;int& b = a;int& c = b;int& d = c;int &x=a;int r = 10;x = r;  //将r的值赋给x;
}

常引用
eg1:

int main()
{const int a = 10;//const修饰代表a不能修改//int& ra = a;// 错误 ra引用a属于权限的放大,所以不行const int& ra = a;//正确int b = 10;int& rb = b;const int& crb = b;//正确,crb引用b属于权限的缩小,所以可以//b是可读可写的,crb是可读的,权限缩小,所以可行
}eg2:
```cpp
int main()
{int c = 10;double d = 1.11;d = c;
}

上述转换是可以的,发生了隐式类型转换,首先产生一个中间临时变量,这个中间临时变量是double类型的,将c赋给临时变量,再将临时变量赋给d

int main()
{ int c=10;double& rc=c;  //错误写法,编译通不过const double &rc=c;//正确写法
}

后者正确是因为:发生类型赋值过程当中,将int给double,中间就会产生临时变量,临时变量是double类型,所以rc引用的是这个临时变量,并且这个临时变量具有常性(只是可读的),所以加了const后编译通过,类似于eg1中的第一个情况。

使用场景
1.0 做参数

void Swap(int& left, int& right) {int temp = left;left = right;right =templ;}

2.0 做返回值

在这里首先简单介绍下传值返回(见下图)
(1)传值返回时,调用Add完成后会产生int类型的临时变量,c给了临时变量,临时变量再给给ret
返回的对象是c的拷贝

通过上图我们可以证明确实产生了临时变量(ret引用的不是c,其实是这个临时变量,临时变量具有常性,所以第二个引用编过了)

(2)传引用返回
传引用返回 ,返回的返回对象是c的引用(别名)

int &Add(int a, int b)
{int c = a + b;return c;
}
int main()
{int ret = Add(1, 2);return 0;
}


主函数中并没有加const编译通过,所以证明返回的是c的引用

这段代码看着是没问题,编译器也通过了,但它实际上却存在这问题,ret的值是不确定的
解释如下,调用函数就会开辟栈帧


接下来再看这段代码‘

int &Add(int a, int b)
{int c = a + b;return c;
}
int main()
{int &ret = Add(1, 2);Add(5, 7);cout << ret << endl;return 0;
}


解释如下:

int &Add(int a, int b)
{int c = a + b;return c;
}
int main()
{int &ret = Add(1, 2);Add(5, 7);printf("hello\n");cout << ret << endl;return 0;
}


这里ret是随机值原理和上述还是一样,调用printf时c那块空间就是随机值

注意:一个函数调用就会向下空间建立一个栈帧,函数调用结束,栈帧就会销毁

实际过程中,出了函数作用域,返回对象就不存在了,不能用引用返回
加了static就可正常使用了

int &Add(int a, int b)
{static int c = a + b;return c;
}
int main()
{int &ret = Add(1, 2);Add(5, 7);printf("hello\n");cout << ret << endl;return 0;
}


ret的值也不会改变。

小小总结下:如果函数返回时,出了函数作用域,如果返回对象还未还给系统(也就是没销毁,例如加了static),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

**

传参和传引用效率

当参数和返回值是比较大的变量时,传引用传参和传引用做返回值可以提高效率,只要符合条件,尽量用引用传参,传返回值

2.引用与指针的区别

int main()
{int a = 10;//在语法上,这里给a这块空间取了一块别名,没有开辟新空间int& ra = a;ra = 20;//在语法上,这里定义个指针变量,开辟了4个字节,存储a的地址int* pa = &a;*pa = 20;
}


但从汇编来看,引用的底层也是类似指针存地址的方式进行的

引用和指针的不同点:

  1. 引用在定义时必须初始化,指针没有要求
  2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  3. 没有NULL引用,但有NULL指针
  4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  6. 有多级指针,但是没有多级引用
  7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  8. 引用比指针使用起来相对更安全

六、内联函数

c++频繁调用的函数,定义成inline,会在调用的地方展开,没有栈帧的开销


inline int add(int x,int y)  //直接在函数前加一个inline构成inline函数
{return x + y;
}
int main()
{int c = 0;}

c语言为了小函数避免建立栈帧的消耗-》》提供了宏函数支持,预处理阶段展开
既然c语言已经解决了,为什么c++还要提供inline函数呢?(宏函数的缺点)
a.不支持调试 b.宏函数语法复杂容易出错 c.没有类型安全的检查

例如写一个add的宏函数

#define Add(int x,int y) return x+y;//典型的错误写法
#define Add(x,y) x+y; //错误 分号问题
#define Add(x,y) (x)+(y) // 错误 优先级问题//标准写法
#define Add(x,y) ((x)+(y))

内联函数特性

  1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。
  2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

七、auto关键字

    int a = 10;auto b = a;//类型声明成auto,可以根据a的类型自动推到b的类型
int main()
{int x = 10;auto a = &x;auto* b = &x;int& y = x;auto c = y;auto& d = x; //指定了d是x的引用//打印变量的类型cout << typeid(x).name() << endl;cout << typeid(a).name() << endl;cout << typeid(b).name() << endl;cout << typeid(y).name() << endl;cout << typeid(c).name() << endl;
}


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

void TestAuto()
{auto a = 1, b = 2; auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

auto不能推到的场景
1.auto不能作为参数的函数

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

2.auto不能用来推导数组

void TestAuto()
{int a[] = {1,2,3};auto b[] ={4,5,6};
}

八、 基于范围的for循环

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。

int main()
{int arr[] = { 1,2,3,4,5 };for (int i = 0;i < sizeof(arr) / sizeof(arr[0]);i++)  //常规方法{cout << arr[i] << " ";}cout << endl;//范围for c++11 新语法遍历,更简单//自动遍历,依次取出arr中的元素,赋值给e,直至结束(e可以任意取其他名称)for (auto e : arr){cout << e << " ";}cout << endl;return 0;}

但如果我们想要改变数组的内容我们就需要借助引用
见如下代码

#include<iostream>
using namespace std;
int main()
{int arr[] = { 1,2,3,4,5,6 };//自动遍历,依次取出arr中的元素,赋值给e,直至结束for (auto e : arr){e *= 2;}for (auto ee : arr){cout << ee<<"  ";} return 0;
}


是不是以为会输出2 4 6 8 10 12,但这个范围for 是自动遍历,依次取出arr中的元素,赋值给e,直至结束,arr是不会改变的如果想要改变增加引用即可

#include<iostream>
using namespace std;
int main()
{int arr[] = { 1,2,3,4,5,6 };//自动遍历,依次取出arr中的元素,赋值给e,直至结束for (auto& e : arr){e *= 2;}for (auto ee : arr){cout << ee<<"  ";} return 0;
}


这样就达到了我们的需求,e是arr每个成员的别名,e改变arr成员也改变。

九、指针空值nullptr(C++11)

NULL实际是一个宏,在传统的C头文件(stdio.h)中,可以看到如下代码:

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int a)
{cout<<"f(int)"<<endl;
}
void f(int*a)
{cout<<"f(int*)"<<endl;
}
int main()
{f(0);
f(NULL);
f(nullptr);
return 0;
}


程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖,所以引入nullptr来解决这一问题。

**注意:

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

【从零开始学习C++】(1)C++ 入门相关推荐

  1. 【PaddlePaddle学习笔记】从零开始学习图像分类01——图像处理入门基础

    本系列文章链接 [PaddlePaddle学习笔记]从零开始学习图像分类01--图像处理入门基础 未完待续...... 目录 一.关于图像的几个基本概念 1. 像素及其坐标 2. 图像的四种基本类型 ...

  2. [转载]从零开始学习jQuery (一) 开天辟地入门篇

    一.摘要 本系列文章将带您进入jQuery的精彩世界, 其中有很多作者具体的使用经验和解决方案,  即使你会使用jQuery也能在阅读中发现些许秘籍. 本篇文章是入门第一篇, 主要是简单介绍jQuer ...

  3. 从零开始学习ASP.NET MVC 入门

    <从零开始学习ASP.NET MVC 1.0> 文章导航 (一) 开天辟地入门篇 (二) 识别URL的Routing组件 (三) Controller/Action 深入解析与应用实例 ( ...

  4. python小白从哪来开始-如何从零开始学习Python【小白入门】

    我应该怎么开始呢? 别着急,我们需要先知道Python是什么.我可不太喜欢没有什么解释的大词. 简单来说,Python就是一种你告诉电脑应该怎么做的方法.你也许会问,电脑怎么听得懂英语呢? Pytho ...

  5. 从零开始学习Java设计模式 | 设计模式入门篇:设计模式概述

    在上一讲中,明确了设计模式这门课所要学习的内容之后,接下来,我们就得开始正式步入设计模式这门课的学习中了,当然,我也祝大家能在设计模式这门课程中能够学到很多东西,也不枉我这一片苦心了! 软件设计模式的 ...

  6. C#程序员的春天之从零开始学习unity3D游戏开发入门教程二(创建项目及基本面板介绍)...

    一项目创建: 创建项目是开发的第一步. 运行untiy之后如果是第一次运行会弹出 我们这里随便创建一个项目. 二Untiy面板介绍: 三代码编辑器的切换: 这里我安装了vs2012. 到这里开发环境基 ...

  7. 从零开始学习jQuery (十一) 实战表单验证与自动完成提示插件

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

  8. 从零开始学习jQuery (十) jQueryUI常用功能实战

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

  9. 从零开始学习jQuery (九) jQuery工具函数

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

  10. 从零开始学习jQuery (八) 插播:jQuery实施方案

    本系列文章导航 从零开始学习jQuery (一) 开天辟地入门篇 从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery ( ...

最新文章

  1. 攻防世界Reverse第十题getit
  2. 最简单的方式实现QML无边框窗口边缘拖动调整大小
  3. mysql strtok_c函数: strtok 和 strtok_r 详解
  4. android设置错误页面,Android ViewPager设置当前项目/页面时抛出IndexOutOfBounds异常
  5. dd命令安装Linux
  6. shiro多Realm分别授权
  7. 【Python实例第9讲】物种分布模型
  8. qt中如何刷新一下屏幕_感情维护:如何在恋爱关系中分开一下,然后更坚强地回来...
  9. Hibernate 基本类型
  10. 清风数学建模学习笔记——模糊综合评价法原理及案例分析讲解
  11. FAT32文件系统结构
  12. 为什么 AI 犯的错有时会很“瘆人”?
  13. JAVA_OPTS 参数介绍 使用记录
  14. 验证18位身份证真实性
  15. 关于新正方教务系统(湖北工程学院)的one day越权漏洞的说明
  16. 如何打造VUCA时代的敏捷型组织?
  17. 北航计算机学院马殿富,北京航空航天大学计算机学院院长马殿富演讲
  18. 联盛德W806入门教程-CDK安装教程及代码下烧录
  19. excel向程序发送命令时出现错误
  20. 有关计算机的英语作文一千字,英语作文一封信大学1000词5篇

热门文章

  1. Android adb devices emulator-5578 offline
  2. 2014秋C++第8周项目5参考-定期存款利息计算器
  3. 释放双脚压力,清爽度过夏日,咕咚运动舒缓拖鞋体验
  4. 计算机房空调的作用,精密空调对机房的作用
  5. JSON解析之JSONObject与JSONArray的使用
  6. SaaS-多租户SaaS平台的数据库方案
  7. Premature end of file 错误解决
  8. Locust工具学习(二)web界面介绍
  9. 在网页上添加微信分享按钮,关注微信号等按钮
  10. 在OCP集群内部署测试应用