知识图谱
一.输入与输出
必须包含< iostream >头文件以及std标准命名空间。
1. 标准输入
cpp
#include <iostream>
using namespace std;
int main(){
int a;
cin >> a; //无需std:cin
return 0;
}
2.标准输出
cpp
#include <iostream>
using namespace std;
int main(){
cout << "一个数据"; //无需std:cout
return 0;
}
endl 用于在行末添加一个换行符
cpp
#include<iostream>;
using namespace std;
int main()
{
int a, b;
cout << "请输入a和b" << endl;
cin >> a >> b;
cout << a << endl << b;
return 0;
}
C++里的输入输出流可以自动识别类型,不需要像C语言一样不需增加数据格式控制,比如:整形--%d,字符--%c
二.一元作用域分辨运算符
1.访问类的静态成员
cpp
class MyClass {
public:
static int num;
static void function();
};
// 访问类的静态成员
MyClass::num = 10;
MyClass::function();
2.解决命名冲突
cpp
int a = 0; //全局域
int main()
{
int a = 1; //局部域
printf("%d\n", a); // 1 局部优先
return 0;
}
加上了( :: ) ,此时访问的a,就是全局域,这里是全局域的原因是" :: "的前面是空白,如若是空白,那么访问的就是全局域
3.访问命名空间成员
cpp
namespace MyNamespace {
int num;
void function();
}
// 访问命名空间的成员
MyNamespace::num = 10;
MyNamespace::function();
三.函数
1.内联函数
(1)定义
内联函数的定义与普通函数基本相同,只是在函数定义前加上关键字 inline。
cpp
inline void print(char *s)
{
printf("%s", s);
}
在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function)。但也存在缺点,就是每一调用处均会展开,增加了重复的代码量。
可以理解为内联函数的关键词是:替换
编译器将函数代码拷贝到程序中,而不是像普通的函数调用
(2)隐式内联
C++中在类内定义的所有函数都自动称为内联函数,类的成员函数的定义直接写在类的声明中时,不需要inline关键字
cpp
#include <stdio.h>
class Trace{
public:
Trace()
{
noisy = 0;
}
void print(char *s)
{
if (noisy)
{
printf("%s", s);
}
}
void on(){ noisy = 1; }
void off(){ noisy = 0; }
private:
int noisy;
};
(3)显式内联
需要使用inline关键字
cpp
#include <stdio.h>
class Trace{
public:
Trace()
{
noisy = 0;
}
void print(char *s); //类内没有显示声明
void on(){ noisy = 1; }
void off(){ noisy = 0; }
private:
int noisy;
};
//类外显示定义
inline void Trace::print(char *s)
{
if (noisy)
{
printf("%s", s);
}
}
四.引用
1. 概念:
引用不是新定义一个变量,而是给已存在变量****取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
2.语法:
类型& 引用变量名(对象名) = 引用实体;
cpp
int a = 10;
int& b = a; // b 是 a 的别名
3.引用的特性
💦 引用在定义时必须初始化
💦 一个变量可以有多个引用💦 一个引用可以继续有引用
💦 引用一旦引用一个实体,再不能引用其他实体
💦 可以对任何类型做引用【变量、指针...】
💦 引用在定义时必须初始化
若是定义了一个引用类型的变量**
int&
**,那么就必须要去对其进行一个初始化,指定一个其引用的对象,否则就会报错
cpp
int a = 10;
int& b = a;
int& c;
C没有引用任何东西,会报错
💦 一个变量可以有多个引用
- 对于第二个特定,通俗一点来说就是b引用了a,那么b等价于a;此时c也可以引用a,那么c也等价于a,此时**
a == b == c
**- 你可以无限对a进行引用,直到把操作系统的内存申请光为止
💦 引用一旦引用一个实体,再不能引用其他实体
- 这个特性很重要【⭐】,要牢记。因为上面有说到对于引用而言在定义时必须初始化,那么在定义结束完后它就已经引用了一个值,无法在对其去进行修改了,这是非法的!
cpp
int a = 10;
int c = 20;
int& b = a;
int& b = c;
4.引用的相关解释(了解)
对于函数中的普通变量而言,是存放在当前所开辟函数的栈帧中的,即存放在内存中的栈区 ;但是对于函数中的静态变量而言,是不存放在当前函数栈帧中的,而是存放在内存中的静态区 ,包括平常可能会使用到的全局变量也是存放在其中
- 存放在【栈区】中的临时变量当函数调用结束后整个函数栈帧就会被销毁,那么存放在这个栈帧中的临时变量也随之消亡,不复存在
- 存放在【静态区】中的变量它们的生命周期是从创建开始到整个程序结束为止,所以不会随着当前所在的函数栈帧销毁而消亡💀
五.常引用
1、权限放大【×】
首先对于【const】关键字修饰的变量具有常性,是不可以被随意修改的,但此时变量d引用了c,那么c和d就从属于同一块地址了,不过变量d不具有常性,因此它是可以被修改的。
本来我这个c是不具有再度修改权限的,但是你引用了我,那就可以修改了,这也就破坏了原先的规则
2、权限保持【✔】
3、权限缩小【✔】
你呢允许我修改,但是我加上了常属性不去修改,那也是说得通的
4.传参问题
如若函数写出普通的引用,那么很多参数可能会传不过来:
只有a能正常传过去,后面的均传不过去,因为后面传的参数均涉及权限放大,固然编译器会出错
但是当我们在函数的形参那加上const呢?
加了const后编译器就不会报错了
5.正确初始化常量变量
正确形式
cpp
const int x=7;
错误形式
cpp
const int x;
x=7;
六.函数重载
1.定义
函数重载:是函数的一种特殊情况。C语言不支持函数重载,而C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。
简单来说,C++允许同一作用域中出现函数名相同,参数不同,功能相似的函数,而这些函数就构成函数重载。
cpp
void Swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void Swap(double* a, double* b)
{
double temp = *a;
*a = *b;
*b = temp;
}
//这两个函数就构成函数重载
这两个函数就构成函数重载
2.函数重载的条件
第一要满足:函数名相同
第二要满足:参数不同, 具体表现在参数类型的顺序、参数的个数、参数的类型。
参数的类型不同的函数重载参数的 个数不同 的函数重载
参数类型的 顺序不同
3.函数重载的注意点
仅仅修改函数返回类型-------- 不能称为函数重载
因为无法区分你要调用的是谁
4.为什么要有函数重载
第一:书写函数名方便。
比如,我们要写两个交换函数,第一个是交换两个整形,第二个是交换两个浮点型,那么你只需要都取Swap即可,不需要写成Swapi、Swapd,如果参数复杂呢?你又要写成什么呢?
到不如直接写成Swap,然后传不同的参数,编译器会自动匹配最符合的函数。
第二:类中构造函数的实现也依靠函数重载
构造函数是同名的成员函数,它一般被划分为:有参构造、无参构造、拷贝构造,它们构成函数重载。
第三:模板的底层实现也依靠函数重载
模板的其实就是让编译器就为你创建重载函数,比如Swap(const T& a,const T&b)
当你传两个整形给a和b时,编译器会自动生成Swap(int* a,int* b),当你传两个浮点型double时,编译器会自动生成Swap(double* a,double* b)。
注:参考了这位大佬的博客