C++学习笔记

Posted 你算哪一个bug?

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++学习笔记相关的知识,希望对你有一定的参考价值。

文章目录

🌲C++关键字

C++一共有63个关键字,C语言有三十二个。

C++关键字

C++兼容C绝大多数的语法

🌲第一个C++程序

#include<iostream>
using namespace std;
int main()

	cout << "hello C++!" << endl;
	return 0;

阅读完之后出现了下面几个问题

🌴cout与endl的解释

cout<<“hello C++”<<endl
cout的功能是打印,相当于printf

end的作用是换行,相当于‘\\n’

<<是输出运算符/流插入运算符

运行效果:

  • C++中cout与C printf相对应,那C里的 scanf 和C++ 中的哪个标识符对应?

scanf对应C++里的 cin

printf – cout scanf–cin

两种方法用起来怎么方便怎么来

提示:

  • printf 和 scanf 速度会比 cout 和cin 快十倍左右,写题时优化速度可以考虑
  • cout和cin用起来更方便,可以自动识别类型
  • cout打印double默认是五位小数
  • printf和scanf在输入输出时可以指定格式,更加自由

🌴#include< iostream>是什么东西?

头文件,只不过没有了.h的标志, 头文件里包括了一些基本的输入输出流的方法,比如cout和cin

cout是输出流类对象,cin是输入流类对象

此外,iostream文件和iostream.h文件(确实有)是两个文件

实质上类似于#include<stdio.h>

🌴using namespace std有什么作用?

将命名空间std里的标识符(变量,函数等)展开,比如std这个命名空间里就有cout

std是包含C++标准库的命名空间

🌵命名空间

引论:一个大型项目,需要多人协作完成,其中难免发生重名的现象,为了避免这种同名的情况发生,就有了命名空间

我们使用的变量如果与库里的变量同名也可以使用定义命名空间的方法解决

  • 什么是命名空间?

ANSIC++引入的可以由用户命名的作用域

翻译:在这个作用域(花括号)里你可以定义变量,由于每个域都不同,在使用变量时只要前面加上域的名字即使同名也可以被区分为不同的变量

  • 命名空间的作用?

解决命名冲突

  • 命名空间的用法

1.用法一:通过两个冒号来使用命名空间里的东西(变量等等)

#include<iostream>
using namespace std;
namespace ck

	int a = 0;

int main()

	cout << ck::a << endl;
	return 0;

说明我们用命名空间里的东西(变量名,函数等)需要把这个变量属于哪个命名空间交代清楚,交代的方法就是通过 :: (两个冒号)

用法二

上面说过cout和endl是属于命名空间std的,using namespace std中using的作用就是展开,类似于把std里所有的东西都声明到全局,所以可以直接用

如果我们去掉using namespace std 但是又想使用cout和endl,那怎么办呢?
答:用 :: 交代出cout和endl是属于命名空间std的即可

即 std::cout << “hello C++”<< std::endl;

下面两段代码作用是相同的,都会打印hello C++

用法三:命名空间可以合并

#include<iostream>
using namespace std;
namespace ck

	int a = 0;

namespace ck

	int b = 100;

int main()

	cout <<"a:"<< ck::a << endl;
	cout <<"b: "<<ck::b << endl;
	return 0;

如何使用命名空间里的东西(用法小结):

1.using namespace xx

将xx命名空间里的所有东西展开到全局

优点:方便

缺点:把自己的定义暴露(曝光)出去了,如果里面东西太多可能导致命名污染

  1. :: 要用的时候用 :: 表示出变量(函数等)属于哪块命名空间

如std::cout

优点:不容易导致命名污染

缺点:麻烦

  1. 折中

如:using std::cout

每次使用时也不用写std::cout了,直接用即可,也没有展开整个std,也不是很麻烦

namespace 可以嵌套

#include<iostream>
using namespace std;
namespace ck

	int Add(int a, int b)
	
		return a + b;
	
	struct People
	
		int height;//身高
		int age;//年龄
	;
	
	namespace ck_2
	
		int a=0;
	

int main()

	ck::People people =  180, 18 ;
	cout << "ADD: " << ck::Add(1, 2) << endl;
	cout << "people height: " << people.height << endl;
	cout << "a: "<<ck::ck_2::a << endl;

🌲缺省参数

说起参数,多半就和函数相关了

🌴缺省参数是什么?

声明或定义函数时给函数参数指定的一个默认值,如果调用 函数时没有传入实参就使用这个默认值

例:

#include<iostream>
using namespace std;
void func(int a = 20)

	cout <<"a: "<< a << endl;

int main()

	func();
	return 0;

🌴全缺省和半缺省

全缺省:

#include<iostream>
using namespace std;

void func(int a = 20,int b=30)

	cout <<"a: "<< a << endl;
	cout << "b:" << b << endl;

int main()

	func();
	return 0;


半缺省:

#include<iostream>
using namespace std;

void func(int a ,int b=20)

	cout <<"a: "<< a << endl;
	cout << "b:" << b << endl;

int main()

	func(10);
	return 0;

注:

  • 缺省只能从右往左缺省,即从右往左给定默认值,不然会造成起义

  • 声明和定义不能都设定默认值,不然会报错,建议写在声明

🌲函数重载

🌴什么是函数重载?

C++允许在同一作用域下存在同名函数,同名函数要求参数的类型、个数、顺序里至少有一个不同

注:和返回值无关

🌴函数重载的作用?

实现功能类似,数据类型不同

比如 int Add(int a,int b) //这个函数就只能实现整形的加法

double Add(double a,double b) //重载后这个函数通过传不同的参数可以实现浮点数的加法

函数重载可以通过传递不同的参数来完成类似的功能,也可以接收多种类型数据,对多种类型的数据进行操作

🌴为什么C++支持函数重载,而C不支持?

函数在编译时会生成一张符号表(本质是哈希表)

C++ :

函数名编译器生成的名字
Add(int a,int b)_Z3Addii
Add(double a,double b)_Z3Adddd
Add(int a,float b)_Z3Addif

C++会代入参数特点对函数名进入修饰(哈希规则不同)

重载函数因为参数不同,所以在编译时期生成的符号表中的对应关系也不同

也即重载函数因为参数不同在编译器里的名字就不同

比如编译器认为两个重载函数,一个叫函数1号,一个叫函数2号,这样编译器就能区分重载的函数了

C:

C编译器生成的符号表就是函数自己的名字,也即修饰规则和参数等没有关系,只和自己的函数名字有关,自然同名时会产生歧义,所以不支持重载

小结:函数名的修饰规则不同导致了C++支持重载,C不支持重载

随笔记录:strcat追加时需要留好充足的空间

🌲extern c

上面说过,C和C++对函数名的修饰规则不同

gcc认为.c的为C程序,.cpp的为C++程序

g++认为.c和.cpp的都是C++程序

这就导致了一个问题,test.h里面有test.c的函数声明,如果是gcc去编译test.c的文件,文件生成的符号表是.c的,.cpp去调用C文件中的函数,就会导致编译通过而链接错误,因为链接时连接器找的函数名是C++修饰过的,而生成的符号表是.c的,以C++的方式寻找肯定找不到

举个例子:

所以此时就要告诉编译器test.c是根据C的方式编译的,铺垫了这么久,extern C就上场了,他会告诉编译器这部分是按照C语言来编译的,所以要修正上面的链接错误,做法是:

简单来说,C和CPP都可以使用extern "C"修饰过的文件

c++兼容C用C文件没问题,C用C的方式来编译C++函数自然就可以用C++的东西了


举个例子:

谷歌用C++写了一个叫做tcmalloc的库,里面提供了更高效的malloc和free方法,但如果是用C++写的,那C语言要使用C++写的东西肯定要用C的方式编译才能被识别,即C文件使用这个库中的函数时必须得加上extern “C”


链接时会根据生成的符号表去找函数

Linkerror : 有声明没定义

编译时通过了,链接时没找到

🌴总结

C程序和C++程序都可以调用被extern ”C“修饰的函数

🌲引用

🌴什么是引用?

引用不是新定义一个变量,而是给变量起一个别名,编译器不会给这个变量开辟内存空间,它和它引用的变量共用同一块内存空间

指针是定义一个指针变量存储地址

引用的底层实现是开辟了空间的,换而言之,编译器屏蔽了引用和指针的差别

例:

#include<iostream>
using namespace std;
int main()

	int a = 1;
	int& b = a;
	cout << b << endl;	


🌴测试引用是不是同一块内存空间:

#include<iostream>
using namespace std;
int main()

	int a = 1;
	int& b = a;
	cout << &b << endl;
	cout << &a << endl;

由于是同一块内存空间,函数传引用可以改变实参

例2:

🌴临时变量具有常性

#include<iostream>
using namespace std;
int main()

	int a = 1;
	int& b = a;
	double& c = b;//报错 error C2440: “初始化”: 无法从“int”转换为“double &
	cout << c << endl;

double& 具有读写权限 const double&只有读权限

🌴使用场景

  • 函数传引用可以减少拷贝

比如我们传参时不会选择传入整个结构体一样,会选择传入结构体的引用

  • 传参时如果不改变引用的值可以加上const保护形参

场景一:

#include<iostream>
using namespace std;
void swap(int& x, int& y)

	int tmp = x;
	x = y;
	y = tmp;

int main()

	int x = 1, y = 2;
	swap(x, y);
	cout << "x:" << x << endl;
	cout << "y:" << y << endl;

	return 0;

场景二:

#include<iostream>
using namespace std;

int& Add(int x, int y)

	int ans = x + y;
	return ans; 

int main()

	int a = Add(1, 2);//
	Add(3, 4);
	cout << a << endl;//打印3?但是哪里错了?
	return 0;

场景三:

#include<iostream>
using namespace std;
int& Add(int x, int y)

	int ans = x + y;
	return ans;

int main()

	int& a = Add(1, 2);//比起上一个场景  这个a的类型为引用类型
	Add(3, 4);
	cout << a << endl;
	return 0;

场景四:

引用必须初始化

🌴引用和指针的不同点

  • 指针开辟了空间存储地址,指针没有
  • 引用必须初始化,指针不用,并且指针可以更改指向
  • sizeof是引用类型的大小,而sizeof指针是指针变量的大小
  • 引用+1是实体+1,指针+1根据指针类型往后偏移
  • 访问实体的方式不同,指针需要解引用
  • 引用比指针相对安全

🌲整形提升实例

int main()

	char ch = 0xff;
	int i = 0xff;
	if (ch == i)//整形提升 
	
		cout << "相同" << endl;
	
	else
	
		cout << "不相同" << endl;
	

以上是关于C++学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

javaScript学习笔记(与c++等不同之处)

C++学习笔记.关键字static&静态成员变量

C++学习笔记.关键字static&静态成员变量

C++学习笔记.关键字static&静态成员变量

C++基础学习笔记命名空间 namespace 的理解和使用

《Effective C++》学习笔记