参考地址 :www.bilibili.com/video/BV1et…
一、基础语法
#include<iostream>
using namespace std;
int main()
{
cout << "hellow word" << endl;
system("pause");
return 0;
}
1、常量、变量
#define month 40 // 全局常量
const int jcDay = 12; // 局部常量
int b = 1; // 变量
b = 2;
cout << "di " << jcDay << month << b << endl;
2、数据类型
1、bool、整形、浮点、字符型
// bool 一个字节
bool flag = true;
// C++ 是强类型语言
short 2个字节 2 的 15次方 127
int 4个字节 2 的 31次方 32767
long windows4个字节 linux (32位是32个字节、64位是8个字节)
long long 8个字节 2 的63次方
// C++ 是强类型语言
float 4个字节 7 位有效数字
double 8个字节 15-16位有效数字
float a = 3.14f;
// 后面加一个f标记他是float类型,不然系统会帮他识别位double然后转乘float
float f2 = 3e2 // 3 * 10 的 2次方
float f3 = 3e-2 // 3 * 0.1 的 2次方
// char 一个字节 只有一个字符哦。 他在内存中是存 ASCII 码的哦,不是存的他本身
char ch = 'a';
/* 创建字符变量一定要用单引号、且单引号里面只有一个字符
a - ASCII 97
A - 65
0-31 控制字符 (换行等)
*/
2、字符串
1、C风格字符串
char str[] = "hellow";
2、C++风格字符串
// 使用C++字符串要导入头文件
#include<string>
string str = "hellow";
3、sizeOf
short num1 = 10;
cout << sizeof(num1) << endl;
// 打印结果为2 其实就是 占用字节数
4、数据输入
// 输入整形
int a = 0;
cin >> a;
// 输入浮点
float b = 3.14f;
cin >> b
5、运算符
// + - * / % 加减乘除 取余
// a++ 和 ++a 前置先++在进行表达式计算
6、程序顺序
// break 结束循环 、 continue 结束当前循环
// goto 无条件标记跳转
cout << "hellow word1" << endl;
goto Flag;
cout << "hellow word2" << endl;
Flag:
cout << "hellow word3" << endl;
3、数组
1、数组
int arr[5] = {1, 2, 3, 4, 5};
int arr[] = {1, 2, 3, 4, 5, 6, 7};
// 通过数组名可以获取 1、数组长度 2、数组在内存中的首地址
sizeof(arr) // 数组总字节数
arr 就是首字符地址
&arr[0] = arr // 数组名就是首地址
数组长度 = sizeof(arr) / sizeof(arr[0]) = arr.length
// 数组反转
int temp = arr[start];
arr[start] = arr[end];
arr[end] = temp;
start++;
end--;
二维数组
int arr[2][3] = {{1,2,3},{2,3,4}};
二、函数
返回值 函数名(参数列表) {
}
// 函数的申明 可以防止函数定义在后面、调用的时候找不到
// 申明可以写多次。
int sum(int num1, int num2);
int sum(int num1, int num2) {
return num1 +num2;
}
int a = 10;
int b = 20;
sum(a, b);
// a b 为实参数
// num1 num2 为形参
上面为值传递、形参如果改变不会影响实参 因为值传递num1 num2 会单独开辟空间去接收
C++ 分文件
- .h 文件
#include<iostream>
using namespace std;
int getSum(int num1,int num2);
- .cpp文件
#include "Sum.h"
int getSum(int num1, int num2) {
int num = num1 + num2;
return num;
}
- 调用
#include<iostream>
using namespace std;
#include "Sum.h"
int main()
{
int a = 10;
int b = 20;
cout << "sum = " << getSum(a, b) << endl;
system("pause");
return 0;
}
三、指针
指针就是一个地址
int a = 10
在内存中开辟一个地址 位 0x00000 的地址来保存10
a 是他的别名
int *p;
p = &a;
则 p = 0x000000 就是指针
*p = 1000;
则 a = 1000;
p 是地址是指针 *p 就是地址中的值。 如果他修改了,则a 肯定也修改了
// 指针在32位系统中站4个字节。 64位占8个字节
空指针 : 就是指向内存中编号位0的空间。
如果指针初始化不知道指向哪,则指向内存位0的指针。 而且这个指针是不能访问的。
0 到 255 之间的内存编号是系统占用的,都不能访问。
int *p = NULL; // 空指针 nullptr;
// 野指针 :指向一个不合法的内存空间。
int * p = (int *)0x1100;
0x1100 是一个我们没有权限访问的内存。 则p就是野指针。
const 修饰指针有三种情况
1、const 修饰指针 - 常量指针
const int *p = &a;
// 特点、指针的指向可以修改、但是指针指向的值不可以修改。
p = &b 可以
*p = 200; 不可以
2、const 修饰指针 - 指针常量
int * const p = &a;
p = &b 不可以
*p = 200; 可以
3、const 修饰指针 - 常量指针常量
const int * const p = &a;
p = &b 不可以
*p = 200; 不可以
// 总结一下、const 右边的不能修改。
// 命名就是 const翻译成常量 。 * 翻译成指针
指针操作数组
int arr[3] = [1, 2, 3];
int *p = arr;
p++;
// 那么 *p = arr[1] 意思就是 *p 就是第二个元素;
四、结构体
结构体属于用户用自定义数据类型、允许用户存储不同的数据类型。
struct Student {
String name;
int age;
}
Student s1;
s1.name = "xiaohong";
s1.age = 18;
Student s2 = {"xiaoshuai", 18};
struct Student array[3] = {{"xiaowu", 18}, {"xiaochao", 19}, {"xiaoshuai", 20}};
Student s = {"xiaoshuai", 18};
Student *p = &s;
p->name; // 指针通过 箭头 访问结构体变量
值传递、会浪费内存 。 怎么办? 函数的形参改为指针、可以减少内存空间、且不会赋值新的副本出来。 但是可能会修改他,那如果加一个 const 则可以防止修改
void printStudent(const Student *p) {
}
C++ 核心编程
内存分区
-
代码区:函数体的二进制代码、系统自己管理
程序编译后就生成了。 CPU执行的机器指令。 代码区是 共享的、只读的。
-
全局区:存放全局变量和静态变量和常量。
程序编译后就生成了。 程序结束后由系统释放。
-
栈区 :由编译器自动分配和释放、存放函数的参数值、局部变量等。
-
堆区 :由程序员分配和释放、若不释放、程序结束后、操作系统收回。
C++主要使用new来开辟内存。
int *p = new int(10);
delete p; // 释放内存
int *arr = new int[10];
delete [] arr; // 释放数组要加中括号
引用
数据类型 &别名 = 原名。
这个别名就是引用类型。
int a = 10;
int &b = a;
如果
b = 20;
则 a 也等于 20;
引用必须要初始化。 例如 int &b; 是不行的。
引用一定初始化之后、就不可以更改。
例如 &b = c; 这是不行的。
// 形参可以改变、实参的值。
void swapAB(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
引用的本质
int a = 10;
int &ref = a; // 相当于 int * const ref = a;
ref = 20; // 系统内部会帮他转换成 *ref = 20; 因为ref实际上是a的地址不可改的,但是系统内部转换的
常量引用
int a = 10;
int &ref = 10; // 这个是不行的
但是
const int &ref = 10; // int temp = 10; const int &ref = temp;
这样是可以的。 但是ref 是不可改的
void showValue(int &val) {
}
函数提高
默认参数
int func(int a, int b = 20) {
}
- 函数申明有默认参数、实现的时候就不能有默认参数。(申明和实现只能有一个有默认参数)
站位参数
int func(int a, int) {
}
重载
// 相同的函数名、不同的参数
void func() {}
void func(int a) {}
类和对象
- public
- protected 子类可以访问
- private 私有子类不能访问
// class 和 struct 区别 区别: struct 默认权限是 public, class 默认的权限是 private
// C++ 的属性 读写权限通过 私有化属性,在暴露共有 set get 方法来实现。
- 例如 只有get 方法, 没有set 方法, 就是只读属性。
// 构造函数 析构函数
class Person {
Person() {
}
Person(int a) {
}
Person(const Person &p) {
}
~Person() {
}
}
**class 创建的时候默认提供 构造函数、析构函数、 和拷贝构造函数**
如果自定义有参构造函数、则系统不提供午餐构造函数。但是会提供拷贝构造函数
如果自定义拷贝构造函数、则系统不提供其他构造函数。
void test() {
// 括号发
Person p1;
Person p2(10); // 调用有参构造函数
Person p3(p2); // 调用拷贝构造函数
// 显示方法
Person p1;
Person p2 = Person(10);
Person p3 = Person(p2);
// 隐式调用
Person p2 = 10;
}
深拷贝 堆区重新申请空间、进行拷贝
~Person(Person &p) {
height = new int(*p.height); // 在堆区单独开辟空间
}
浅拷贝 简单的赋值拷贝操作。
~Person(Person &p) {
height = *p.height; // 直接引用
}
初始化列表
Person(int a, int b) :m_A(a). :m_A(b) {
}
静态函数
static void func() {
}
void test() {
Person p = Person();
p.func();
Person::func();
}
// 静态函数只能访问静态变量
空对象也会被分配一个字节的内存, 且是独一无二的。 之后非静态成员变量、属于类的对象上。 静态成员变量、非静态成员函数、静态成员函数、都不属于对象上
问题: 如果非静态成员函数不属于对象,那怎么区分是哪个对象在调用的。 答: this 指针、谁调用的, this 指针 就指向谁。 this 指针的本质是一个 指针常量。指针指向是不可以修改的(指向一个对象后、就不能指向别的对象了)
const 修饰指针 - 指针常量 int * const p = &a; p = &b 不可以 *p = 200; 可以 Person * const this
空指针可以访问没有使用成员变量的成员函数。
常函数
- 成员函数后加const 后 我们称为常函数
- 不能修改成员属性。
void showPerson() const {
a = 100;
}
int a;
mutable int b; // 属性加 mutable 这样常函数可以修改。
成员函数的 this 指针 是 Person * const this 而成员函数后面加 const this 指针就是 const Person * const this 。 所以里面不能修改属性。
// 常对象
const Person p;
p.a = 100; // 不可以
p.b = 200; // 可以
常对象只能调用常函数。
友元
全局函数 友元
friend void GoodGay(Person *per); // 这样这个函数就可以访问本类的私有属性了。
friend class Student; // 好朋友友元
运算符重载
加法重载
两个自定义数据类型相加减
class Person {
public
int a;
int b
}
Person *p1;
Person *p2;
Person = p1 + p2; // 内部实现 a + b
// 通过自定义函数
Person personAdd(Person &p) {
Person temp;
tem.a = this.a + p.a;
temp.b = this.b + p.b;
}
// 如果帮 personAdd 改为 operator+
// 则 直接可以使用
Person = p1 + p2; 来相加减。
改为全局函数也可以。
左移重载、递增重载、赋值重载、关系重载
#include<iostream>
#include <string>
using namespace std;
class Person {
public:
int a;
int b;
// 递增重载
Person& operator++() {
this->a = this->a + 1;
return *this;
}
void operator=(Person& p) {
cout << "赋值重载" << p.a << endl;
a = p.a;
b = p.b + 1000;
}
};
// 左移重载
void operator<<(ostream &cout, Person &p)
{
cout << "hellow word" << p.a << p.b << endl;
}
int main()
{
cout << "hellow word" << endl;
Person p = Person();
p.a = 10;
p.b = 20;
++p;
cout << p;
Person p2;
p2 = p;
cout << p2.a << p2.b << endl;
system("pause");
return 0;
}
// 其他关系。 例如 == >= 都可以通过 operator 进行重载
函数调用重载
就是小括号重载。称之为访函数。没有固定写法
#include<iostream>
#include <string>
using namespace std;
class myPrint
{
public:
myPrint();
~myPrint();
void operator()(string str) {
cout << "chaoshuai :" << str << endl;
}
int operator()(int a, int b) {
return a + b;
}
private:
};
myPrint::myPrint()
{
}
myPrint::~myPrint()
{
}
int main()
{
myPrint jcPrint;
cout << jcPrint(1, 2) << endl;
jcPrint("hellow wo chao shuai");
system("pause");
return 0;
}
// 匿名函数对象
类和对象
继承
class a : public b {
} // public 集成可以访问 父类的 public protected // protected 继承 可以访问 public protected 但是 public 会变成 protected // private 继承 可以访问 public protected 但是 public 和 会变成 private
// 父类先构造 、 子类在构造。 子类先析构、父类在析构。
// 如果父类和子类属性重复。可以加作用域来访问父类同名成员属性。
son.Base::m_A 可以访问
son.Base::func()
// 访问父类同名静态成员变量 Son::Base::m_A;
多态:
静态多态:重载、复用函数名 (函数地址在编译时期确定)
动态多态:派生类、和虚拟函数实现运行时多态 (运行阶段确定函数的地址)
C++ 可以多继承
文件操作
fstream
#include <fstream>
ofstream ofs;
ofs.open(path, ios::out);
ofs << "content" << endl;
ofs.close;