【基础必备】C语言转C++入门篇(各种杂碎知识)

简介

本篇文章学习c++知识,主要是补充C语言的不足之处,同时也为后续C++学习铺路。

命名空间

命名空间来历

C/C++中 变量,函数都是大量存在的,都是存在全局作用域中,且看如下代码:

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{	
	return 0;
}

在这里插入图片描述

报错了,因为rand是包含在stdlib.h中的函数,用来获取随机值,但现在把他当作变量,所以错了。
所以用到命名空间

要用到namespace关键词,后面加命名空间名字和{},记得不用加分号

namespace jibin
{
	int rand=15;
	int Add(int a, int b)
	{
		return a + b;
	}
	struct st
	{
		int a;
		char c;
	};
}

命名空间相当于开辟了一个全新的作用域,里面的东西都局限该域

命名空间使用

  • 第一种 命名空间的名字加 : :
int main()
{	
   int a = 2, b = 3;
   int sum = jibin::Add(a, b);
   printf("%d", sum);
   return 0;
}

相当于专门去访问该域里的Add ,现在就可以编译运行了

  • 第二种 using +命名空间的某个成员
using jibin:: st ;
int main()
{	
   int a = 2, b = 3;
   int sum = jibin::Add(a, b);
   st k;
   k.c = 'm';
   printf("%d", sum);
   printf("%c", k.c);
   return 0;
}
  • 第三种 全部展开
using namespace jibin;
int main()
{	
   int a = 2, b = 3;
   int sum = jibin::Add(a, b);
   st k;
   k.c = 'm';
   printf("%d", sum);
   printf("%c", k.c);
   return 0;
}

C++输入输出函数

学习一门新计算机语言,第一件事肯定输出 Hello World,

  • 使用cin cout函数,1.必须包含iostream头文件,2.以及使用上述方法展开命名空间std
  • "<<"是流插入运算符,“>>"是流提取运算符,endl表示换行
  • 使用该函数非常方便,他们自动识别类型格式,不用再像scanf,printf手动调整,
  • 早期c++包含.h,所有的功能都在全局域实现,后来std发展,为了和c去分就去掉.h了
#include <iostream>
using namespace std;
int main()
{
    int a;
    cin>>a;
	cout << "Hello World!" << endl;
}

std使用问题

  1. 日常学习直接全部展开即可,using namespace std;
  2. 但是全部展开,以后定义变量就可能和std库里重合了,但是日常学习代码量少,问题不大,但如果要做项目代码量大就容易出现冲突,所有项目中最好用std::或者using std::cin,using*std::cout,这种,展开常用即可。

缺省函数

缺省函数是声明或定义函数时,指定一个参数缺省值。 如果没有实参传入,就用缺省值。

#include <iostream>
using namespace std;
void Func(int t=9)
{
   cout << t << endl;
}
int main()
{
   Func();
   Func(5);
   return 0;
}

如果传入5就打印5,否则打印函数缺省值9,

分类

  • 半缺省函数,顾名思义,函数参数一些缺省,一些不缺省,记住一定要从右往左缺省
#include <iostream>
using namespace std;
void Func(int t,int f=5)
{
	cout << t <<" " << f << endl;
}
int main()
{
	Func(1,2);
	Func(3);
	return 0;
}
  • 全缺省函数,即每个参数都有缺省值。
#include <iostream>
using namespace std;
void Func(int t=4,int f=5)
{
	cout << t <<" " << f << endl;
}
int main()
{
	Func();
	Func(1,2);
	Func(3);
	return 0;
}

注意: 1.声明和定义不能都出现缺省值,优先给声明,(万一两处的缺省值不一样)。
2.缺省值必须是常量或全局变量。

函数重载

C语言种如果两个函数名字相同,那就会报错。
但c++中,如果两个函数相同,但参数类型或者数目个数或者类型顺序不同,就能通过。

如果参数相同,但返回类型不同,不够成重载

#include <iostream>
using namespace std;
void Func(int t=4,int f=5)
{
  cout << t <<" " << f << endl;
}
void Func(char c)
{
  cout << c << endl;
}
int main()
{
  Func();
  Func(1,2);
  Func(3);
  Func('m');
  return 0;
}

4 5
1 2
3 5
m

函数运作原理

  • 预处理展开头文件 / 宏替换 / 条件编译 / 去掉注释,后缀.cpp变为.i
  • 编译检查代码,生成汇编代码,后缀 .i 变为 .s,如果有函数声明,那相当于承诺,到链接再兑现,如果是函数定义,那直接实现
  • 汇编汇编代码转为二级制机器码,后缀 .s 变为 .o
  • 链接生成可执行程序,xxx.exe / a.out,找到定义(兑现承诺),

C语言无法区分同名函数,所以不支持重载函数,
但C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。

引用

定义

引用是给一个变量取一个别名,两者共用一块内存,两者关系就像西红柿和番茄的关系 ,引用的存在主要来替代指针作用,符号是&,和取地址符相同。

#include <iostream>
using namespace std;
int main()
{
	int a = 15;
	int& b = a;
	cout<<b<<endl;
	cout <<&a<< endl;
	cout << &b << endl;
	return 0;
}

误区

注意 :
1, 引用类型必须和要引用的类型一致
2,引用必须要有初始化
3, 一个变量可以有多个引用,(可以有多个别名),
4,一个引用有对应之后,不能再引用别人,

const int a = 10;
//int& ra = a;  a是常量,不能更改
const int& ra = a;
//int& b = 10;  10是常量,
const int& b = 10;
double d = 12.133;
//int& dd = d;  类型不同
const int& ddd = d;

应用

void swap(int& a, int& b)
{
	int t = a;
	a = b;
	b = t;
}
int& Add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	int& t = Add(1, 3);
	Add(4, 5);
	cout << t << endl;
	return 0;
}

这里,t的值是随机值,经过第一个Add函数t是4(指向销毁的c),可是第一个函数结束栈就销毁了,第二函数又进行,顶替了原来c的位置,所以t的值不确定。

传值和传引用效率比较

#include <iostream>
#include <ctime>
struct Arr {
	int arr[1000];
};
Arr a;
void Func1(Arr a)
{
	return;
}
void Func2(Arr& a)
{
	return;
}
Arr Func3()
{
	return a;
}
Arr& Func4()
{
	return a;
}
using namespace std;
int main()
{
	Arr a{ 5,8,9,1 };
	const int N = 1000005;
	int begin1 = clock();
	for (int i = 0;i < N;i++)
		Func1(a);
	int end1 = clock();

	int begin2 = clock();
	for (int i = 0;i < N;i++)
	{
		Func2(a);
	}
	int end2 = clock();

	int begin3 = clock();
	for (int i = 0;i < N;i++)
	{
		Func3();
	}
	int end3 = clock();
	int begin4 = clock();
	for (int i = 0;i < N;i++)
	{
		Func4();
	}
	int end4 = clock();
	cout << end1 - begin1 << endl;
	cout << end2 - begin2 << endl;
	cout << end3 - begin3 << endl;
	cout << end4 - begin4 << endl;
	return 0;
}

33
2
72
2

可见 传引用比传值效率明显高很多,因为传引用本质是传地址,而传值要复制,时间花费高。

引用和指针区别

  • 语法概念上讲,引用就是一个别名,没有独立空间,和引用实体共用一块空间
  • 实际底层上,引用有空间,引用本质上是按照指针方式实现的,
	int a = 10;
	int& ra = a;
	ra = 20;

	int* pa = &a;
	*pa = 20;

引用和指针汇编代码对比:
在这里插入图片描述
引用和指针区别
1,引用是变量的别名,指针存的是变量地址。
2,引用定义必须要初始化,指针不用,
3,引用初始化引用一个实体后,不能再引用其他实体,而指针可以随时指向同类型实体。
4,没有NULL引用,但有NULL指针,
5,在sizeof中不同,引用大小是引用实体类型的大小,指针始终是地震空间所占大小(32位是4字节,64位是8字节),
6,自加,引用+1就是引用实体加1,指针+1 是指针向后偏移一个类型的大小。
7,没有多级引用,但有多级指针
8,访问实体方式不同,指针是显式解引用,而引用是编译器自己处理。
9,引用比指针更安全

内联函数

概念

以inline修饰的函数,在程序编译时会用函数体替换掉原来函数位置,减少栈的开销,提高效率。

特性

1,内联函数是牺牲空间换时间做法, 缺陷就是会使目标文件增大
2,编译器会自主选择是否进行内联,就算加上inline,编译器也会自主选择是否内联,那种函数短小且被多次调用的而且不是递归就会内联,
3,内联函数定义和声明不能分离,不然导致链接错误,因为inline展开,函数就被函数体替换了,函数地址消失,导致链接找不到函数地址,

#include <iostream>
using namespace std;
inline int Add(int a, int b)
{
	a++;b++;
	return a + b;
}
int main()
{
	int t = 0;
	for (int i = 0;i < 1000;i++)
	{
		t = Add(2, 3);
	}
}

如果不内联,反汇编代码行数(忽略其他): 1000+3,(会call函数地址),
内联就是1000*3,将函数体替换过去了

#define Add(a,b) ((a)+(b))

或者可以用宏代替,

【面试题】
宏的优缺点?
优点:
1.增强代码的复用性。
2.提高性能。
缺点:
1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。
C++有哪些技术替代宏?

  1. 常量定义 换用const enum
  2. 短小函数定义 换用内联函数

auto

随着c++学习,类型越来越多,复杂,长度也长,所以auto发挥作用,自动识别类型

注意: 编译时,auto会被替换成实际所需类型

auto 与指针和引用结合

auto当作指针用时,加不加 * 无所谓,但是当引用用时必须加 &

#include <iostream>
using namespace std;
int main()
{
	int x = 10;
	auto a = &x;
	auto* ra = &x;
	auto& c = x;
	* a = 12;
	cout << *ra << endl;
	c = 20;
	cout << *a  << " " << c << endl;
	return 0;
}

12
20 20

auto与for循环使用

int arr[] = { 1,5,2,6,8 };
for (auto& x : arr)
{
	x *= 2;
	cout << x << endl;
}

2
10
4
12
16

auto会获得数组长度,从开头到结尾依次将数组读取到x中,

//错误示例
void test(int arr[])
{
	for (auto& x : arr)
		cout << x;
}

这种错误,因为数组作参数接受是以指针方式接受的,丢失了长度信息,auto无法确定开头结尾,所以用不了。

nullptr

C语言中NULL实际上代表0,与我们想要“空指针”含义有别,c++中我们用nullptr代替NULL,
使用nullptr时不用包含头文件,null是c++的关键词,
sizeof()大小与sizeof((void*)0)一致是8字节,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值