C++ 类和对象(一)

目录

0.前言

1.面向过程&面向对象

1.1面向过程编程(PP)

1.2面向对象编程(OOP)

1.3从C到C++

2.类的引入

2.1C语言中的结构体

2.2C++中类的引入

2.3结构体与类的区别

2.4为什么引入类

3.类的定义

3.1声明与定义不分离

3.2声明与定义分离

3.3如何选择

4.类的访问限定符与封装

4.1访问限定符

4.2封装

5.类的作用域

6.类的实例化

6.1概念

6.2实例化方式

7.类成员的储存

7.1计算类对象的大小

7.2类对象的储存方式

7.2.1成员变量的储存

7.2.2成员函数的储存

7.3类/结构体内存对齐

7.3.1内存对齐的基本规则

8.this指针

8.1概述

8.2为什么引入this指针

8.3this指针的特性

9.小结


(图像由AI生成) 

0.前言

在计算机编程的世界里,语言的演进是为了更好地适应开发的需要,提高软件的质量和开发效率。C++作为一种高效的编程语言,它在C语言的基础上增加了面向对象的特性。这篇博客将带你了解C++中类和对象的基础知识,为你打开面向对象编程的大门。

1.面向过程&面向对象

当我们从学习C语言转向学习C++时,我们实际上是在从面向过程编程(Procedural Programming, PP)迈向面向对象编程(Object-Oriented Programming, OOP)。这两种编程范式在处理复杂性、代码组织和重用方面有着根本的不同。

1.1面向过程编程(PP)

面向过程编程是一种以过程(函数)为中心的编程范式,强调的是“做什么”和“如何做”。在C语言中,程序被视为一系列的函数调用。数据和函数是分开的,数据定义在函数外部,而函数则操作这些数据。这种方式在处理简单任务时非常有效,因为它允许程序员以线性方式思考问题。

  • 优点:对于小型程序和简单问题,面向过程的方法可以快速地提供解决方案,因为它允许直接操作数据和使用简单的逻辑。
  • 缺点:随着程序的增长,面向过程的代码可能变得难以维护和扩展。全局数据的使用可能导致数据被错误地修改,而代码的重用也变得更加困难。

1.2面向对象编程(OOP)

面向对象编程则是一种以对象为中心的编程范式,强调“是什么”和“能做什么”。在C++中,对象是数据和操作这些数据的函数(称为方法)的封装体。OOP通过封装(Encapsulation)、继承(Inheritance)和多态性(Polymorphism)来增加代码的重用性、灵活性和可维护性。

  • 封装:封装是将数据(属性)和操作数据的代码(方法)捆绑在一起的过程,这样可以隐藏对象的实际实现细节,仅通过定义好的接口与对象交互。

  • 继承:继承允许我们定义一个基类(父类)的属性和方法,然后通过派生更具体的子类来扩展或修改这些功能。这促进了代码的重用和扩展性。

  • 多态性:多态性是指允许我们用一个统一的接口来操作不同类型的对象,具体操作依赖于对象的实际类型。这使得我们可以编写更通用和灵活的代码。

  • 优点:OOP使得程序更易于理解、维护和扩展。通过对象的封装,可以更好地管理和保护数据。继承和多态性进一步提高了代码的重用性和灵活性。

  • 缺点:面向对象的设计和实现通常比面向过程更复杂,可能需要更多的时间来学习和掌握。对于一些简单的问题,使用OOP可能会导致过度设计。

1.3从C到C++

当我们从C语言转向C++学习时,实际上是在学习如何以一种更抽象的方式思考问题。我们需要开始考虑如何将问题域内的概念建模为对象,这些对象如何相互交互,以及如何通过继承和多态性来组织和简化代码。尽管这种转变最初可能会挑战我们的思维习惯,但随着时间的推移,我们将发现面向对象的方法能够更自然地映射复杂的问题和现实世界的结构。

2.类的引入

在理解C++类的引入之前,我们首先要看看C语言中的结构体(struct),因为它为类的概念奠定了基础。

2.1C语言中的结构体

C语言允许我们通过结构体来定义和组织不同类型的数据。结构体是一种复合数据类型,它使得我们能够将多个不同类型的变量组合成一个单一的单位。例如,如果我们想要存储一个人的信息,包括名字、年龄和身高,我们可以这样定义一个结构体:

struct Person {
    char name[50];
    int age;
    float height;
};

结构体帮助我们在C语言中实现了数据的初步“封装”,但它的功能还是相对有限。结构体主要用于数据的存储,而对于数据的操作,则仍然依赖于外部的函数。

2.2C++中类的引入

C++在结构体的基础上引入了类(class),这是面向对象编程的核心。类不仅包括数据成员(即属性),还包括成员函数(即方法),这使得数据和操作数据的逻辑能够被封装在一起。这种封装性是OOP的一个重要特性,它提高了代码的复用性和可维护性。

使用C++类,我们可以这样重写上面的例子:

class Person {
public:
    char name[50];
    int age;
    float height;

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

在这个类的定义中,printInfo是一个成员函数,它与结构体内部的数据紧密相关,可以直接访问和操作这些数据。与C语言的结构体相比,C++的类提供了更高级的数据抽象和封装能力。

2.3结构体与类的区别

在C++中,结构体和类非常相似,事实上,它们之间的主要区别在于默认的访问权限:类的成员默认是private的,而结构体的成员默认是public的。这意味着,除非显式指定,否则类的数据成员和成员函数在类的外部是不可访问的,这强化了封装性。

2.4为什么引入类

引入类的目的是为了更好地支持抽象和封装,这是面向对象编程的核心概念之一。通过将数据和操作数据的逻辑捆绑在一起,类使得开发者能够创建更加复杂和高级的数据结构,这些数据结构不仅能够存储数据,还能够定义与数据相关的操作。这种方式大大提高了代码的重用性和可维护性,是从结构化编程向面向对象编程转变的一个重要步骤。

3.类的定义

在C++中,定义类是建立对象模板的基础步骤,涉及到成员变量(属性)和成员函数(方法)的声明及定义。C++提供两种主流的类定义方法:声明与定义不分离与声明与定义分离。

3.1声明与定义不分离

这种方法将类的声明和定义放置在同一位置,通常适用于简单的类定义。在这个方法中,类的成员函数直接在类定义内部实现。例如:

class Box {
public:
    double length; // 长度
    double width;  // 宽度
    double height; // 高度

    double getVolume() {
        return length * width * height; // 计算体积
    }
};

这里,Box类直接在其声明中定义了getVolume函数。

3.2声明与定义分离

对于更复杂的类,通常采用声明与定义分离的方式。这种方法将类的声明(包含成员变量和成员函数原型)放在头文件中,而将成员函数的具体实现放在源文件中。这样做的好处包括提高代码的可维护性和编译效率。

  • 头文件(Box.h)源文件(Box.cpp) 示例:
// Box.h
#ifndef BOX_H
#define BOX_H

class Box {
public:
    double length;
    double width;
    double height;

    double getVolume(); // 成员函数声明
};

#endif

// Box.cpp
#include "Box.h"

double Box::getVolume() {
    return length * width * height; // 成员函数定义
}

在头文件Box.h中,我们声明了Box类和getVolume函数的原型。在源文件Box.cpp中,我们定义了getVolume函数的具体实现。

3.3如何选择

  • 简单类或模板类:倾向于使用声明与定义不分离的方法,因为这简化了代码结构,减少了文件数量。
  • 复杂类或大型项目:推荐声明与定义分离的方法。这种方式不仅能提高编译效率(只有在类实现改变时才需要重新编译源文件),还有助于隐藏实现细节,提升代码的模块化和可维护性。

4.类的访问限定符与封装

在C++中,类的封装是通过访问限定符来实现的,它们定义了类成员的访问范围和权限。封装不仅能保护对象的状态不被外部随意访问,还能通过定义良好的接口与外界交互,是面向对象编程中的一个核心概念。

4.1访问限定符

C++中主要有三种访问限定符:publicprivateprotected,它们各自的含义如下:

  • public:公有成员在任何地方都能被访问。
  • private:私有成员只能被其所在类的成员函数访问。
  • protected:受保护成员可以被其所在类以及所有子类的成员函数访问。

使用这些访问限定符可以精确控制类成员的访问权限,防止外部代码直接访问内部状态或执行不应该被外部调用的操作。

class Box {
private:
    double width;  // 宽度,私有成员

public:
    double length; // 长度,公有成员
    void setWidth(double wid); // 公有成员函数
    double getWidth(void);     // 公有成员函数
};

void Box::setWidth(double wid) {
    width = wid;  // 私有成员,只能在类内部访问
}

double Box::getWidth(void) {
    return width; // 私有成员,只能在类内部访问
}

在这个例子中,width是一个私有成员,它只能通过类的公有成员函数setWidthgetWidth来访问和修改。这就是封装的体现:通过公有接口暴露必要的操作,而将实现细节隐藏起来。

4.2封装

封装是面向对象编程中用于限制对对象成员的直接访问的一种机制。它有以下几个重要作用:

  • 保护数据:通过将数据成员设置为私有,可以防止外部代码直接修改对象的内部状态,从而避免数据的不一致或损坏。
  • 简化接口:通过公有成员函数提供操作数据的方法,可以简化对象的使用,使外部代码不需要了解对象内部的复杂逻辑就能使用该对象。
  • 增强可维护性:封装使得对象的内部实现可以独立于外部代码变化,只要公有接口保持不变,就可以自由改变内部实现而不影响使用该对象的代码。

5.类的作用域

在C++中,类的作用域是一个重要概念,它定义了名称(比如变量名、函数名)的可见性和生命周期。理解类的作用域对于正确地编写和维护C++程序至关重要。

基本规则

  • 类内作用域:定义在类内部的成员(包括数据成员和成员函数)在整个类内部都是可见的。这意味着类的任何成员函数都可以访问该类的所有成员,无论这些成员定义在函数之前还是之后。
  • 类外作用域:类的成员在类外默认是不可见的,除非这些成员被声明为public。访问控制符(publicprivateprotected)决定了类成员在类外的可见性。

示例代码

#include <iostream>

class MyClass {
private:
    int a = 1;  // 私有成员变量,只能在类内部访问

public:
    int b = 2;  // 公有成员变量,可以在类外部访问

    void display() {
        std::cout << "私有成员a的值: " << a << std::endl;  // 类内部访问私有成员
        std::cout << "公有成员b的值: " << b << std::endl;  // 类内部访问公有成员
    }
};

int main() {
    MyClass obj;
    // std::cout << obj.a << std::endl; // 错误:'a'是私有的
    std::cout << "通过类外访问公有成员b的值: " << obj.b << std::endl;  // 类外部访问公有成员
    obj.display();  // 调用公有成员函数,它可以访问私有和公有成员

    return 0;
}

类的作用域不仅定义了成员的可见性和访问权限,还影响着代码的组织和结构。合理利用类的作用域可以提高代码的可读性和维护性,避免命名冲突,并保护数据不被非法访问。

6.类的实例化

在C++中,类实例化是指根据类模板创建对象的过程。类本身像是一个蓝图,描述了对象的结构和行为,但直到我们创建了类的实例,即对象,这些描述才具有实际意义。

6.1概念

当我们实例化一个类时,实际上是在内存中分配了一块区域来存储该类的数据成员,并根据类定义初始化这些数据。这个过程可以通过调用类的构造函数来完成,构造函数是一种特殊的成员函数,专门用于初始化新创建的对象。

6.2实例化方式

C++提供了多种实例化类的方式,但最基本的两种是:

  1. 在栈上实例化:这是最简单的创建对象的方式,类似于基本数据类型的声明。例如,如果有一个MyClass类,我们可以简单地通过MyClass obj;来在栈上创建一个MyClass类型的对象obj。这种方式创建的对象会在离开其作用域时自动被销毁。

  2. 在堆上实例化:通过使用new操作符,在堆上动态分配内存来创建对象。例如,MyClass* obj = new MyClass();创建了一个指向MyClass类型的新对象的指针obj。使用这种方式创建的对象不会自动销毁,需要手动使用delete操作符来释放内存。

简单示例代码

class MyClass {
public:
    MyClass() {} // 构造函数
};

int main() {
    MyClass obj; // 在栈上实例化对象
    MyClass* pObj = new MyClass(); // 在堆上实例化对象

    delete pObj; // 释放堆上对象的内存
}

7.类成员的储存

7.1计算类对象的大小

类对象的大小是其所有非静态成员的大小总和,但这个计算受内存对齐的规则影响。静态成员不占用类对象的存储空间,因为静态成员是被类的所有实例共享的。

示例代码:

#include <iostream>

class MyClass {
public:
    char a;    // 1 byte
    int b;     // 4 bytes
    double c;  // 8 bytes
};

int main() {
    std::cout << "Size of MyClass: " << sizeof(MyClass) << " bytes" << std::endl;
    return 0;
}

 

这个示例中,尽管char, int, double分别占1, 4, 8字节,类的总大小可能大于13字节,这取决于编译器如何对成员bc进行内存对齐。 

7.2类对象的储存方式

类对象可以存储在堆或栈上。选择哪种方式取决于对象的预期使用寿命和程序设计。

  • 栈上存储:创建时简单,由编译器自动管理内存。对象在其声明的作用域结束时自动销毁。
  • 堆上存储:使用new关键字在堆上分配内存,适用于生命周期长或大小可变的对象。需要程序员手动管理内存,使用delete释放。

7.2.1成员变量的储存

  • 非静态成员变量:这些变量的存储空间直接包含在每个类对象中。也就是说,每当创建一个类的实例时,每个非静态成员变量都会在内存中占有一份独立的空间。这些成员的排列和大小可能受到内存对齐的影响,导致类的实际占用空间可能大于各成员大小的简单累加。

  • 静态成员变量:静态成员变量不属于类的某个特定实例,而是由类的所有实例共享。它们的存储在所有对象之外,通常在程序的全局数据区或静态存储区。静态成员变量只有一份副本,无论创建多少个类实例。

7.2.2成员函数的储存

  • 非静态成员函数:与静态成员变量不同,非静态成员函数并不存储在每个对象中。相反,所有对象共享同一段成员函数代码,而不是在每个对象中复制一份函数代码。这意味着成员函数不会增加单个对象的大小。

  • 静态成员函数:与非静态成员函数类似,静态成员函数也不存储在对象中。它们属于类本身,而非类的某个实例,并且可以在没有创建类实例的情况下被调用。静态成员函数同样不增加对象的大小。

  • 虚函数:当类中包含虚函数时,C++实现通常会在每个对象中添加一个指向虚函数表(vtable)的指针。虚函数表是一个包含指向类虚函数的指针的数组。这意味着含有虚函数的类的对象会比没有虚函数的类的对象大一个指针的大小。

class MyClass {
public:
    int data;              // 非静态成员变量
    static int count;      // 静态成员变量
    void display() const { // 非静态成员函数
        std::cout << data;
    }
    static void showCount() { // 静态成员函数
        std::cout << count;
    }
};

int MyClass::count = 0; // 静态成员变量的初始化

int main() {
    MyClass obj;
    std::cout << "Size of object: " << sizeof(obj) << " bytes" << std::endl; // 显示对象大小
    MyClass::showCount(); // 调用静态成员函数
    obj.display(); // 调用非静态成员函数
    return 0;
}

 

在这个示例中,data是每个对象中实际占用空间的非静态成员变量,而成员函数(无论是静态的还是非静态的)不占用对象的存储空间。静态成员变量count存储在所有对象之外,并由所有对象共享。

7.3类/结构体内存对齐

内存对齐是优化数据存取效率的关键编程实践,特别是在处理结构体和类时。这涉及如何在内存中布局类或结构体的成员,以便符合处理器访问内存的最优方式。

7.3.1内存对齐的基本规则

  1. 对齐需求:一个类型的对齐需求通常由该类型的大小决定。例如,类型大小为4字节的int通常需要按4字节对齐。这意味着其地址必须是4的倍数。

  2. 结构体/类的对齐:一个结构体或类的总对齐需求通常由其最大成员的对齐需求决定。结构体或类的实际对齐方式会影响其总大小,因为可能在成员之间或末尾添加填充字节来满足对齐需求。

  3. 填充:为满足对齐需求,编译器可能在成员之间插入填充字节。填充确保每个成员都在其对齐需求指定的地址边界上开始。

示例:内存对齐的影响

考虑以下结构体示例,展示了如何计算大小并理解可能的内存填充。

#include <iostream>

struct Sample {
    char a;    // 1字节
    int b;     // 4字节,通常要求4字节对齐
    char c;    // 1字节
};

int main() {
    std::cout << "Size of Sample: " << sizeof(Sample) << " bytes" << std::endl;
    return 0;
}

 

在这个结构体中,尽管charint成员的总大小是6字节(1 + 4 + 1),最终的结构体大小是12字节,具体取决于编译器和平台的内存对齐策略。这是因为:

  • b 要求4字节对齐,因此在a后可能需要插入3字节的填充以确保b从4字节边界开始。
  • c后可能需要额外填充以保证整个结构体的大小为最大对齐要求的倍数(在这里是4字节)。

控制内存对齐

在C++中,可以使用特定的编译器指令或属性来控制内存对齐。例如,GCC和Clang支持__attribute__((aligned(x))),而MSVC支持__declspec(align(x)),用来指定变量或结构体成员的最小对齐。

struct __attribute__((aligned(8))) AlignedSample {
    char a;
    int b;
    char c;
};

在这个例子中,AlignedSample的每个实例都将按照至少8字节的边界对齐。这样的手动对齐可以帮助提高内存访问效率,尤其是在频繁访问数据时,但也可能导致内存使用效率降低。

8.this指针

在C++中,this指针是一个特殊的指针,它在每个非静态成员函数中隐含地存在。这个指针指向调用该成员函数的对象的地址。理解this指针的作用和特性对于编写面向对象的C++代码非常重要。

8.1概述

this指针是每个类的非静态成员函数的隐含参数,由编译器自动提供。它用于指向调用成员函数的对象。由于每个对象的非静态成员函数访问的是相同的代码,this指针提供了一种方法来解析对象特定的数据。

8.2为什么引入this指针

this指针的引入主要是为了解决以下几个问题:

  1. 区分同名成员和局部变量:在成员函数内部,可能会有与类的成员变量同名的局部变量。this指针可以用来区分这些变量。通过this->成员名,可以明确指出访问的是成员变量而非局部变量。

  2. 实现链式调用:通过在成员函数中返回*this,可以实现对同一个对象的连续操作。这样的方法常用于设计流畅接口(Fluent Interface)和方法链。

  3. 返回对象自身的引用:在某些需要返回调用对象自身的成员函数中,this指针使得函数能返回当前对象的引用。

8.3this指针的特性

this指针具有以下特性:

  1. 只能在类的非静态成员函数中使用:静态成员函数不与特定的对象关联,因此不能使用this指针。

  2. 是一个常量指针this指针本身不能被修改。它始终指向调用对象。

  3. 类型:在一个类T的成员函数中,this指针的类型是T* const,即一个指向T类型的常量指针。这意味着你不能改变this指针的指向(即this本身是常量),但可以修改this指向的对象的成员。

  4. 本质上是“成员函数”的形参:this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。

  5. 不需要用户传递:this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

class MyClass {
public:
    int value;

    // 使用this指针区分成员变量和参数
    void setValue(int value) {
        this->value = value; // 明确指定访问成员变量value
    }

    // 返回对象自身的引用实现链式调用
    MyClass& setValueAndReturnSelf(int value) {
        this->value = value;
        return *this;
    }
};

int main() {
    MyClass obj;
    obj.setValue(5);
    obj.setValueAndReturnSelf(10).setValue(15); // 链式调用示例
}

9.小结

在本博客中,我们深入探讨了C++中类和对象的基本概念。从面向对象的引入、类的定义、访问限定符和封装,到类的实例化、成员存储、内存对齐以及this指针的作用和特性,每一部分都是理解和运用C++面向对象编程的关键。这些基础知识不仅帮助我们更好地组织代码,提高程序的可读性和维护性,还是构建复杂系统时不可或缺的工具。C++ 类和对象(二),不见不散!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java探索之旅】从输入输出到猜数字游戏

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java编程秘籍 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、输入输出1.1 输出到控制台1.2 从键盘输入 二、猜数字游戏2.1 所需知识&#xff1a…

【动态规划】【01背包】Leetcode 1049. 最后一块石头的重量 II

【动态规划】【01背包】Leetcode 1049. 最后一块石头的重量 II 解法 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法 &#x1f612;: 我的代码实现> 动规五部曲 ✒️确定dp数组以及下标的含义 dp[j]表示容量为…

Learn SRP 01

学习链接&#xff1a;Custom Render Pipeline (catlikecoding.com) 使用Unity版本&#xff1a;Unity 2022.3.5f1 1.A new Render Pipeline 1.1Project Setup 创建一个默认的3D项目&#xff0c;项目打开后可以到默认的包管理器删掉所有不需要的包&#xff0c;我们只使用Unit…

陆面、生态、水文模拟与多源遥感数据同化

原文链接&#xff1a;陆面、生态、水文模拟与多源遥感数据同化https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247601198&idx6&sn51b9b26b75c9df1f11dcb9a187878261&chksmfa820dc9cdf584df9ac3b997c767d63fef263d79d30238a6523db94f68aec621e1f91df85f6…

算法——字符串

T04BF &#x1f44b;热门专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享字符串相关算法 如果有不足的或者错误的请您指出! 目录 1.最长公共前缀1.1解析1.2题解 2.最长回文子串2.1解析2.2题解 3.二级制求和3.1解析3.2题解 4.字符串相乘4.1解析4.2…

【环境变量】常见的环境变量 | 相关指令 | 环境变量系统程序的结合理解 | 环境变量表 | 本地变量环境变量 | 外部命令内建命令

目录 常见的环境变量 HOME PWD SHELL HISTSIZE 环境变量相关的指令 echo&env export unset 本地变量 环境变量整体理解 程序现象_代码查看环境变量 ​整体理解 环境变量表 环境变量表的传递 环境变量表的查看 内建命令 少说废话&#x1f197; 每个用…

大型网站系统架构演化

大型网站质量属性优先级&#xff1a;高性能 高可用 可维护 应变 安全 一、单体架构 应用程序&#xff0c;数据库&#xff0c;文件等所有资源都在一台服务器上。 二、垂直架构 应用和数据分离&#xff0c;使用三台服务器&#xff1a;应用服务器、文件服务器、数据服务器 应用服…

JavaEE 初阶篇-深入了解 CAS 机制与12种锁的特征(如乐观锁和悲观锁、轻量级锁与重量级锁、自旋锁与挂起等待锁、可重入锁与不可重入锁等等)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 乐观锁与悲观锁概述 1.1 悲观锁&#xff08;Pessimistic Locking&#xff09; 1.2 乐观锁&#xff08;Optimistic Locking&#xff09; 1.3 区别与适用场景 2.0 轻…

我企业的业务需要制作企业网站吗?11个支持的理由以及5个反对的理由!

如果你的企业经营得还不错&#xff0c;你可能会找出很多理由&#xff0c;说明为什么一个高效的网站对你来说并不那么重要。确实&#xff0c;你明白企业需要在互联网上有一定的存在感&#xff0c;但你可能并不认为一个高效的网站会对你的特定业务产生太大的影响——尤其是当你已…

实战纪实 | 编辑器漏洞之Ueditor-任意文件上传漏洞 (老洞新谈)

UEditor 任意文件上传漏洞 前言 前段时间在做某政府单位的项目的时候发现存在该漏洞&#xff0c;虽然是一个老洞&#xff0c;但这也是容易被忽视&#xff0c;且能快速拿到shell的漏洞&#xff0c;在利用方式上有一些不一样的心得&#xff0c;希望能帮助到一些还不太了解的小伙…

PCIe总线-存储器域和PCIe总线域访问流程(二)

1.概述 PCIe总线的最大特点是像CPU访问DDR一样&#xff0c;可以直接使用地址访问PCIe设备&#xff08;桥&#xff09;&#xff0c;但不同的是DDR和CPU同属于存储器域&#xff0c;而CPU和PCIe设备属于两个不同的域&#xff0c;PCIe设备&#xff08;桥&#xff09;的地址空间属于…

[RK3399 Linux] 使用busybox 1.36.1制作rootfs

一、 编译、安装、配置 busybox 1.1 下载源码 根文件系统是根据busybox来制作的。 下载地址:https://busybox.net/downloads/。 这里就以1.36.1版本为例进行编译安装介绍: 注意:编译linux内核与文件系统中的所有程序要使用相同的交叉编译器。 下载完成后解压: mkdir …

03 SQL基础 -- 查询与运算符

一、SELECT 语句基础 1.1 从表中选取数据 SELECT 语句 从表中选取数据时需要使用SELECT语句,也就是只从表中选出(SELECT)必要数据的意思。通过SELECT语句查询并选取出必要数据的过程称为匹配查询或查询(query) 基本SELECT语句包含了SELECT和FROM两个子句(clause)。示…

NAT实验

要求&#xff1a; 1、AR2为ISP路由器&#xff0c;其上只能配置IP地址&#xff0c;不得再进行其他的任何配置 2、PC1-PC2可以ping通客户平板和DNS服务器&#xff1b; 3、客户端可以通过域名访问http1&#xff0c;通过地址访问http2 4、R1为边界路由器&#xff0c;其上只有一…

计算机视觉工程师

为进一步贯彻落实中共中央印发《关于深化人才发展体制机制改革的意见》和国务院印发《关于“十四五”数字经济发展规划》等有关工作的部署要求&#xff0c;深入实施人才强国战略和创新驱动发展战略&#xff0c;加强全国数字化人才队伍建设&#xff0c;持续推进人工智能从业人员…

【深度学习】深度学习md笔记总结第4篇:TensorFlow介绍,学习目标【附代码文档】

深度学习笔记完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;深度学习课程&#xff0c;深度学习介绍要求,目标,学习目标,1.1.1 区别,学习目标,学习目标。TensorFlow介绍&#xff0c;2.4 张量学习目标,2.4.1 张量(Tensor),2.4.2 创建张量的指令,2.4.3 张量…

C语言世界上最详细自定义类型:联合和枚举

前言&#xff1a; hello! 大家好&#xff0c;我是小陈&#xff0c;今天给大家带来一篇联合和枚举的博客&#xff01;&#xff01;&#xff01; 1.联合体类型的声明 像结构体⼀样&#xff0c;联合体也是由⼀个或者多个成员构成&#xff0c;这些成员可以不同的类型。 但是编译…

安装达梦(DM8)数据库(图形化安装)

一、配置DM8数据库系统环境 在CentOS7系统环境安装DM8&#xff08;达梦&#xff09;数据库前的准备。&#xff08;注意&#xff1a;安装前必须创建 dmdba 用户&#xff0c;禁止使用 root 用户安装数据库。&#xff09; 1、新建用户 运行SecureCRT工具&#xff0c;root登录16…

域控软件安全隔离关键技术剖析:MCU域 VS SOC域

安全隔离的需求 功能安全开发中&#xff0c;软件阶段由软件V模型左边的软件安全需求SSR开始。SSR是从技术安全需求TSR中提取出软件的功能安全需求&#xff0c;大多数情况下具有不同的ASIL等级。 图1 功能安全软件开发V模型 随后&#xff0c;软件安全需求会被分配到软件架构中的…

利用SARscape对日本填海造陆和天然气开采进行地表形变监测

日本千叶市&#xff0c;是日本南部重要的工业港市。位于西部的浦安市是一个典型的"填海造田"城市&#xff0c;东南部的东金区有一片天然气开采区域&#xff0c;本文利用SARscape&#xff0c;用干涉叠加的方法&#xff0c;即PS和SBAS&#xff0c;对这两个区域进行地表…