剖析【C++】——类与对象(上)超详解——小白篇

news2024/9/8 11:16:44

目录

1.面向过程和面向对象的初步认识

1.面向过程(Procedural Programming)

2.面向对象(Object-Oriented Programming)

概念:

特点:

总结

2.C++ 类的引入

1.从 C 语言的结构体到 C++ 的类

2.C++ 中的结构体和类

3.使用类来替代结构体

4.总结

3.类的定义

1.什么是类?

2.如何定义一个类?

类的成员

示例 1:简单的类定义

3.两种类的定义方式

1.全部在类体中

2.分开声明和定义

4.总结

4.C++ 类的访问限定符及封装

1.访问限定符

1.访问限定符有三种:

2.注意:

2.C++ 中 struct 和 class 的区别

3.封装

1.封装的优势:

5.总结

5.类的作用域

1.作用域和作用域操作符

示例:

2.在类体外定义成员函数

Step 1: 类声明

Step 2: 类体外定义成员函数

Step 3: 使用类

3.总结

6.类的实例化

1. 类是一个描述

2. 类的实例化

3. 类与对象的类比

4.总结

7.类对象模型

7.1 如何计算类对象的大小

7.2 类对象的存储方式

7.3 结构体内存对齐规则

7.4面试题

8.C++ 类成员函数的 this 指针

8.1 this 指针的引出

8.2 this 指针的特性

8.3面试题

8.4 C 语言和 C++ 实现 Stack 的对比

1. C 语言实现 Stack

2. C++ 实现 Stack

8.5总结


1.面向过程和面向对象的初步认识

1.面向过程(Procedural Programming)

面向过程是一种编程范式,它主要关注程序的执行过程和步骤。程序员通过将问题分解为一个个具体的步骤和函数,逐步解决问题。面向过程的编程语言强调函数的调用和顺序的执行。

特点:

  1. 函数为中心:程序的逻辑是通过调用函数来实现的,每个函数执行特定的任务。
  2. 步骤明确:分析问题并明确解决步骤,通过函数逐步实现这些步骤。
  3. 数据和操作分离:数据和操作通常是分离的,通过函数来操作数据。

示例语言:

  • C语言
  • Pascal

示例代码(C语言):

#include <stdio.h>

// 函数定义
void greet() {
    printf("Hello, World!\n");
}

int main() {
    // 调用函数
    greet();
    return 0;
}

在这个例子中,我们定义了一个叫做 greet 的函数,这个函数打印问候语。main 函数调用 greet 函数来实现问候。

2.面向对象(Object-Oriented Programming)

概念:

  • 面向对象是一种编程方法,关注的是对象和对象之间的交互。我们把问题拆分成一个个对象,然后通过这些对象之间的合作来解决问题。
  • 比如管理一家餐厅,我们有服务员对象、厨师对象、顾客对象,每个对象有自己的职责,他们之间的互动完成了餐厅的运作。

特点:

  • 对象:把现实中的事物抽象成程序中的对象,每个对象都有属性和方法。
  • 交互:对象之间通过方法相互协作完成任务。

示例语言:

  • C++

简单示例(C++):

#include <iostream>
using namespace std;

// 定义一个叫做 Person 的类
class Person {
public:
    // 类的属性
    string name;

    // 类的方法
    void greet() {
        cout << "Hello, " << name << "!" << endl;
    }
};

int main() {
    // 创建一个 Person 对象
    Person person;
    person.name = "World";

    // 调用对象的方法
    person.greet();

    return 0;
}

在这个例子中,我们定义了一个 Person 类,这个类有一个 name 属性和一个 greet 方法。我们创建了一个 Person 对象,设置了它的 name 属性,然后调用它的 greet 方法来打印问候语。

总结

  • 面向过程:关注解决问题的步骤,通过函数调用一步步完成任务。
  • 面向对象:关注对象和对象之间的交互,通过对象的方法来完成任务。

2.C++ 类的引入

1.从 C 语言的结构体到 C++ 的类

在 C 语言中,我们使用结构体(struct)来定义一组相关的变量。例如,一个表示点的结构体可以包含 xy 坐标:

// C 语言的结构体
struct Point {
    int x;
    int y;
};

在这个例子中,Point 结构体只能包含变量 xy,不能包含函数。

2.C++ 中的结构体和类

在 C++ 中,结构体不仅可以包含变量,还可以包含函数。这使得结构体比 C 语言中的结构体更加强大和灵活。例如,我们可以在结构体中定义一个函数来打印点的坐标:

// C++ 中的结构体
struct Point {
    int x;
    int y;

    // 结构体中的函数
    void print() {
        cout << "Point(" << x << ", " << y << ")" << endl;
    }
};

不过,在 C++ 中,更常用的是类(class),因为类提供了更多的功能和控制。类和结构体在语法上很相似,但有一些重要的区别:

  1. 默认访问权限:在结构体中,成员默认是公有的(public),而在类中,成员默认是私有的(private)。
  2. 类可以使用继承、封装、多态等高级特性。

3.使用类来替代结构体

我们可以使用类来定义一个更加完整的点类,包括私有变量和公有函数:

#include <iostream>
using namespace std;

// 定义一个 Point 类
class Point {
private:
    int x;
    int y;

public:
    // 构造函数
    Point(int xVal, int yVal) {
        x = xVal;
        y = yVal;
    }

    // 公有函数
    void print() {
        cout << "Point(" << x << ", " << y << ")" << endl;
    }
};

int main() {
    // 创建一个 Point 对象
    Point point(3, 4);

    // 调用对象的方法
    point.print();

    return 0;
}

在这个例子中,我们定义了一个 Point 类,它有私有的 xy 变量,以及一个构造函数来初始化这些变量。我们还定义了一个 print 函数来打印点的坐标。这样,类不仅封装了数据,还提供了操作数据的方法。

4.总结

  • C 语言结构体:只能定义变量,不能包含函数。
  • C++ 结构体:不仅可以定义变量,还可以包含函数。
  • C++ 类:更常用,提供了更多功能和控制,如私有变量、公有函数、构造函数等。

通过引入类,C++ 提供了更强大的工具来组织和管理代码,使得代码更易于维护和扩展。

3.类的定义

1.什么是类?

类是一个模板,它定义了一种新的数据类型,这种类型包含数据(变量)和功能(函数)。可以把类想象成一种蓝图,用来创建对象(具体的实例)。

2.如何定义一个类?

class 关键字来定义一个类。类的名字可以是你选择的任何名字,类的主体包含变量和函数。在类定义的最后要加上一个分号 ;

类的成员
  • 成员变量:类里面的变量,称为属性。
  • 成员函数:类里面的函数,称为方法。
示例 1:简单的类定义

我们来定义一个表示点(Point)的类,这个类有两个属性 xy,以及一个打印点坐标的方法。

#include <iostream>
using namespace std;

class Point {
public:
    int x; // 成员变量
    int y; // 成员变量

    // 成员函数
    void print() {
        cout << "Point(" << x << ", " << y << ")" << endl;
    }
};

int main() {
    Point point; // 创建一个 Point 对象
    point.x = 3; // 设置属性 x
    point.y = 4; // 设置属性 y

    point.print(); // 调用成员函数

    return 0;
}

在这个例子中,Point 类定义了两个变量 xy,还有一个打印点坐标的函数 print。在 main 函数中,我们创建了一个 Point 对象,设置了它的 xy 值,然后调用 print 方法打印坐标。

3.两种类的定义方式

1.全部在类体中

  • 简单直接,适合小项目或示例代码。
  • 成员函数在类中定义,可能会被编译器当成内联函数(优化的一种)。

class Point {
public:
    int x;
    int y;

    void print() {
        cout << "Point(" << x << ", " << y << ")" << endl;
    }
};

2.分开声明和定义

  • 更清晰,适合大型项目。
  • 类的声明放在头文件(.h 文件)中,成员函数的定义放在源文件(.cpp 文件)中。

Point.h

#ifndef POINT_H
#define POINT_H

class Point {
public:
    int x;
    int y;

    void print();
};

#endif // POINT_H

 Point.cpp

#include <iostream>
#include "Point.h"
using namespace std;

void Point::print() {
    cout << "Point(" << x << ", " << y << ")" << endl;
}

main.cpp

#include "Point.h"

int main() {
    Point point;
    point.x = 3;
    point.y = 4;

    point.print();

    return 0;
}

4.总结

  • :用 class 定义,包含变量和函数。
  • 成员变量:类里面的变量,称为属性。
  • 成员函数:类里面的函数,称为方法。
  • 两种定义方式:全部放在类体中或分开声明和定义。

4.C++ 类的访问限定符及封装

1.访问限定符

C++ 提供了访问限定符来控制类成员(属性和方法)的访问权限。通过这些限定符,我们可以实现封装,让类更加安全和易于维护。

1.访问限定符有三种:

  1. public:公有成员可以在类外部直接访问。
  2. protected:保护成员不能在类外部直接访问,但可以在子类中访问。
  3. private:私有成员不能在类外部直接访问,仅能在类的内部访问。

2.注意:

  • 访问权限从访问限定符出现的位置开始,直到下一个访问限定符出现为止。如果没有下一个访问限定符,则作用域一直到类的结束。
  • class 中,默认访问权限是 private。在 struct 中,默认访问权限是 public

示例:

#include <iostream>
using namespace std;

class Person {
public:
    string name; // 公有成员变量

protected:
    int age; // 保护成员变量

private:
    string secret; // 私有成员变量

public:
    // 构造函数
    Person(string n, int a, string s) : name(n), age(a), secret(s) {}

    // 公有成员函数
    void showInfo() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }

    // 私有成员函数
    void showSecret() {
        cout << "Secret: " << secret << endl;
    }
};

int main() {
    Person person("Alice", 30, "Loves coding");

    // 直接访问公有成员
    cout << "Name: " << person.name << endl;

    // 直接调用公有成员函数
    person.showInfo();

    // 尝试访问保护和私有成员会导致编译错误
    // cout << "Age: " << person.age << endl; // 错误
    // cout << "Secret: " << person.secret << endl; // 错误

    return 0;
}

2.C++ 中 structclass 的区别

在 C++ 中,struct 可以用来定义类,其功能与 class 基本相同,唯一的区别在于默认的访问权限不同:

  • struct 默认访问权限是 public
  • class 默认访问权限是 private

示例:

struct Point {
    int x;
    int y;

    void print() {
        cout << "Point(" << x << ", " << y << ")" << endl;
    }
};

class Circle {
private:
    int radius;

public:
    void setRadius(int r) {
        radius = r;
    }

    void showRadius() {
        cout << "Radius: " << radius << endl;
    }
};

3.封装

封装是面向对象编程的三大特性之一。它将数据和操作数据的方法有机结合,隐藏对象的属性和实现细节,仅对外公开接口来与对象进行交互。

1.封装的优势:

  1. 隐藏实现细节:用户不需要知道内部如何实现,只需通过公开的接口与对象交互。
  2. 提高代码安全性:通过控制访问权限,防止外部直接修改对象内部状态。
  3. 增强代码维护性:内部实现可以随时更改而不影响外部代码。

现实例子: 就像使用计算机时,我们不需要知道内部的工作原理,只需要通过键盘、鼠标、显示器等接口与计算机交互即可。

在 C++ 中实现封装: 通过类将数据和方法结合在一起,并使用访问限定符来控制访问权限。

示例:

class Computer {
private:
    string cpu;
    int memory;

public:
    // 构造函数
    Computer(string c, int m) : cpu(c), memory(m) {}

    // 公有成员函数
    void start() {
        cout << "Computer started with CPU: " << cpu << " and Memory: " << memory << "GB" << endl;
    }
};

int main() {
    Computer myComputer("Intel i7", 16);
    myComputer.start(); // 通过公开的接口与对象交互

    // 直接访问私有成员会导致编译错误
    // cout << myComputer.cpu << endl; // 错误

    return 0;
}

5.总结

  • 访问限定符:控制类成员的访问权限,分为 publicprotectedprivate
  • 封装:将数据和方法结合,隐藏实现细节,只公开必要的接口,提高代码安全性和可维护性。
  • structclass 的区别struct 默认访问权限是 publicclass 默认访问权限是 private

5.类的作用域

在 C++ 中,类定义了一个新的作用域。类的所有成员(变量和函数)都在这个类的作用域中。如果在类体外定义成员函数,需要使用 :: 作用域操作符来指明成员属于哪个类。

1.作用域和作用域操作符

什么是作用域? 作用域指的是变量或函数在程序中可以被访问的区域。在类中,类的作用域指的是类的所有成员变量和成员函数的可访问范围。

作用域操作符 :: 作用域操作符 :: 用于指定一个变量或函数属于哪个作用域。在类体外定义成员函数时,需要使用 :: 来指明函数属于哪个类。

示例:

2.在类体外定义成员函数

假设我们有一个表示点(Point)的类,包含两个成员变量 xy 以及一个打印点坐标的成员函数 print

我们可以在类体内声明成员函数,然后在类体外定义它们。

Step 1: 类声明

在头文件(如 Point.h)中声明类和成员函数:

#ifndef POINT_H
#define POINT_H

class Point {
public:
    int x;
    int y;

    // 声明成员函数
    void print();
};

#endif // POINT_H

Step 2: 类体外定义成员函数

在源文件(如 Point.cpp)中定义成员函数:

#include <iostream>
#include "Point.h"
using namespace std;

// 使用作用域操作符 :: 来定义成员函数
void Point::print() {
    cout << "Point(" << x << ", " << y << ")" << endl;
}

Step 3: 使用类

在主文件(如 main.cpp)中使用这个类:

#include "Point.h"

int main() {
    Point point;
    point.x = 3;
    point.y = 4;

    point.print(); // 调用成员函数

    return 0;
}

3.总结

  1. 类定义了一个新的作用域:类的所有成员都在类的作用域中。
  2. 在类体外定义成员函数:需要使用作用域操作符 :: 指明成员属于哪个类。
  3. 示例代码:通过分离声明和定义的方式,使用 :: 作用域操作符在类体外定义成员函数

6.类的实例化

类的实例化是用类类型创建对象的过程。可以把类看作一种描述或模板,通过这个模板可以创建具体的对象。

1. 类是一个描述

类就像一个模型或模板,它定义了对象的成员(变量和函数),但本身并不占用内存空间。例如,一个 Person 类可能包含成员变量 nameage,以及成员函数 printInfo,但只有在实例化出具体对象时,这些成员才会实际占用内存空间。

类的例子:

class Person {
public:
    string name;
    int age;

    void printInfo() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};

现实类比: 类就像一张空的学生信息表,它描述了学生有哪些信息(比如姓名和年龄),但没有具体存储任何学生的信息。只有在填写表格时,才会有具体的学生数据。

2. 类的实例化

一个类可以实例化出多个对象,这些对象占用实际的物理空间,用于存储类的成员变量。

实例化对象的例子:

int main() {
    // 创建 Person 类的对象(实例化)
    Person person1;
    person1.name = "Alice";
    person1.age = 30;

    Person person2;
    person2.name = "Bob";
    person2.age = 25;

    // 调用对象的成员函数
    person1.printInfo();
    person2.printInfo();

    return 0;
}

在这个例子中,我们实例化了两个 Person 对象,分别是 person1person2。这些对象各自拥有自己的 nameage,并实际占用了内存空间。

3. 类与对象的类比

类实例化出对象就像使用建筑设计图建造房子:

  • :就像建筑设计图,定义了房子应该有什么样子(例如有几间房、什么颜色的墙壁),但设计图本身并不是房子。
  • 对象:就像根据设计图建造出来的房子,房子是实际存在的,占用了物理空间。

类与对象的关系:

  • :模板或蓝图,描述了对象的特性和行为。
  • 对象:类的实例,实际存在并占用内存空间,存储类的成员变量。

4.总结

  1. 类是一个描述:类定义了对象的成员,但本身不占用内存空间。
  2. 实例化对象:通过类创建对象,对象占用实际的物理空间,存储类的成员变量。
  3. 类与对象的类比:类就像设计图,实例化出的对象就像建造出来的房子。

7.类对象模型

在 C++ 中,类的对象模型描述了类的实例(对象)在内存中的存储方式。了解这个模型对于优化程序性能和理解内存管理非常重要。

7.1 如何计算类对象的大小

问题: 一个类的对象包含什么?如何计算一个类的大小?

回答: 一个类的对象包含类的成员变量,但不直接包含成员函数。成员函数在公共的代码段中存储。类的对象大小实际上是该类中所有成员变量的大小之和,考虑内存对齐后得到的结果。

示例:

class MyClass {
public:
    int a;
    double b;

    void myFunction() {}
};

int main() {
    MyClass obj;
    cout << "Size of MyClass: " << sizeof(MyClass) << endl; // 输出类对象的大小
    return 0;
}

7.2 类对象的存储方式

对象模型猜测:

  1. 成员变量存储在对象中:每个对象都包含自己的成员变量。
  2. 成员函数存储在公共代码段:成员函数只存储一份,在对象中保存指向函数代码的地址。

这样可以节省内存空间,因为多个对象共享同一份成员函数代码。

存储方式总结:

  • 成员变量:存储在每个对象中,占用实际内存空间。
  • 成员函数:存储在公共代码段,所有对象共享,节省内存空间。

示例:

class MyClass {
public:
    int a;
    double b;

    void myFunction() {
        cout << "Hello" << endl;
    }
};

int main() {
    MyClass obj1;
    MyClass obj2;

    // 输出类对象的大小
    cout << "Size of MyClass: " << sizeof(MyClass) << endl;
    return 0;
}

7.3 结构体内存对齐规则

内存对齐是为了提高内存访问效率,使得 CPU 可以快速读取和写入数据。

内存对齐规则:

  1. 第一个成员在与结构体偏移量为 0 的地址处:即第一个成员从 0 地址开始。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处:对齐数是编译器默认对齐数和成员大小的较小值。
  3. 结构体总大小为最大对齐数的整数倍:即所有成员变量类型最大值和默认对齐参数的最小值的整数倍。
  4. 嵌套结构体:嵌套的结构体对齐到自己的最大对齐数的整数倍处,整体大小为所有最大对齐数的整数倍。

示例:

#include <iostream>
using namespace std;

struct MyStruct {
    char a;
    int b;
    double c;
};

int main() {
    cout << "Size of MyStruct: " << sizeof(MyStruct) << endl; // 输出结构体大小
    return 0;
}

内存对齐示例:

  • char 对齐到 1 字节
  • int 对齐到 4 字节
  • double 对齐到 8 字节

计算大小:

  • a 从偏移量 0 开始,占 1 字节。
  • b 需要对齐到 4 字节,从偏移量 4 开始,占 4 字节。
  • c 需要对齐到 8 字节,从偏移量 8 开始,占 8 字节。
  • 结构体总大小是 8 的整数倍,即 16 字节。

7.4面试题

  1. 结构体怎么对齐?为什么要进行内存对齐?

    回答: 结构体的每个成员按照对齐规则对齐,具体规则如上所述。内存对齐是为了提高内存访问效率,使 CPU 可以快速读取和写入数据。

  2. 如何让结构体按照指定的对齐参数进行对齐?能否按照 3、4、5 即任意字节对齐?

    回答: 可以使用编译器提供的指令来指定对齐参数,例如 #pragma pack 指令。可以按照任意字节对齐,但通常使用的是 1、2、4、8 等字节对齐。

    #pragma pack(push, 1)
    struct MyStruct {
        char a;
        int b;
        double c;
    };
    #pragma pack(pop)
    

    什么是大小端?如何测试某台机器是大端还是小端,有没有遇到过要考虑大小端的场景?

    回答: 大端(Big-endian)和小端(Little-endian)是两种字节序,决定了多字节数据的存储顺序。大端将最高字节存储在最低地址,小端将最低字节存储在最低地址。

    测试方法:

    #include <iostream>
    using namespace std;
    
    int main() {
        unsigned int x = 1;
        char *c = (char*)&x;
        if (*c)    
            cout << "Little-endian" << endl;
        else
            cout << "Big-endian" << endl;
        return 0;
    }
    

    场景: 网络传输、文件存储时需要考虑大小端问题,因为不同系统可能使用不同的字节序,需要进行转换以确保数据正确解析。

8.C++ 类成员函数的 this 指针

8.1 this 指针的引出

当我们定义一个类,并在类中包含成员函数时,这些函数需要知道它们是属于哪个对象。例如,我们定义一个日期类 Date

class Date {
public:
    int day;
    int month;
    int year;

    void Init(int d, int m, int y) {
        day = d;
        month = m;
        year = y;
    }

    void Print() {
        cout << day << "/" << month << "/" << year << endl;
    }
};

问题: 当我们有两个对象 d1d2 时,调用 d1.Init(1, 1, 2020)d2.Init(2, 2, 2021),函数是如何区分这两个对象的?

解决方法: C++ 编译器通过引入 this 指针来解决这个问题。this 指针是一个隐藏的指针参数,指向当前对象(即调用成员函数的对象)。在成员函数内部,所有的成员变量访问都是通过 this 指针实现的。

8.2 this 指针的特性

  1. this 指针的类型类类型* const,即 this 指针是指向类对象的常量指针,不能修改 this 指针的指向。
  2. 只能在成员函数内部使用this 指针只能在成员函数中使用。
  3. this 指针是成员函数的形参:当对象调用成员函数时,对象的地址作为实参传递给 this 指针。所以对象本身并不存储 this 指针。
  4. this 指针由编译器维护this 指针是成员函数的第一个隐含的指针形参,编译器会自动处理,不需要用户传递。

示例:

class Date {
public:
    int day;
    int month;
    int year;

    void Init(int d, int m, int y) {
        this->day = d;
        this->month = m;
        this->year = y;
    }

    void Print() {
        cout << this->day << "/" << this->month << "/" << this->year << endl;
    }
};

8.3面试题

  1. this 指针存在哪里?

    回答: this 指针存储在成员函数的形参列表中,由编译器在调用成员函数时自动传递,通常通过寄存器(如 ecx 寄存器)传递。

  2. this 指针可以为空吗?

    回答: 在正常情况下,this 指针不会为空,因为它指向的是当前调用成员函数的对象。但是在某些特定情况下(如对象被错误地删除或未正确初始化),this 指针可能会变成空指针或指向无效地址。

8.4 C 语言和 C++ 实现 Stack 的对比

1. C 语言实现 Stack

在 C 语言中,实现 Stack 通常需要定义一个结构体,并且所有操作都通过函数来实现。

示例:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int *data;
    int top;
    int capacity;
} Stack;

// 初始化栈
void InitStack(Stack *s, int capacity) {
    s->data = (int *)malloc(capacity * sizeof(int));
    s->top = -1;
    s->capacity = capacity;
}

// 压栈
void Push(Stack *s, int value) {
    if (s->top < s->capacity - 1) {
        s->data[++s->top] = value;
    }
}

// 出栈
int Pop(Stack *s) {
    if (s->top >= 0) {
        return s->data[s->top--];
    }
    return -1; // 栈空
}

// 打印栈
void PrintStack(Stack *s) {
    for (int i = 0; i <= s->top; i++) {
        printf("%d ", s->data[i]);
    }
    printf("\n");
}

在 C 语言中,每个函数都需要传递 Stack 指针作为参数,并且需要手动检查指针是否为 NULL。

2. C++ 实现 Stack

在 C++ 中,通过类可以将数据和操作数据的方法结合在一起。这样使用时更方便,且更加符合人类对事物的认知。

示例:

#include <iostream>
using namespace std;

class Stack {
private:
    int *data;
    int top;
    int capacity;

public:
    // 构造函数
    Stack(int capacity) {
        this->data = new int[capacity];
        this->top = -1;
        this->capacity = capacity;
    }

    // 析构函数
    ~Stack() {
        delete[] data;
    }

    // 压栈
    void Push(int value) {
        if (top < capacity - 1) {
            data[++top] = value;
        }
    }

    // 出栈
    int Pop() {
        if (top >= 0) {
            return data[top--];
        }
        return -1; // 栈空
    }

    // 打印栈
    void PrintStack() {
        for (int i = 0; i <= top; i++) {
            cout << data[i] << " ";
        }
        cout << endl;
    }
};

int main() {
    Stack s(10);
    s.Push(1);
    s.Push(2);
    s.Push(3);

    s.PrintStack();

    s.Pop();
    s.PrintStack();

    return 0;
}

在 C++ 中,Stack 类将数据和操作方法结合在一起,使用时不需要显式传递 Stack 指针,因为编译器会自动处理 this 指针。

8.5总结

  1. this 指针的引出:解决成员函数区分不同对象的问题,this 指针指向当前对象。
  2. this 指针的特性:只能在成员函数内部使用,编译器自动传递。
  3. C 语言和 C++ 实现 Stack 的对比:C 语言通过函数操作结构体,C++ 通过类将数据和方法结合,更加方便和安全。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1703529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LLaMa系列模型详解(原理介绍、代码解读):LLaMA 2

LLaMA 2 大型语言模型&#xff08;LLMs&#xff09;作为高度能力的人工智能助手&#xff0c;在需要跨多个领域专家知识的复杂推理任务中表现出巨大潜力&#xff0c;包括编程和创意写作等专业领域。它们通过直观的聊天界面与人类互动&#xff0c;这导致了快速和广泛的公众采用。…

分布式事务解决方案(最终一致性【TCC解决方案】)

最终一致性分布式事务概述 强一致性分布式事务解决方案要求参与事务的各个节点的数据时刻保持一致&#xff0c;查询任意节点的数据都能得到最新的数据结果&#xff0c;这就导致在分布式场景&#xff0c;尤其是高并发场景下&#xff0c;系统的性能受到了影响。而最终一致性分布式…

JavaScript表达式语句二

异常处理语句 异常标识一种非中正常得信息&#xff0c;它提示程序在运行过程中发生了意外或错误&#xff0c;然后JavaScript通过一定的方式把它暴露出来&#xff0c;这叫做抛出异常。抛出异常操作表示系统告诉我们当前程序出现了问题&#xff0c;JavaScript使用异常处理语句来…

【python】python商家会员数据分析可视化(源码+数据集+课程报告论文)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

【CSharp】将ushort数组保存为1通道位深16bit的Tiff图片

【CSharp】将ushort数组保存为1通道位深16bit的Tiff图片 1.背景2.接口 1.背景 System.Drawing.Common 是一个用于图像处理和图形操作的库&#xff0c;它是 System.Drawing 命名空间的一部分。由于 .NET Core 和 .NET 5 的跨平台特性&#xff0c;许多以前内置于 .NET Framework…

【傻呱呱】VirtualHere共享局域网中的USB设备(使用Pavadan老毛子固件搭建篇)

前期准备 SSH工具&#xff08;FinalShell&#xff09;老毛子固件路由器一台 搭建VirtualHere服务端 进入VirtualHere官网下载对应处理器架构的包&#xff0c;我的是RT-N14U-GPIO路由器刷的老毛子固件&#xff0c;这种一般选择最后一个或者倒数第二个包&#xff0c;这里我选择…

企业心声社区,应该如何规划?

企业内部员工社区是一个具有极大价值的平台&#xff0c;不仅为高层管理者提供了直接倾听一线员工心声的渠道&#xff0c;同时也为员工提供了表达建议、参与管理、吐槽发泄的重要途径。 通过这个社区&#xff0c;基层管理者始终处于员工监督之下&#xff0c;迫使他们不能懈怠。…

Qt 5前后调色板差异变化

Qt 5之前&#xff1a; QPalette palette;//调色板 设置背景颜色 palette.setColor(QPalette::Backgound, color...);Qt 5之后&#xff1a; 由原有的 Background 模式 更新为 Window 模式 QPalette palette;//调色板 设置背景颜色 palette.setColor(QPalette::Window, color..…

STM32H743+USBHID+CubeMX配置

一、环境准备 电脑系统&#xff1a;Windows 10 专业版 20H2 IDE&#xff1a;Keil v5.35、STM32CubeMX v6.5.0 测试硬件&#xff1a;正点原子阿波罗STM32H743 二、测试步骤 1、使用用例工程 配置STM32H743定时器功能-CSDN博客https://blog.csdn.net/horse_2007s/article/d…

深入了解Linux中的环境变量

在Linux系统中&#xff0c;环境变量&#xff08;Environment Variables&#xff09;是用于配置操作系统和应用程序运行环境的一种机制。它们储存在键值对中&#xff0c;可以控制程序的行为、路径查找和系统配置。本文将深入探讨环境变量的基本概念、常见类型、设置和管理方法&a…

第十七届全国大学生信息安全竞赛创新实践能力赛初赛部分复现

Misc 神秘文件 1.根据提示信息&#xff0c;均需要从ppt中提取信息 2.在ppt的属性中发现一串密文和key&#xff0c;解密之后得到第一部分&#xff0c;根据提示Bifid chipher&#xff0c;为双歧密码解密&#xff0c;使用Bifid Cipher Decode解码 3.在第五张幻灯片&#xff0c;…

香橙派Kunpeng Pro测评:他给的实在太多了

文章目录 一、开箱环节1、包装配置2、开发板包装3、开发板3.1、开发版正面3.2、开发板背面 二、硬件配置1、硬件配置清单 2、配置图解 三、开机~启动&#xff01;1、运行系统1.1、外设配置1.2、系统启动1.3、官方教程 2、openEuler系统概览 四、系统测试1、性能测试1.1、安装sy…

现代 c++ 三:移动语义与右值引用

移动语义很简单&#xff0c;但它相关联的术语很复杂。本文尝试从历史的角度解释清楚这些乱七八糟的术语及其关联&#xff1a; 表达式 (expression)、类型&#xff08;type&#xff09;、值类别 (value categories)&#xff1b; 左值 (lvalue)、右值 (rvalue)、广义左值 (glval…

电脑找不到opencl.dll原因分析及5种详细的解决方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到opencl.dll”。这通常意味着计算机中缺少或损坏了与OpenCL&#xff08;开放计算语言&#xff09;相关的动态链接库文件。OpenCL允许应用程序利用图形处理器&#xff08;GPU&#xff…

[STM32-HAL库]ADC采集-DMA中断采集-平均值滤波-STM32CUBEMX开发-HAL库开发系列-主控STM32F103C8T6

目录 一、前言 二、实现步骤 1.STM32CUBEMX配置 2.Keil工程程序设计 三、结语 一、前言 本文通过STM32CUBEMX实现对ADC的数据采集和滤波操作&#xff0c;帮助各位开发者完成与模拟量输入的采集工作。 二、实现步骤 1.STM32CUBEMX配置 以STM32F103C8T6为例&#xff0c;打开S…

接口响应断言-json

json认识JSONPath源码类学习/json串的解析拓展学习 目的&#xff1a;数据返回值校验测试 json认识 json是什么-是一种数据交换格式&#xff0c;举例平时看到的json图2&#xff0c;在使用中查看不方便&#xff0c;会有格式转化的平台&#xff0c;json格式的展示 JSON在线视图…

OSPF减少LSA更新量1

OSPF的LSA优化 一、汇总——优化骨干区域 (1)域间汇总ABR设备基于某个区域的1/2类LSA计算所得的最佳路由&#xff0c;共享给其他区域时&#xff0c;进行汇总传递。 [r2]ospf 1 [r2-ospf-1]area 1——明细路由所在区域&#xff0c;该ABR设备必须和明细路由在同一区域 [r2-ospf…

学习javascript的函数

1.什么是函数&#xff1f; 可以重复被使用的代码块 作用&#xff1a;函数可以把具有相同或者相似逻辑的代码“包裹起来”&#xff0c;有利于代码的复用。 2.函数的基本使用 1.定义函数 利用关键字Function 定义函数&#xff08;声明函数&#xff09; function 函数名(){函…

windows-386、windows-amd64、windows-arm64这三者有什么区别?

选择文件的版本出现下面问题&#xff1a; Architectures windows-386 &#xff1a;这些是针对 32 位 Windows 系统编译的。windows-amd64 &#xff1a;这些是针对具有 AMD 或 Intel x86-64 架构的 64 位 Windows 系统编译的。windows-arm64 &#xff1a;这些是针对具有 ARM 架…

模型实战(20)之 yolov8分类模型训练自己的数据集

yolov8分类模型训练自己的数据集 yolov8,一个实时快速的端到端的集检测、分割、分类、姿态识别于一体的视觉算法库/框架本文将给出yolov8 分类模型的数据集制作格式及训练流程 1. 环境搭建 关于虚拟环境的搭建真的是老生常谈了,给出一个简单的搭建流程吧#新建虚拟环境 conda …