C++笔记

324 阅读5分钟

参考地址 :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个字节       215次方     127
int    4个字节       231次方    32767
long  windows4个字节   linux (32位是32个字节、64位是8个字节)
long long  8个字节   263次方        
// 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的指针。 而且这个指针是不能访问的。 
0255 之间的内存编号是系统占用的,都不能访问。
int *p = NULL; // 空指针 nullptr;
// 野指针 :指向一个不合法的内存空间。
int * p = (int *)0x1100;
0x1100 是一个我们没有权限访问的内存。 则p就是野指针。

const 修饰指针有三种情况

1const 修饰指针 -  常量指针
const int *p = &a;
// 特点、指针的指向可以修改、但是指针指向的值不可以修改。
p = &b    可以
*p = 200; 不可以

2const 修饰指针 - 指针常量
int * const p = &a;
p = &b  不可以
*p = 200; 可以

3const 修饰指针 - 常量指针常量
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;