✨✨小新课堂开课了,欢迎欢迎~✨✨
🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:C++:由浅入深篇
小新的主页:编程版小新-CSDN博客
前言:正式进入知识点的学习之前,我们先来简单的了解一下C++吧。
一:C++的发展史
C++的起源可以追溯到1979年,当时Bjarne Stroustrup(本贾尼·斯特劳斯特卢普,这个翻译的名字不同的地⽅可能有差异)在贝尔实验室从事计算机科学和软件工程的研究工作。面对项目中复杂的软件开发任务,特别是模拟和操作系统的开发工作,他感受到了现有语言(如C语言)在表达能力、可维护性和可扩展性方面的不足。
1983年,Bjarne Stroustrup在C语言的基础上添加了面向对象编程的特性,设计出了C++语言的雏形,此时的C++已经有了类、封装、继承等核心概念,为后来的面向对象编程奠定了基础。这⼀年该语言被正式命名为C++。
在随后的几年中,C++在学术界和工业界的应用逐渐增多。⼀些大学和研究所开始将C++作为教学和研究的首选语言,而一些公司也开始在产品开发中尝试使用C++。这一时期,C++的标准库和模板等特性也得到了进⼀步的完善和发展。
C++的标准化⼯作于1989年开始,并成立了⼀个ANSI和ISO(International Standards Organization)国际标准化组织的联合标准化委员会。1994年标准化委员会提出了第⼀个标准化草案。在该草案中,委员会在保持斯特劳斯特卢普最初定义的所有特征的同时,还增加了部分新特征。
在完成C++标准化的第⼀个草案后不久,STL(Standard Template Library)是惠普实验室开发的⼀系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室⼯作时所开发出来的。在通过了标准化第⼀个草案之后,联合标准化委员会投票并通过了将STL包含到C++标准中的提议。STL对C++的扩展超出C++的最初定义范围。虽然在标准中增加STL是个很重要的决定,但也因此延缓了C++标准化的进程。
1997年11月14日,联合标准化委员会通过了该标准的最终草案。1998年,C++的ANSI/IS0标准被投入使用。
二:C++版本的更新
现在大多数企业还是在沿用C++98和C++11这两个标准。
三:C++的重要性
3.1最新编程语言排行榜
3.2C++的就业方向
四:C++的第一个程序
//test.cpp
#include<stdio.h>
int main()
{
printf("hello world\n");
return 0;
}
// test.cpp
#include<iostream>
using namespace std;
int main()
{
cout << "hello world\n" << endl;
return 0;
}
这里的std ,cout,endl等我们都看不懂,没关系,下面我们会依次讲解。
五:命名空间
5.1命名空间的价值
#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
printf("%d\n", rand);
return 0;
}
运行结果:
这里的报错其实就是 rand重定义。这里rand重定义的原因是rand与<stdlib.h>这个头文件中的rand函数同名,printf函数分不清是哪一个。更详细的解释我们放在命名空间的后面一些讲解。
5.2namespace(命名空间)的定义
1• 定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
#include <stdio.h>
#include <stdlib.h>
// 1. 正常的命名空间定义
// labi是命名空间的名字,一般开发中是用项目名字做命名空间名。
namespace labi
{
// 命名空间中可以定义变量/函数/类型
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
int main()
{
// 这里默认是访问的是全局的rand函数指针
printf("%p\n", rand);
// 这里指定labi命名空间中的rand
printf("%d\n", labi::rand);//::是用来访问命名空间的
return 0;
}
2• namespace本质是定义出一个域,这个域跟全局域,局部域各自独立,不同的域可以定义同名变量,所以下面的a不在冲突了。
#include <stdio.h>
#include <stdlib.h>
namespace labi
{
//命名空间域
int a = 10;
}
int main()
{
//局部域
int a = 1;
//默认会在局部域和全局域中找,不会找命名空间
printf("%d\n", a);
printf("%d\n", labi::a);
}
运行结果:
3• C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所以有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的声明周期,命名空间域和类域不影响变量声明周期。
4• namespace只能定义在全局,当然他还可以嵌套定义。
#include <stdio.h>
#include <stdlib.h>
// 命名空间可以嵌套
namespace haha
{
//蜡笔
namespace labi
{
int rand = 1;
int Add(int left, int right)
{
return left + right;
}
}
//小新
namespace xiaoxin
{
int rand = 2;
int Add(int left, int right)
{
return (left + right) * 10;
}
}
}
int main()
{
printf("%d\n", haha::labi::rand);
printf("%d\n", haha::xiaoxin::rand);
printf("%d\n", haha::labi::Add(1, 2));
printf("%d\n", haha::xiaoxin::Add(1, 2));
return 0;
}
运行结果:
5• 项目工 程中多文件中定义的同名namespace会认为是一个namespace,不会冲突。
//stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
namespace labi
{
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* ps, int n);
void STPush(ST* ps, STDataType x);
}
//stack.cpp
#include"stack.h"
namespace labi
{
void STInit(ST* ps, int n)
{
assert(ps);
ps->a = (STDataType*)malloc(n * sizeof(STDataType));
ps->top = 0;
ps->capacity = n;
}
// 栈顶
void STPush(ST* ps, STDataType x)
{
assert(ps);
// 满了, 扩容
if (ps->top == ps->capacity)
{
printf("扩容\n");
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity
* 2;
STDataType* tmp = (STDataType*)realloc(ps->a,
newcapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity = newcapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
}
6• C++标准库都放在⼀个叫std(standard)的命名空间中。
5.3命名空间的使用
1• 指定命名空间访问,项目中推荐这种方式。
#include<stdio.h>
namespace labi
{
int a = 0;
int b = 1;
}
int main()
{
// 编译报错:error C2065: “a”: 未声明的标识符
//printf("%d\n", a);
printf("%d\n", labi::a);
return 0;
}
2• using将命名空间中某个成员展开,项目中经常访问的不存在冲突的成员推荐这种方式。
#include<stdio.h>
namespace labi
{
int a = 0;
int b = 1;
}
// using将命名空间中某个成员展开
using labi::b;
int main()
{
printf("%d\n", labi::a);
printf("%d\n", b);
return 0;
}
3• 展开命名空间中全部成员,项目不推荐,冲突风险很大,日常小练习程序为了方便推荐使用。
#include<stdio.h>
namespace labi
{
int a = 0;
int b = 1;
}
// 展开命名空间中全部成员
using namespace labi;
int main()
{
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
六:C++的输入和输出
#include<iostream>
using namespace std;
int main()
{
cout << "hello world\n" << endl;
return 0;
}
现在我们就来解答我们遇到的第一个C++程序的吧。
#include<iostream>
using namespace std;
int main()
{
int i = 1234;
int j = -1234;
cout << i << endl;
cout << j << endl;
return 0;
}
运行结果:
示例二:
#include<iostream>
using namespace std;
int main()
{
int a = 0;
double b = 0.1;
char c = 'x';
cout << a << " " << b << " " << c << "\n" << '\n' << endl;
std::cout << a << " " << b << " " << c << std::endl;
//cout 和 std::cout一个意思
//自动识别类型
return 0;
}
运行结果:
示例三:
#include<iostream>
using namespace std;
int main()
{
int a = 0;
double b = 0;
char c = 0;
scanf("%d%lf", &a, &b);
printf("%d %lf\n", a, b);
// 可以自动识别变量的类型
//cin >> a;
//cin >> b >> c;
cin >>a>> b >> c;
cout << a << endl;
cout << b << " " << c << endl;
return 0;
}
运行结果:
七:缼省参数
#include <iostream>
#include <assert.h>
using namespace std;
void Func(int a = 0)
{
cout << a << endl;
}
int main()
{
Func(); // 没有传参时,使⽤参数的默认值
Func(10); // 传参时,使⽤指定的实参
return 0;
}
运行结果:
示例二:
#include <iostream>
using namespace std;
// 全缺省
void Func1(int a = 10, int b = 20, int c = 30)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
// 半缺省
//从右往左依次缼省,不得跳跃
void Func2(int a, int b = 10, int c = 20)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl << endl;
}
int main()
{
Func1();
Func1(1);
Func1(1, 2);
//从左往右依次给参数,不得跳跃
//Func1(1, ,3)这种写法错误
Func1(1, 2, 3);
Func2(100);
Func2(100, 200);
Func2(100, 200, 300);
return 0;
}
运行结果:
示例三:
// Stack.h
#include <iostream>
#include <assert.h>
using namespace std;
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
//声明
void STInit(ST* ps, int n = 4);
// Stack.cpp
#include"Stack.h"
// 缺省参数不能声明和定义同时给
void STInit(ST* ps, int n)
{
assert(ps && n > 0);
ps->a = (STDataType*)malloc(n * sizeof(STDataType));
ps->top = 0;
ps->capacity = n;
}
#include"Stack.h"
int main()
{
ST s1;
STInit(&s1);
// 确定知道要插⼊1000个数据,初始化时⼀把开好,避免扩容
ST s2;
STInit(&s2, 1000);
return 0;
}
八:函数重载
#include<iostream>
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;
}
int main()
{
Add(10, 20);
Add(10.1, 20.2);
f();
f(10);
f(10, 'a');
f('a', 10);
return 0;
}