一.C++简介
C++ 是一种广泛使用的计算机编程语言,它支持过程化编程、面向对象编程以及泛型编程。C++ 被设计为一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,它支持过程化编程、面向对象编程和泛型编程。C++ 被认为是一种中级语言,它包含了高级语言的特性,如类和对象,同时也提供了低级语言的特性,如内存管理和指针操作。
C++ 是由 Bjarne Stroustrup 在 1983 年在贝尔实验室开发的,作为 C 语言的扩展,它最初被命名为 “C with Classes”,之后在 1983 年更名为 C++。C++ 旨在提供一种更高效的编程方式,同时保持与 C 语言的兼容性,这使得 C++ 成为 C 语言的一个超集,几乎所有的 C 程序都是合法的 C++ 程序。
C++ 的主要特点包括:
- 面向对象编程:C++ 支持面向对象编程的所有主要特性,包括封装、继承和多态。
- 泛型编程:C++ 支持泛型编程,这允许程序员编写与数据类型无关的代码。这是通过模板实现的。
- 内存管理:C++ 提供了对内存管理的低级控制,允许程序员直接操作内存。
- 异常处理:C++ 提供了一套异常处理机制,用于处理程序执行期间可能出现的错误。
- 函数重载:C++ 允许在同一作用域内存在多个具有相同名称但参数类型或数量不同的函数。
- 操作符重载:C++ 允许程序员为自定义数据类型重载操作符,以提供与内置类型相似的操作。
- 标准模板库(STL):C++ 拥有一个丰富的标准模板库,提供了一系列用于常见数据结构和算法的模板。
C++ 在软件开发领域有着广泛的应用,包括系统软件、游戏开发、嵌入式系统、高性能服务器和客户端应用、图形界面应用以及许多其他领域。C++ 的灵活性和效率使其成为许多程序员的首选语言
2.C++入门
2.1 C++关键字
C++总共63个关键字,C语言总共32个关键字
C++的关键字包含以下63个关键字:
2.2 C++命名空间
在学习C++时,我们会用到大量的变量,类,函数,如果将这些函数,变量,类都作用于全局域中,就会造成大量的命名冲突,为了解决这些问题,C++引入了命名空间,namespace关键字的出现就是解决这类问题的。
使用命名空间的目的就是对标识符的名称进行本地化,以避免命名冲突或名字污染
那么会出现哪些命名冲突呢?
比如:
#include<iostream>
using namespace std;
int rand = 10;
int main()
{
cout << rand;//rand会重定义,因为其之前的定义为函数
return 0;
}
通过命名空间就能解决这类问题(这里用到了作用域限定符,看不懂的同学可以先往下看)
#include<iostream>
using namespace std;
namespace yidai
{
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
int main()
{
cout << yidai::Add(1, 2)<<endl;
cout << yidai::rand;//rand在命名空间域中,就不会有重定义的报错
}
2.2.1 命名空间的定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员。
比如:
namespace yidai
{
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
命名空间还可以嵌套使用并且在同一个项目中的源文件和头文件中的相同名字的命名空间会被合并
#include<iostream>
#include"test.h"
//test.h
//namespace N1//和源文件中的N1命名空间名称相同,被合并
//{
// int Mul(int left, int right)
// {
// return left * right;
// }
//}
using namespace std;
namespace N1
{
int a;
int b;
int Add(int left, int right)
{
return left + right;
}
namespace N2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
int main()
{
cout << N1::Mul(1, 2) << " " << N1::Add(1, 2);
return 0;
}
2.2.2命名空间的使用
1. 命名空间加作用域限定符
#include<iostream>
using namespace std;
namespace N
{
// 命名空间中可以定义变量/函数/类型
int a = 0;
int b = 1;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
int main()
{
cout << N::a;
}
2.using将命名空间中某个成员引入
#include<iostream>
using namespace std;
namespace N
{
// 命名空间中可以定义变量/函数/类型
int a = 0;
int b = 1;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val = 1;
}N1;
}
using N::Add;
using N::a;
using N::Node;
using N::N1;
int main()
{
cout << N1.val << endl;
Node N2;
cout << N2.val << endl;
cout << a << endl;
cout << Add(1,2);
}
3.使用using namespace 命名空间名称引入
#include<iostream>
using namespace std;
namespace N
{
// 命名空间中可以定义变量/函数/类型
int a = 0;
int b = 1;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val = 1;
}N1;
}
using namespace N;
int main()
{
cout << a << endl;
cout <<Add(1, 2);
}
2.2 C++输入与输出
说明:
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件,以及按命名空间使用方法使用std。
- cout和cin是全局的流对象,endl是特殊的c++符号,表示换行输出,他们都包含在包含头文件中。
- << 是流插入运算符, >> 是流提取运算符。
- 使用c++输入输出更方便,不需要像printf / scanf输入输出时那样,需要手动控制格式。 c++的输入输出可以自动识别变量类型。
- 实际上cout和cin分别是ostream和istream类型的对象, >> 和 << 也涉及运算符重载等知识,
注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应
头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,
规定C++头文件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用iostream的方式。
//C++输入输出
#include<iostream>
// std是c++标准库的命名空间名,c++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
int a;
cin >> a;//输入
cout << "hello world!!!" << endl;//输出
return 0;
}
2.3 C++缺省参数
2.3.1 缺省参数概念
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
#include<iostream>
using namespace std;
void func(int a = 0)
{
cout << a << endl;
}
int main()
{
func();//没有指定的实参,用指定的缺省值
func(10);
}
2.3.2 全缺省参数
#include<iostream>
using namespace std;
void func(int a = 1, int b = 2 , int c = 3)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
int main()
{
func();
}
2.3.3 半缺省参数
半缺省参数只能从右往左缺省,因为函数匹配参数是从左往右匹配
#include<iostream>
using namespace std;
int d = 9;
void func(int a, int b, int c = d)//半缺省参数只能从右往左缺省,因为函数匹配参数是从左往右匹配
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl;
}
int main()
{
func(4, 2);
}
注意:
- 半缺省参数必须从右往左依次来给出,不能间隔着给
- 缺省参数不能在函数声明和定义中同时出现,一般在声明中给出,否则编译器不知道用哪一个缺省参数,就会报错
//test.h
void func(int a = 10);
//test.cpp
void func(int a = 20)
{}
int main()
{
return 0;
}
- 缺省值必须是常量或者全局变量
- C语言不支持缺省参数(编译器不支持)
2.4 函数重载
2.4.1 函数重载的概念
函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这 些同名函数的形参列表(参数个数 或 类型 或
类型顺序)不同,常用来处理实现功能类似数据类型 不同的问题。
1.参数类型不同
#include<iostream>
using namespace std;
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
int Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
//double Add(int left, int right)
//{
// cout << "double Add(double left, double right)" << endl;
// return left + right;
//}//返回值类型不同不能构成函数重载
int main()
{
cout << Add(1.1, 2.1);
cout << Add(1, 2);
return 0;
}
2.参数个数不同
#include<iostream>
using namespace std;
//2.参数个数不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
int Add(int left)
{
cout << "int Add(int left)" << endl;
return left;
}
int main()
{
Add(1);
Add(1, 2);
return 0;
}
3.参数类型顺序不同
#include<iostream>
using namespace std;
//3.参数类型顺序不同
int Add(int left, double right)
{
cout << "int Add(int left, double right)" << endl;
return left + right;
}
int Add(double right, int left)
{
cout << "int Add(double right, int left)" << endl;
return left;
}
int main()
{
Add(1.0, 2);
Add(2, 1.0);
return 0;
}
2.4.2 为什么C++支持重载而C语言不支持
在C/C++中,一个程序要运行起来,需要经历几个阶段:
1.预处理:处理源文件中#开始的预处理,比如:#include,#define
展开头文件/宏/条件编译//删除注释之类的
test.cpp、test.h-》test.i
2.编译:进行一系列的词义分析、语法分析、语义分析及优化生成相应的
汇编代码文件,test.i-》test.s
3.汇编:将汇编代码转换成一条一条的二进制机器指令
test.s-》test.o
4.链接:把一堆文件进行链接生成可执行程序,test.o-》xxx.exe
链接的主要过程:空间和地址的分配,符号决议和重定义等步骤
了解的更加编译与链接过程:点击链接
在进行链接的过程,编译器为了寻找函数的地址,就会对函数名进行修饰,不同编译器对函数名的修饰不一样,而在C++中会对函数名进行修饰,C语言中不会对函数名进行修饰(一般就是函数名),而C++根据函数重载的规则,函数名不同,修饰的名字也就不同
下面给大家演示一下windows下面函数名修饰规则:
stack.h
#include<iostream>
using namespace std;
struct Stack
{
};
void StackInit(struct Stack* ps, int n);
void f(int a, char b);
void f(char b, int a);
stack.cpp(将定义注释掉,方便报错看函数名修饰)
void StackInit(struct Stack* ps, int n)
{
cout << "void StackInit(struct Stack* ps, int n)" << endl;
}
//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;
//}
test.cpp
#include"stack.h"
int main()
{
Stack st;
StackInit(&st, 10);
f(1, 'a');
f('b', 2);//将函数的定义注释掉,就会发生链接错误,解决方法就是可以将函数的声明和定义放在同一头文件中或源文件中
return 0;
}
在windows下面函数名修饰规则: