C++入门

文章目录

  • c++入门学习路线
  • c++简介
  • c++关键字
  • 命名空间
    • 命名空间的定义
    • 命名空间的使用
      • 1、加命名空间名称及作用域限定符
      • 2、使用using将命名空间中某个成员引入
      • 3、使用using namespace 命名空间名称 引入
  • c++输入&输出
  • 缺省参数
    • 概念
    • 缺省参数分类
      • 全缺省参数
      • 半缺省参数
  • 函数重载
    • 函数重载概念
  • 引用
    • 引用的概念
    • 引用的特性
    • 常引用
    • 引用的使用场景
    • 引用和指针的区别
  • 内联函数
    • 内联函数的概念
    • 内联函数的特征
  • auto关键字
    • auto简介
    • auto的使用规则
    • auto不能使用的场景
  • 基于范围的for循环(c++11)
    • 语法
    • 使用条件
  • 指针空值nullptr(c++11)

c++入门学习路线

C++入门_第1张图片

c++简介

c语言是结构化和模块化语言,不适合解决复杂问题。20世纪80年代,为了解决软件危机 计算机界提出了OOP面向对象思想。
C++是一种面向对象的编程语言,祖师爷Bjarne Stroustrup本贾尼在20世纪80年代开发出这门语言,因为C++是基于C语言而产生的,从而命名为C++也叫cpp。c++支持大部分c的语法, 所以c++既可以进行c语言得过程化程序设计,又可以进行面向对象的程序设计。
在学习c++之前 ,应该对c语言有很好的掌握。
开发工具
和c语言一样 仍然以vs为主 本人主页之前介绍过vs的安装即使用

接下来就正式进入正题

c++关键字

c++共有63个关键字
C++入门_第2张图片

命名空间

在学习c语言的时候 可能会遇到下面的情况

#include
int time = 0;
int main()
{
   printf("%d \n", time);
   return 0;
}

这段代码没有任何问题 但是下面这样写就会出问题

#include
#include
int time = 0;
int main()
{
	printf("%d \n", time);
	return 0;
}

time本来是自己定义的一个全局变量 但是在库里面是一个库函数 所以就会出现重定义错误
在c++中就有了命名空间namespac这个概念 来解决c语言的缺陷

命名空间的定义

定 义命名空间,需要使用到namespace关键字

//命名空间
namespace test
{
	//命名空间可以定义变量、函数、结构体等...
	int time = 0;

	int Add(int x, int y)
	{
		return x + y;
	}

	struct student
	{
		int id;
		char name[20];
	};
}

namespace 后面跟命名空间的名字(自定义名称) 然后加{ }即可

命名空间的使用

命名空间的使用方式一共有三种 接下来一一介绍

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

::两个冒号就是c++的作用域限定符

int main()
{
   test::time = 10;
   printf("%d \n", test::time);
   return 0;
}

使用上面命名空间中的time变量 test::time
空间名称加作用域限定符加变量名即可
在引用结构体的时候正确的语法是

struct test::student s1;

而不是

test::struct student s1;

2、使用using将命名空间中某个成员引入

为了避免每次使用变量都要加test::
可以用下面的方法

int main()
{
	using test::time;
	time = 10;
	printf("%d", time);
	return 0;
}

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

int main()
{
	time = 10;
	Add(6, 7);
	struct student s1;
	printf("%d", time);
	return 0;
}

以上就是关于命名空间的知识了下面看一下c++的输出和输出

c++输入&输出

在c语言中 输入输出都需要指定数据类型 %d %f 等等
在c++的输出输出中就不用指定其数据类型 会自动识别类型
在c语言中使用输入输出函数都需要引用头文件stdio.h
在c++中std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中 需要包含头文件iostream

先看输出

#include
using namespace std;
int main()
{
	cout << "Hello C++" << endl;
	return 0;
}

C++入门_第3张图片
cout endl 都是在std命名空间里面的需要引用std
cout 是c++标准输出对象
endl 是换行
<<流插入运算符可以自动识别数据类型

输入

#include
using namespace std;
int main()
{
	int a = 0;
	double b = 0;
	char c = 0;
	cin >> a;
	cin >> b;
	cin >> c;
	cout << a <<  " " << b << " " << c << endl;
	return 0;
}

cin标准输入对象
“>>” 是流提取运算符也可以自动识别数据类型

缺省参数

概念

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

void Print(int a = 0)
{
	cout << a << endl;
}
int main()
{
	Print();//没有传实参  使用形参的值 打印0
	Print(10);//指定实参的值   使用实参指定的值 打印10
	return 0;
}

缺省参数分类

全缺省参数

即函数全部形参都指定一个缺省值
例如

void Print(int a = 10, int b = 10, int c = 10)
{
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

半缺省参数

即函数部分形参指定缺省值
例如

void Print(int a, int b, int c = 10)
{
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

缺省参数注意:
1.半缺省参数必须从右向左依次给 不能间隔着给
例如

//错误代码
void Print(int a, int b=10, int c)
{
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

2.缺省参数不能在函数声明和定义中同时出现

//错误代码
//函数声明
void Print(int a = 0);
int main()
{
	Print(1);
	return 0;
}
//函数定义
void Print(int a = 0)
{
	cout << a << endl;
}

3.缺省值必须时常量或者全局变量

函数重载

函数重载概念

c++允许在同一作用域中声明几个功能类似的同名函数。这些同名函数的形参列表的(参数个数\类型\类型顺序)不同。

//函数重载
//参数类型不同
int Add(int x, int y)
{
	return x + y;
}
double Add(double x, double y)
{
	return x + y;
}
int main()
{
	Add(1, 1);
	Add(1.1, 1.1);
	cout << "Add(1, 1)=" << Add(1, 1) << endl;
	cout << "Add(1.1, 1.1)=" << Add(1.1, 1.1) << endl;
	return 0;
}

//参数个数不同
int Add(int x, int y)
{
	return x + y;
}
int Add(int x, int y,int z)
{
	return x + y + z;
}

int main()
{
	Add(1,1);
	Add(1,1,1);
	cout << "Add(1, 1)=" << Add(1, 1) << endl;
	cout << "Add(1,1,1)=" << Add(1,1,1) << endl;
	return 0;
}
//参数顺序不同
void Fun(char a, int b)
{
	cout << a << endl;
	cout << b << endl;
}
void Fun(int b, char a)
{
	cout << a << endl;
	cout << b << endl;
}
int main()
{
	Fun('a',10);
	Fun(10,'a');
	return 0;
}

引用

引用的概念

引用不是新定义一个变量,而是给已经存在的变量取一个别名 因此编译器不会为引用变量开辟内存空间,和它引用的变量共用用一块空间
语法: 类型& 引用变量名 = 引用实体

	int a = 10;
	int& ra = a;//定义引用类型
int main()
{
	int a = 10;
	int& ra = a;//定义引用类型ra
	cout << "a=" << a << endl;
	cout << "ra=" << ra << endl;
	ra++;//改变ra  实际上就是改变a
	cout << "a=" << a << endl;
	cout << "ra=" << ra << endl;
	a++;//改变a ra也会改变
	cout << "a=" << a << endl;
	cout << "ra=" << ra << endl;
	return 0;
}

引用的特性

1.引用的时候必须初始化

//错误写法

	int a = 10;
	int& ra;

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

	int a = 10;
	int& ra = a;
	int& rb = a;
	int& rc = a;
	int& rd = a;

ra rb rc rd 都是变量a的引用

3.引用一旦引用 在不能引用其他实体

	int a = 10;
	int& ra = a;
	int c = 20;
	ra = c;

ra已经是a的引用 这是想让ra引用c是做不到的

常引用

	const int a = 10;
	//int& ra = a;//a本来是常变量 不能修改 而ra是整形 权限被放大了 语法不支持
	const int& ra = a;//正确写法

	int b = 10;
	const int& rb = b;//b本来是可改的 而rb不能改 权限被缩小了 语法支持

	//int& c = 10;//给常量取别名,常量不能被修改 权限放大 error
	const int& rc = 10;//正确写法

	double d = 3.14;
	//int& rd = d;//类型不同 编译错误
	const int& rd = d;//从double到int会存在隐式类型转换 类型转换会产生临时变量,临时变量具有常性所以支持

关于常引用:引用的权限不能放大但是可以缩小
在类型转换时(隐式类型转换/强制类型转换)会产生临变量 而临时变量具有常性下面这种写法也是可以的

	int i = 1;
	double j = i;//i-->j产生临时变量
	const double& ri = i;

引用的使用场景

1.做参数

void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

和指针类似 函数结束释放形参 也会改变实参
2.做返回值


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

函数内部创建普通局部变量 函数调用结束时布局变量也会被销毁 这种情况不能引用返回 否则结果不确定

int& Count()
{
	static int s_n = 0;
	s_n++;
	return s_n;
}

返回的数据应该时static修饰的或者时malloc的或者时全局变量 不会随着函数调用结束而销毁的数据

引用和指针的区别

在语法上 引用就是一个别名,没有独立空间,和引用实体共用一快空间
在底层实现上实际是有空间的 引用时按照指针的方法来实现的
我们一般只讨论语法
区别
1.引用概念上时一个变量的别名,指针时存储一个变量的地址
2.引用在使用时必须初始化,指针没有要求
3.引用初始化引用一个实体后,不能在引用其他实体。 指针可以在任何时候指向任何同类型实体
4.没有空引用 但是有空指针
5.sizeof中含义不同 引用的结果时引用实体类型的大小 指针的大小是固定的4/8
6.引用++即引用实体自增,指针++即指针向后移动一个类型的大小
7.没有多级引用 但是有多级指针
8.访问实体方式不同 引用编译器自己处理,指针需要进行解引用
9.引用比指针相对来说更安全

内联函数

内联函数的概念

inline修饰的函数叫做内联函数
比如

inline int  Add(int x, int y)
{
   return x + y;
}

内联函数编译器在编译c++时会在调用内联函数的地方进行展开,没有函数调用时建立的栈帧,内联函数提升程序的运行效率
C++入门_第4张图片
C++入门_第5张图片
从汇编代码可以看出 内联函数并没有去调用Add函数这个指令

内联函数的特征

  1. 内联函数是一种以空间换时间的做法,编译器将函数当作内联函数处理时,在编译阶段会用函数本体替换函数调用。
  2. 内联函数对编译器只是一个建议,不同的编译器对内联函数实现的机制可能会有不同。一般采取的措施是:对规模较小的函数,不是递归函数且调用频繁的函数采用inline修饰。否则编译器会忽略inline特性(过大的函数采用inline修饰 编译器会忽略inline特性 按照普通函数调用的方式进行)
  3. 内联函数不建议声明和定义分离,分离会导致链接错误。因为inline被展开后 没有函数地址 链接就会找不到
    内联函数的缺陷:可能会使目标文件变大
    内联函数的优势:少了调用建立栈帧开销,提高程序运行效率

auto关键字

auto简介

在c++11中auto 关键字用于两种情况:声明变量时根据初始化表达式自动推断该变量的类型、声明函数时函数返回值的占位符
比如

   auto a = 10;
   auto b = 1.1;
   auto c = 'c';
   cout << typeid(a).name() << endl;//打印a的类型
   cout << typeid(b).name() << endl;
   cout << typeid(c).name() << endl;

结果分别是int double char

auto的使用规则

1.使用auto必须对其进行初始化

错误示范

auto d;

在编译阶段编译器需要根据初始化表达式来推导auto的类型。因此auto并非一种类型的声明,而是一个类型声明的占位符,在编译阶段时会将auto替换为实际的类型
2.auto与指针和引用结合使用
用auto声明指针类型时 auto和auto*没有任何区别 但是auto声明引用类型时必须加&(auto&)

#include
using namespace std;
int main()
{
  int x = 10;
  auto a = &x;
  auto* pa = &x;
  auto& ra = x;
  cout << typeid(a).name() << endl;//结果为int* 
  cout << typeid(pa).name() << endl;//结果为int*
  cout << typeid(ra).name() << endl;//结果为int
  return 0;
}

3.在同一行定义多个变量
在同一行定义多个变量时 这些变量必须是同一类型 否则编译器会报错
比如

   auto a = 10, b = 10;
   auto c = 10, d = 1.1;//报错

auto不能使用的场景

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

void Test(auto x)
{}

2.auto不能直接用来定义数组

void Test()
{
   auto arr[] = { 1,2,3,4,5 };
}

基于范围的for循环(c++11)

语法

在之前的c语言或c++98中要遍历一个数组 需要按照下面的方式进行

void Test()
{
	int  arr[] = { 1,2,3,4,5 };
	for (int  i = 0; i < sizeof(arr)/sizeof(int); i++)
	{
		//....
	}
}

在c++11中引入了基于范围的for循环 实现方法如下

	for (auto e : arr)
	{
		//...
	}

for循环条件由5两部分组成 第一部分是范围内用于迭代的变量 第二部分表示迭代的范围
会依次取数组中的值赋给e 自动判断结束 自动++向后走
和普通循环一样 也可以同continue和break

使用条件

for循环的迭代范围必须是确定的
下面的例子就是错误的

void Test(int arr[])
{
	for (auto e : arr)
	{
		//...
	}
}

指针空值nullptr(c++11)

c++98中的指针空值

	int* p = NULL;
	int* p = 0;

NULL实际上是一个宏 在传统c头文件中可以看到下面的代码

/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else  /* __cplusplus */
#define NULL    ((void *)0)
#endif  /* __cplusplus */
#endif  /* NULL */

可以看出 NULL可能会被定义成 0 或这是无类型指针(void*) 的常量 因此在定义空指针时 可能会遇到下面的问题

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

程序本意时想通过test(NULL)调用指针版test(int*)函数 但是由于NULL被定义为0 最终调用的时test(int)函数
在C++98中字面常量0,既可以是一个整型数字,也可以是无类型的指针(void*)常量,但编译器默认情况下将其看成是一个整型常量,如果要将其按照指针方式来使用,必须对其进行强制转换。
c++11的空值指针
对于c++98中的问题 c++11引入关键字nullptr

int* p = nullprt;

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

你可能感兴趣的:(C++,c++)