Administrator
发布于 2023-11-04 / 0 阅读 / 0 评论 / 0 点赞

11月4日😣

12:00起床

13:20-14:25英语学习

14:25-16:30算法学习,要不要找方法

c++

static

修饰普通变量

存储在静态区,生命周期随程序,具有全局性、共享性、所有人可见。

内存分配和释放是由编译器和链接器在编译和链接阶段自动处理的,而不是由程序员显式管理。

修饰普通函数

表明函数的作用范围,仅在定义该函数的文件内才能使用。在多人开发项目时,为了防止与他人命名空间里的函数重名,可以将函数定位为 static。

修饰成员变量

修饰成员变量使所有的对象只保存一个该变量,而且不需要生成对象就可以访问该成员。

修饰成员函数

修饰成员函数使得不需要生成对象就可以访问该函数,但是在 static 函数内不能访问非静态成员。

c++ 变量的存储区域

自动存储区(Automatic Storage Area)
  • 栈区(Stack Area):用于存储局部变量和函数参数。在函数调用时分配内存,函数返回时释放内存。具有自动分配和释放的特性。栈上的变量是按照后进先出(LIFO)的方式管理。

  • 寄存器变量(Register Variables):声明为 register 关键字的变量,请求编译器将其存储在 CPU 寄存器中,以便快速访问。对于大多数现代编译器,register 关键字已经被忽略,编译器会自动进行优化。

静态存储区(Static Storage Area):
  • 静态区(Static Area):用于存储全局变量、静态变量和静态对象。在程序的整个生命周期内存在,由编译器和链接器在编译和链接阶段进行内存分配和初始化。静态区的变量具有全局可见性和共享性。

动态存储区(Dynamic Storage Area):
  • 堆区(Heap Area):用于手动分配和释放内存,通常用于动态对象的创建和管理。在堆上分配的内存需要手动释放,否则可能会导致内存泄漏。

  • 自由存储区(Free Store):与堆区类似,是通过 newdelete 运算符进行内存分配和释放的区域。自由存储区是堆区的一部分,两者之间的术语通常可以互换使用。

#pragma pack(n)

设定结构体、联合以及类成员变量以 n 字节方式对齐

#pragma pack(n) 使用

#pragma pack(push)  // 保存对齐状态
#pragma pack(4)     // 设定为 4 字节对齐

struct test
{
    char m1;
    double m4;
    int m3;
};

#pragma pack(pop)   // 恢复对齐状态

extern "C"

  • 被 extern 限定的函数或变量是 extern 类型的

  • extern "C" 修饰的变量和函数是按照 C 语言方式编译和链接的

extern "C" 的作用是让 C++ 编译器将 extern "C" 声明的代码当作 C 语言代码处理,可以避免 C++ 因符号修饰导致代码不能和C语言库中的符号进行链接的问题。

extern "C" 使用

#ifdef __cplusplus
extern "C" {
#endif

void *memset(void *, int, size_t);

#ifdef __cplusplus
}
#endif

静态多态(编译期/早绑定)

函数重载

class A
{
public:
    void do(int a);
    void do(int a, int b);
};

动态多态(运行期期/晚绑定)

  • 虚函数:用 virtual 修饰成员函数,使其成为虚函数

  • 动态绑定:当使用基类的引用或指针调用一个虚函数时将发生动态绑定

注意:

  • 可以将派生类的对象赋值给基类的指针或引用,反之不可

  • 普通函数(非类成员函数)不能是虚函数

  • 静态函数(static)不能是虚函数

  • 构造函数不能是虚函数(因为在调用构造函数时,虚表指针并没有在对象的内存空间中,必须要构造函数调用完成后才会形成虚表指针)

  • 内联函数不能是表现多态性时的虚函数,解释见:虚函数(virtual)可以是内联函数(inline)吗?

动态多态使用

class Shape                     // 形状类
{
public:
    virtual double calcArea()
    {
        ...
    }
    virtual ~Shape();
};
class Circle : public Shape     // 圆形类
{
public:
    virtual double calcArea();
    ...
};
class Rect : public Shape       // 矩形类
{
public:
    virtual double calcArea();
    ...
};
int main()
{
    Shape * shape1 = new Circle(4.0);
    Shape * shape2 = new Rect(5.0, 6.0);
    shape1->calcArea();         // 调用圆形类里面的方法
    shape2->calcArea();         // 调用矩形类里面的方法
    delete shape1;
    shape1 = nullptr;
    delete shape2;
    shape2 = nullptr;
    return 0;
}

虚析构函数

虚析构函数是为了解决基类的指针指向派生类对象,并用基类的指针删除派生类对象。

虚析构函数使用

class Shape
{
public:
    Shape();                    // 构造函数不能是虚函数
    virtual double calcArea();
    virtual ~Shape();           // 虚析构函数
};
class Circle : public Shape     // 圆形类
{
public:
    virtual double calcArea();
    ...
};
int main()
{
    Shape * shape1 = new Circle(4.0);
    shape1->calcArea();    
    delete shape1;  // 因为Shape有虚析构函数,所以delete释放内存时,先调用子类析构函数,再调用基类析构函数,防止内存泄漏。
    shape1 = NULL;
    return 0;
}

纯虚函数

纯虚函数是一种特殊的虚函数,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。

virtual int A() = 0;

数据结构

并查集

int len = 1000;
int pre[len];
int find(int c) {               // 函数返回 c 的根节点
    int r = c;
    while(parents[r] != r) {    // 返回根节点 r
        r = parents[r];
    }

    int i = c, j;
    while(i != r) {             // 压缩算法,将每个节点的父节点更新为根节点
        j = parents[i];
        parents[i] = r;         // 更新为根节点 r
        i = j;
    }
    return r;
}
void union(int node1, int node2) {      // 判断 node1 和 node2 是否连通,如果不连通那么将其所在分
    int root1 = find(node1);            // 支进行合并。
    int root2 = find(node2);
    if(root1 != root2) {
        parents[root1] = root2;         // 合并:这里 root1 和 root2 的顺序可以不考虑
    }
}

二叉树

完全二叉树(堆)

  • 大顶堆:根 >= 左 && 根 >= 右

  • 小顶堆:根 <= 左 && 根 <= 右


评论