【C++】初学者的浪漫编程指南

  少年不惧岁月长,彼方尚有荣光在。 

前言

  这是我自己学习C++的第一篇博客总结。后期我会继续把C++学习笔记开源至博客上。

C++的兼容性

1. C++兼容绝大多数C语言的语法,因此只需要把 .c 后缀文件改为 .cpp 即可。

2. VS编译器看到是.cpp就会调用C++编译器编译。

#define _CRT_SECURE_NO_WARNINGS
#include 
int main()
{
	printf("hello world\n");
	return 0;
}
//hello world

//实际上应该这样写
#include 
using namespace std;//将标准库展开后,调用标准库的函数时,就可以不需要作用域限定符。
int main()
{
	cout << "hello world" << endl;
	return 0;
}
//hello world
#define _CRT_SECURE_NO_WARNINGS
#include 
using namespace std;
int main()
{
	int sum = 0;
	int val = 0;
	while (cin >> val)
	{
		sum += val;
	}
	cout << sum;
	return 0;
}
//输入 1 2 3 4 5 a
//输出 15

命名空间

namespace关键字

1. 在 C/C++ 中,变量、函数和类都是大量存在的,这些变量、函数和类的名称,如果都存在于全局作用域中,则可能会导致很多冲突。
2. 使用命名空间的目的是对标识符的名称进行本地化,避免命名冲突或名字污染。
3. 定义命名空间时,需要使用到 namespace 关键字,后面跟命名空间的名字,然后接⼀对 { } 即可, { } 中即为命名空间的成员。命名空间中可以定义变量、函数、类型等。
4.  namespace 本质是定义⼀个域,创建一个命名空间,这个域跟其他的域相互独立。
5. 不同的域可以定义同名变量,但同一个域不能定义同名变量。
6. 命名空间域和类域只能在全局域中定义,原本就是为了在全局域中进行隔离。所以里面的变量、函数的生命周期都是全局的。
7. 命名空间域里面可以继续嵌套命名空间域,使用里面内容时需要多用几个作用域限定符。
8. 多个文件中可以定义同名 namespace ,它们会默认合并到⼀起,就像同⼀个 namespace ⼀样。
9.  C++ 标准库都放在⼀个叫 std(standard) 的命名空间中。
10. 域分为局部域、全局域、名命空间域和类域。
#define _CRT_SECURE_NO_WARNINGS
#include 
namespace hsy
{
	int rand = 10;//命名空间域相当于在全局域中划出一片区域,形成独立的命名空间域
}
int main()
{
	printf("%d\n", hsy::rand);//10
    return 0;
}
x//局部变量的x
::x//全局变量的x
hsy::x//命名空间hsy的x
:://域作用限定符
#define _CRT_SECURE_NO_WARNINGS
#include 
namespace hsy
{
	namespace yhy
	{
		int rand = 2024;
	}
	namespace sbd
	{
		int rand = 2023;
	}
}
//命名空间域里面可以继续嵌套命名空间域。
int main()
{
	printf("%d\n", hsy::yhy::rand);//2024
	printf("%d\n", hsy::sbd::rand);//2023
    return 0;
}

命名空间的使用

1. 编译查找⼀个变量的声明、定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找。

2. 所以我们要使用命名空间中定义的变量、函数,有三种方式:

  1. 指定命名空间访问。
  2. using将命名空间中某个成员展开。
  3. using展开命名空间中全部成员。
#include
namespace hsy
{
	int a = 0;
	int b = 1;
}

int main()
{
	printf("%d\n", a);// 编译报错:error C2065: “a”: 未声明的标识符
	return 0;
}

int main()
{
	printf("%d\n", hsy::a);// 指定命名空间访问
	return 0;
}

using hsy::b;// using将命名空间中某个成员展开,相当于把命名空间域hsy里面的东西暴露在全局域中
int main()
{
	printf("%d\n", hsy::b);
	printf("%d\n", b);//效果相同
	return 0;
}

using namespce hsy;// 展开命名空间中全部成员
int main()
{
    printf("%d\n", a);
    printf("%d\n", b);
    return 0;
}

C++的输入输出

1. 头文件,是Input Output Stream的缩写,包括了标准的输入、输出流库,定义了标准的输入、输出对象。

2. <<是''流插入''运算符,>>是''流提取''运算符。

3. std::cinistream类的对象,标准输入流。

4. std::coutostream类的对象,标准输出流。

5. std::endl是⼀个函数,相当于插入⼀个换行字符加刷新缓冲区。

6. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动指定格式,C++的输入输出可以自动识别变量类型。

7. cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间域中,所以要通过命名空间的使用方式去用他们。

8. ⼀般日常练习中我们可以using namespace std;。(使用标准库函数时候更方便)

#include 
using namespace std;
int main()
{
	int a = 0;
	cout << a << " " << 'b' << endl;// 可以⾃动识别变量的类型
	std::cout << a << " " << 'b' << std::endl;// 可以⾃动识别变量的类型
	return 0;
}
//0 b
//0 b

缺省参数

1. 缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。
2. 在调用该函数时,如果没有指定实参,则采用该形参的缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省参数。
3.  全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。
4.  C++ 规定半缺省参数必须从右往左 依次连续缺省,不能间隔跳跃给缺省值。
5.  函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省 值。
#include 
using namespace std;
void Add(int a = 10, int b = 5)
{
	cout<<(a + b)<
#include 
#include 
using namespace std;
typedef int StackDataType;
typedef struct Stack
{
	StackDataType* arr;
	int top;
	int capacity;
}Stack;
void StackInit(Stack* ps, int n = 4);// 如果函数声明和定义同时存在时,则在函数声明时给定缺省值


void StackInit(Stack* ps, int n)
// 缺省参数不能声明和定义同时给,如果函数声明时候给了,则函数定义时候就不能给。
{
	assert(ps);
	ps->arr = (StackDataType*)malloc(n * sizeof(StackDataType));
	ps->top = 0;
	ps->capacity = n;//如果没传入n的值,那么使用缺省参数为4
}


int main()
{
	Stack s1;
	StackInit(&s1);
	Stack s2;
	StackInit(&s2, 1000);// 确定知道要插⼊1000个数据,初始化时⼀把开好,避免扩容
	return 0;
}

函数重载

1. C语言不支持同⼀作用域中出现同名函数的。

2. C++支持在同⼀作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者参数类型不同。

3. 函数重载是通过函数参数类型、个数的不同来加以区分的。

#include
using namespace std;

// 1、参数类型不同
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	return left + right;
}

// 2、参数个数不同
void f()
{
	cout << "f()" << endl;
}
void f(int a)
{
	cout << "f(int a)" << endl;
}

// 3、参数类型顺序不同
void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
	cout << "f(char b, int a)" << endl;
}

// 返回值不同不能作为重载条件,因为调⽤时⽆法通过参数区分
void fxx()
{}
int fxx()
{
    return 0;
}

// 下⾯两个函数构成重载
// 但是f()但是调⽤时,会报错,存在歧义,编译器不知道调⽤谁,可能是第一个函数没有参数,可能是第二个函数缺省参数。
void f1()
{
	cout << "f()" << endl;
}
void f1(int a = 10)
{
	cout << "f(int a)" << endl;
}

引用

引用的概念

1. 引用不是新定义⼀个变量,而是给已存在变量取了⼀个别名,编译器不会为引用变量开辟内存空间, 它和它引用的变量共用同⼀块内存空间。
2. 引用格式: 类型& 引用别名=引用对象  。
3. 区别于 typedef 关键字, typedef 关键字用于给类型取别名,而引用多用于给变量取别名。
4. 引用可以用来代替往函数里面传地址的操作。
#include
using namespace std;
int main()
{
	int a = 0;
	// 引⽤:b和c是a的别名
	int& b = a;
	int& c = a;
	// 也可以给别名b取别名,d相当于还是a的别名
	int& d = b;
	++d;
	// 这⾥取地址我们看到是⼀样的
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	cout << &d << endl;
	return 0;
}
#include 
using namespace std;
void swap1(int x,int y)
{
	int mid;
	mid = y;
	y = x;
	x = mid;
}
void swap2(int& rx, int& ry)
{
	int mid;
	mid = ry;
	ry = rx;
	rx = mid;
}
int main()
{
	int a = 10;
	int b = 20;
	swap1(a, b);//没交换
	cout << a << " " << b << endl;
	swap2(a, b);//交换了
	cout << a << " " << b << endl;
	return 0;
}

引用的特性

1. 引用在定义时必须初始化,指针在引用时候不一定要初始化。

2. ⼀个变量可以有多个引用。

3. 引用⼀旦引用⼀个实体,再不能引用其他实体。

4. 由第三条特性可知:引用不能替代指针。(引用是用来辅助指针的)

int a=20,b=30;
int& pa=a;//引用pa是变量a的别名
pa=10;//把10赋值给pa,就是把10赋值给a
pa=b;//这里不是把引用pa重新设定为变量b的别名,而是把b的值赋值给pa,即把b的值赋值给a
#include 
using namespace std;
int main()
{
	int a = 10;
	int& b = a;//不能这样: int& b;
	int& c = b;
	cout << a << " " << b << " " << c << endl;//10 10 10
	int e = 20;
	b = e;//把e的值赋值给b(a)(c)
	cout << a << " " << b << " " << c << " " << e << endl;//20 20 20 20
	return 0;
}

引用的使用

1. 引用主要是于引用传参,改变引用对象(rx,ry)时同时改变被引用对象(x,y)

2. 引用传参跟指针传参功能是类似的,引用传参相对更方便⼀些。(实现数据结构时候更容易理解)

#include 
using namespace std;
void Swap(int& rx, int& ry)
{
	int tmp = rx;
	rx = ry;
	ry = tmp;
}
int main()
{
	int x = 0, y = 1;
	cout << x << " " << y << endl;
	Swap(x, y);//改变引用对象(rx,ry)的同时,改变被引用对象(x,y)。
	cout << x << " " << y << endl;
	return 0;
}

const引用 

1. const引用时候,权限不能放大,但是可以缩小。

2. 对变量进行赋值时,在计算中间值和类型转换中会产生临时量对象,而C++规定临时量对象具有常属性,所以这里就触发了权限放大,必须要用const引用才可以。

3. 在自定义函数传参时候,形参建议使用const引用,这样传入的实参形式就更多样

#include 
using namespace std;
int main()
{
	const int a = 10;
	int& ra = a;//报错,const引用权限不能放大,a已经被const引用限定,那么a的别名ra也必须被const引用限定
    const int& ra = a;//正确
	int b = 20;
    const int& rb = b;//不会报错,const引用权限可以缩小,b没有被const引用限定,那么b的别名rb可以被const引用限定
    int c = 30;
    int& rc = c * 3;//报错,引用过程中出现了计算中间值,中间值是临时量对象,默认已经用const引用
    const int& rc = c * 3;//正确
    return 0;
}
void Add(const int& ra)

Add(3);
Add(3*5);
Add(3.12);

指针与引用

1. 语法概念上,引用是⼀个变量的取别名,不开空间;指针是存储⼀个变量地址,要开空间。
2. 引用在定义时必须初始化;指针建议初始化,但是语法上不是必须的。
3. 引用在初始化时,引用⼀个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象。
4. 引用可以直接访问指向对象;指针需要解引用才是访问指向对象。
5.  sizeof() 中含义不同,引用结果为引用类型的大小;但指针始终是地址空间所占字节个数。
6. 指针很容易出现空指针和野指针的问题;引用很少出现,引用使用起来相对更安全⼀些。

inline内联修饰 

1. 用inline修饰的函数叫做内联函数,编译时C++编译器会在调用的地方直接展开内联函数,这样调用内联函数时就不需要建立栈帧了,可以提高效率。

2. inline对于编译器而言只是⼀个建议,inline适用于频繁调用的短小函数,对于代码相对多⼀些的函数,使用inline修饰也会被编译器忽略。

3. C语言宏的本质就是在编译的时候进行替换,C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不方便调试。C++设计了inline目的就是替代C的宏函数。

4. inline修饰函数时,不建议声明和定义分离到两个文件,因为分离会导致链接错误。

#define _CRT_SECURE_NO_WARNINGS
#include 
#define Add(x,y) ((x)+(y))
//后面不能加分号
//必须加外面的括号
//必须加里面的括号
using namespace std;
int main()
{
	int ret = Add(1, 2);
	cout << ret << endl;
	return 0;
}

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

nullptr空指针 

1. 程序员通常会用0NULL来表示一个空指针。但是这种方式存在一些潜在的问题,主要是因为0NULL实际上是整数常量,在某些情况下可能会导致意外的类型转换。

2. C++11中引入nullptr(null pointer)nullptr是⼀个特殊的关键字,它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,而不能被转换为整数类型。

3. nullptr提供了一种更安全、更清晰的方式来表示空指针,有助于减少错误并提高代码的可读性和安全性。

void f(int) 
{
    std::cout << "Integer version" << std::endl;
}

void f(char*) 
{
    std::cout << "Pointer version" << std::endl;
}

int main() 
{
    f(0);      // 可能调用f(int),也可能调用f(char*),取决于编译器
    f(nullptr); // 明确调用f(char*),因为nullptr明确指向一个指针
}

致谢 

  感谢您花时间阅读这篇文章!如果您对本文有任何疑问、建议或是想要分享您的看法,请不要犹豫,在评论区留下您的宝贵意见。每一次互动都是我前进的动力,您的支持是我最大的鼓励。期待与您的交流,让我们共同成长,探索技术世界的无限可能!

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