当前位置: 首页 > news >正文

C++(11)类语法分析(2)

C++(10)之类语法分析(2)


Author: Once Day Date: 2024年8月17日

一位热衷于Linux学习和开发的菜鸟,试图谱写一场冒险之旅,也许终点只是一场白日梦…

漫漫长路,有人对你微笑过嘛…

全系列文章可参考专栏: 源码分析_Once-Day的博客-CSDN博客

参考文章:

  • C++ 重载运算符和重载函数 | 菜鸟教程 (runoob.com)
  • 类和结构 (C++) | Microsoft Learn
  • C++ 类 & 对象_w3cschool
  • 复制构造函数和复制赋值运算符 (C++) | Microsoft Learn
  • 如何:定义移动构造函数和移动赋值运算符 (C++) | Microsoft Learn
  • 委托构造函数 (C++) | Microsoft Learn
  • 指向成员的指针 | Microsoft Learn
  • 对象生存期和资源管理 (RAII) | Microsoft Learn
  • 友元 (C++) | Microsoft Learn
  • 用户定义的类型转换 (C++) | Microsoft Learn

文章目录

  • C++(10)之类语法分析(2)
        • 1. 类高级特性
          • 1.1 运算符重载
          • 1.2 友元函数
          • 1.3 类型转换
          • 1.4 特殊成员函数
          • 1.5 禁用方法
          • 1.6 返回值类型
          • 1.7 内存处理(new/delete)
          • 1.8 嵌套结构体
          • 1.9 成员初始化列表

1. 类高级特性

基础类的介绍请参考文章:C++(10)类语法分析(1)-CSDN博客

1.1 运算符重载

C++ 允许在同一作用域中的某个函数运算符指定多个定义,分别称为函数重载运算符重载。重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。

当调用一个重载函数重载运算符时,编译器通过把所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策

运算符重载是C++的一个强大特性,它允许为用户定义的类型自定义运算符的行为。通过运算符重载,我们可以使自定义类型的对象支持各种运算符,如算术运算符、比较运算符、输入输出运算符等,从而提高代码的可读性和表现力。

运算符重载的语法,运算符重载的实现方式是定义一个特殊的成员函数或全局函数,函数名为operator后跟运算符符号。例如,重载+运算符的函数名为operator+

class MyClass {
public:MyClass operator+(const MyClass& other);  // 成员函数形式的运算符重载
};MyClass operator+(const MyClass& lhs, const MyClass& rhs);  // 全局函数形式的运算符重载

重载算术运算符,可以重载各种算术运算符,如+-*/等,以支持自定义类型的算术运算。

class Complex {
public:Complex(double real, double imag) : real(real), imag(imag) {}Complex operator+(const Complex& other) const {return Complex(real + other.real, imag + other.imag);}private:double real;double imag;
};

下面是可重载的运算符列表:

双目算术运算符+ (加),-(减),*(乘),/(除),% (取模)
关系运算符==(等于),!= (不等于),< (小于),> (大于),<=(小于等于),>=(大于等于)
逻辑运算符||(逻辑或),&&(逻辑与),!(逻辑非)
单目运算符+ (正),-(负),*(指针),&(取地址)
自增自减运算符++(自增),–(自减)
位运算符| (按位或),& (按位与),~(按位取反),^(按位异或),,<< (左移),>>(右移)
赋值运算符=, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空间申请与释放new, delete, new[ ] , delete[]
其他运算符()(函数调用),->(成员访问),,(逗号),[](下标)

下面是不可重载的运算符列表:

  • .,成员访问运算符。

  • .*, ->\*,成员指针访问运算符。

  • ::,域运算符。

  • sizeof,长度运算符。

  • ?:,条件运算符。

  • #,预处理符号。

重载运算符还需要满足一下限制:

  • 重载运算符必须至少有一个操作数是用户定义的类型。这意味着不能重载两个内置类型的运算符。
  • 重载运算符的优先级和结合性是固定的,不能被改变。重载运算符的优先级和结合性与对应的内置运算符相同。
  • 重载运算符必须是公有的(public)成员函数或全局函数。如果是成员函数,则其中一个操作数必须是该类的对象。
  • 重载运算符时不能改变操作数的个数。例如,二元运算符重载后仍然是二元的,一元运算符重载后仍然是一元的。
  • 重载运算符时不能改变运算符的语法含义。例如,不能将加法运算符+重载为执行减法操作。
  • 重载运算符时不能创建新的运算符,只能重载已有的运算符。
  • 某些运算符必须以成员函数的形式进行重载,如赋值运算符=、下标运算符[]、函数调用运算符()和成员访问箭头运算符->。
  • 重载运算符时,参数列表中至少应有一个参数是类的对象或对象的引用。
  • 静态成员函数不能用于重载运算符。
1.2 友元函数

在C++中,友元函数(Friend Function)是一种特殊的函数,它可以访问类的私有成员和保护成员,即使它不是类的成员函数。这打破了类的封装性,但在某些情况下,友元函数可以提供更加灵活和方便的方式来操作类的私有数据。

要将一个函数声明为类的友元函数,需要在类的定义中使用关键字 friend,并在函数声明前加上 friend 关键字。友元函数可以是全局函数,也可以是另一个类的成员函数。

class MyClass {
private:int secret;public:MyClass(int s) : secret(s) {}friend void friendFunction(MyClass& obj);
};void friendFunction(MyClass& obj) {// 友元函数可以访问 MyClass 的私有成员std::cout << "My friend knows my secret: " << obj.secret << std::endl;
}

在上面的例子中,friendFunction 被声明为 MyClass 的友元函数。尽管 friendFunction 不是 MyClass 的成员函数,但它可以访问 MyClass 的私有成员 secret

当两个类需要频繁地访问对方的私有成员时,使用友元函数可以避免繁琐的公有接口设计。

1.3 类型转换

在C++中,类可以定义自动类型转换和强制类型转换,以实现类对象与其他类型之间的转换。

自动类型转换(Implicit Type Conversion):有一个名为 Fruit 的类,它表示一种水果。现在,把这个水果变成一个整数,代表这个水果的数量。可以通过定义一个接受 Fruit 对象的构造函数来实现这个功能。

class Fruit {
public:Fruit(int quantity) : quantity_(quantity) {}// 定义转换函数,将 Fruit 对象转换为整数operator int() const {return quantity_;}private:int quantity_;
};// 使用示例
Fruit apple(5);
int quantity = apple; // 自动将 Fruit 对象转换为整数

在这个例子中,定义了一个转换函数 operator int(),它允许 Fruit 对象自动转换为整数。将 Fruit 对象赋值给一个整数变量时,编译器会自动调用这个转换函数,将 Fruit 对象转换为对应的整数值。

隐式类型转换是自动进行的,不需要显式地调用转换函数。以下是一些常见的隐式类型转换场景:

  • 将类对象赋值给其他类型的变量。
  • 将类对象作为函数参数传递。
  • 在条件语句中使用类对象。
  • 返回值声明为类对象。

此外,这里定义了一个转换函数operator int() const,其格式通常如下:

operator typename();

转换函数必须是类方法,且不能指定返回类型,不能有参数,一般最好进行显示声明(explicit),可以避免隐式自动转换。

强制类型转换(Explicit Type Conversion):现在,让我们考虑一个更复杂的情况。假设有一个名为 Juice 的类,它表示一种果汁。想把整数转换为 Juice 对象,代表制作果汁所需的水果数量。但是这个转换不希望是自动进行的,而是要求显式地进行转换。

class Juice {
public:explicit Juice(int quantity) : quantity_(quantity) {}private:int quantity_;
};// 使用示例
Juice orangeJuice = Juice(10); // 正确,显式地创建 Juice 对象
Juice appleJuice = 5; // 错误,不允许自动转换

在这个例子中,使用 explicit 关键字来修饰 Juice 类的构造函数,表示不允许进行隐式转换。这意味着不能直接将整数赋值给 Juice 对象,而必须显式地调用构造函数来创建 Juice 对象。

通过使用 explicit 关键字,可以防止意外的自动转换,提高代码的可读性和安全性

自动类型转换允许类对象与其他类型之间的隐式转换,通过定义转换函数来实现。而强制类型转换要求显式地进行转换,通过使用 explicit 关键字来禁止自动转换。

当提供两个或多个用户定义的用于执行相同转换的转换时,该转换将被视为不明确。 这种不明确性是一个错误,因为编译器无法确定应选择哪一个可用转换

1.4 特殊成员函数

在C++类中,有一些特殊的成员函数,它们在类的生命周期中扮演着重要的角色。

  • 默认构造函数(Default Constructor),默认构造函数是一种特殊的构造函数,它不接受任何参数,或者接受的参数都有默认值。当创建一个类的对象时,如果没有显式地调用其他构造函数,默认构造函数会被自动调用。默认构造函数的作用是初始化对象的成员变量,将其设置为合适的默认值。

    class_name::class_name() {}
    
  • 默认析构函数(Default Destructor),默认析构函数是一种特殊的成员函数,它在对象的生命周期结束时被自动调用。析构函数的作用是释放对象所占用的资源,如动态分配的内存、打开的文件等。默认析构函数不接受任何参数,也没有返回值。

    class_name::~class_name() {}
    
  • 复制构造函数(Copy Constructor),复制构造函数是一种特殊的构造函数,它接受一个同类型对象的常量引用作为参数。复制构造函数的作用是根据已有对象创建一个新对象,并将已有对象的成员变量的值复制到新对象中。

    class_name(const class_name &);
    

    当以下情况发生时,复制构造函数会被调用:

    • 用一个对象初始化另一个同类型的对象。
    • 函数按值传递对象。
    • 函数返回一个对象。

    由于按值传递对象将调用复制构造函数,因此应该按照引用传递对象,可以节省调用构造函数的时间和存储新对象的空间。

    复制构造函数只是浅复制,即简单的复制非静态成员的值,所以指针指向的区域还是共用的,这种情况下需要定义一个复制构造函数,进行深度赋值操作。

  • 赋值运算符重载(Assignment Operator),赋值运算符重载是一种特殊的成员函数,它定义了对象之间的赋值操作。默认情况下,赋值运算符执行逐个成员的赋值操作。但是,有时需要自定义赋值运算符的行为,以处理特殊的赋值逻辑,如深拷贝、资源管理等。

    class_name & class_name::operator=(const class_name &);
    

    由于目标对象可能引用了以前分配的数据,所以函数应该使用delete[]来释放这些数据,同时应该避免将对象赋给自己。

  • 移动构造函数(Move Constructor),移动构造函数是C++11引入的新特性,它接受一个同类型对象的右值引用作为参数。移动构造函数的作用是将资源从一个对象转移到另一个对象,而不是进行复制。这可以提高性能,避免不必要的复制操作。

    class_name::class_name(class_name &&);
    

    移动构造函数需要对右值才能生效(没有实际存储空间的值),如下所示:

    class_name two = one;			// 匹配中复制构造函数
    class_name four (one + three); 	// 匹配中移动构造函数
    
  • 移动赋值运算符重载(Move Assignment Operator),移动赋值运算符重载也是C++11引入的新特性,它允许将一个对象的资源转移到另一个对象,而不是进行复制。与移动构造函数类似,移动赋值运算符重载接受一个同类型对象的右值引用作为参数,并将资源从源对象转移到目标对象。

    class_name & class_name::operator=(class_name &&);
    

    如果要对左值强行使用移动赋值语义,可以通过static_cast强制类型转换为class_name &&,或者使用utility中的std::move函数。

委托构造函数(Delegating Constructors),委托构造函数允许一个构造函数调用同一个类中的另一个构造函数。这样可以避免在多个构造函数中重复相同的初始化代码。

class Person {
public:Person(const std::string& name, int age) : name(name), age(age) {// ...}Person(const std::string& name) : Person(name, 0) {// ...}// ...
private:std::string name;int age;
};

在上述示例中,第二个构造函数委托给了第一个构造函数,并将年龄参数设置为默认值0。

继承构造函数(Inheriting Constructors):继承构造函数允许派生类直接使用基类的构造函数,而无需在派生类中显式定义对应的构造函数。这可以简化派生类的构造函数编写。

class Base {
public:Base(int x) : x(x) {// ...}// ...
protected:int x;
};class Derived : public Base {
public:using Base::Base;// ...
};

在上述示例中,派生类 Derived 使用 using Base::Base; 语句继承了基类 Base 的构造函数。这样,Derived 类可以直接使用 Base 类的构造函数,而无需显式定义自己的构造函数。

1.5 禁用方法

默认方法(Default Functions),默认方法是指编译器自动生成的特殊成员函数,包括默认构造函数、析构函数、复制构造函数和赋值运算符重载函数。在C++11之前,如果没有显式定义这些函数,编译器会自动生成它们的默认实现。但是,从C++11开始,可以使用 =default 语法来显式地指定使用编译器生成的默认实现。

class MyClass {
public:MyClass() = default;~MyClass() = default;MyClass(const MyClass&) = default;MyClass& operator=(const MyClass&) = default;// ...
};

使用 =default 可以明确表示使用编译器生成的默认实现,提高代码的可读性和维护性。

禁用方法(Deleted Functions),禁用方法是指使用 =delete 语法来明确禁止使用某个函数。当我们不希望某个函数被调用时,可以将其声明为禁用方法。这样,如果在代码中尝试调用被禁用的函数,编译器会报错。

class NonCopyable {
public:NonCopyable() = default;NonCopyable(const NonCopyable&) = delete;NonCopyable& operator=(const NonCopyable&) = delete;// ...
};

在上述示例中,通过将复制构造函数和赋值运算符重载函数声明为禁用方法,我们可以禁止对象的复制和赋值操作

1.6 返回值类型

在C++类中,函数的返回值类型可以是值、常量对象、引用或常量引用。不同的返回值类型在不同的场景下有其特定的用途。

(1) 值返回(Return by Value):当函数返回一个值时,它会创建一个临时对象,并将函数内部对象的值复制到该临时对象中。这个临时对象将作为函数的返回值被返回给调用方。值返回适用于以下情况:

  • 返回的对象较小,复制成本较低。
  • 返回的对象是函数内部创建的,没有与外部共享状态。
  • 不需要在函数外部修改返回的对象。
class Point {
public:int getX() const { return x; }// ...
private:int x;// ...
};

(2) 常量对象返回(Return by Const Object),当函数返回一个常量对象时,它表示返回的对象不能被修改。这提供了一种安全性,确保调用方不会意外地修改返回的对象。常量对象返回适用于以下情况:

  • 返回的对象不应被修改。
  • 希望强调返回对象的不可变性。
class Date {
public:const std::string& getFormattedDate() const {// ...return formattedDate;}// ...
private:std::string formattedDate;// ...
};

(3) 引用返回(Return by Reference):当函数返回一个引用时,它返回的是对象的引用,而不是对象的副本。引用返回允许在函数外部直接访问和修改函数内部的对象。引用返回适用于以下情况:

  • 返回的对象是函数外部已经存在的对象。
  • 希望在函数外部能够修改返回的对象。
  • 返回的对象较大,复制成本较高,希望避免不必要的复制。
class Array {
public:int& operator[](size_t index) {return data[index];}// ...
private:int data[100];// ...
};

(4) 常量引用返回(Return by Const Reference):当函数返回一个常量引用时,它返回的是对象的引用,但该引用不允许修改对象。常量引用返回提供了访问对象的能力,同时确保了对象的不可变性。常量引用返回适用于以下情况:

  • 返回的对象是函数外部已经存在的对象。
  • 希望在函数外部能够访问返回的对象,但不允许修改它。
  • 返回的对象较大,复制成本较高,希望避免不必要的复制。
class Person {
public:const std::string& getName() const {return name;}// ...
private:std::string name;// ...
};
1.7 内存处理(new/delete)

在C++中,使用new运算符动态分配对象时,会先分配内存,然后调用类的构造函数来初始化对象。相应地,使用delete运算符释放对象时,会先调用类的析构函数来清理资源,然后再释放内存。

class MyClass {
public:MyClass() {std::cout << "Constructor called" << std::endl;}~MyClass() {std::cout << "Destructor called" << std::endl;}
};int main() {MyClass* obj = new MyClass();  // 分配内存并调用构造函数delete obj;                    // 调用析构函数并释放内存return 0;
}

定位new运算符(Placement New Operator),定位new运算符允许在已分配的内存上构造对象。它接受一个指向内存位置的指针作为参数,并在该位置构造对象。定位new运算符通常用于在特定的内存位置上构造对象,如在预分配的内存池中创建对象。

int main() {char* buffer = new char[sizeof(MyClass)];  // 分配原始内存MyClass* obj = new (buffer) MyClass(42);   // 使用定位new在buffer上构造对象obj->~MyClass();                           // 显式调用析构函数delete[] buffer;                           // 释放原始内存return 0;
}

在某些情况下,我们可能需要显式调用对象的析构函数,而不是依赖于delete运算符。这通常发生在使用定位new运算符构造对象时,或者在使用placement new构造对象数组时

int main() {char* buffer = new char[sizeof(MyClass) * 3];  // 分配原始内存MyClass* obj1 = new (buffer) MyClass();        // 使用定位new构造对象MyClass* obj2 = new (buffer + sizeof(MyClass)) MyClass();MyClass* obj3 = new (buffer + sizeof(MyClass) * 2) MyClass();obj3->~MyClass();  // 显式调用析构函数obj2->~MyClass();obj1->~MyClass();delete[] buffer;   // 释放原始内存return 0;
}

在上述示例中,我们使用定位new在预分配的内存上构造了多个对象。由于没有使用delete运算符,我们需要显式调用每个对象的析构函数来进行清理。注意,析构函数的调用顺序与构造顺序相反。

1.8 嵌套结构体

在C++中,可以在一个类或结构体内部定义另一个类或结构体,这种内部定义的类或结构体称为嵌套类(Nested Class)或嵌套结构体(Nested Struct)。嵌套类和嵌套结构体提供了一种将相关类或结构体组织在一起的方式,增强了代码的可读性和封装性。

嵌套类(Nested Class),嵌套类是在另一个类的内部定义的类。它可以访问外部类的成员,包括私有成员和保护成员。嵌套类通常用于实现与外部类密切相关的功能,或者用于隐藏实现细节。

class Outer {
public:void outerMethod() {Inner inner;inner.innerMethod();}
private:class Inner {public:void innerMethod() {std::cout << "Inner method called" << std::endl;}};
};

在上述示例中,Inner类是在Outer类内部定义的嵌套类。Outer类的成员函数outerMethod()可以直接创建和使用Inner类的对象。

嵌套结构体(Nested Struct),嵌套结构体与嵌套类类似,只是使用struct关键字定义。嵌套结构体的成员默认为公有访问权限,而嵌套类的成员默认为私有访问权限。

struct Outer {void outerMethod() {Inner inner;inner.x = 10;}struct Inner {int x;};
};

在上述示例中,Inner结构体是在Outer结构体内部定义的嵌套结构体。Outer结构体的成员函数outerMethod()可以直接访问和修改Inner结构体的成员变量x

要在外部类或结构体之外访问嵌套类或嵌套结构体,需要使用外部类或结构体的作用域解析运算符::

class Outer {
public:class Inner {public:void innerMethod() {std::cout << "Inner method called" << std::endl;}};
};int main() {Outer::Inner inner;inner.innerMethod();return 0;
}

在上述示例中,我们在main()函数中创建了Outer::Inner类型的对象,并调用了其成员函数innerMethod()

1.9 成员初始化列表

在C++中,成员初始化列表(Member Initialization List)是一种在构造函数中初始化类成员变量的方式。它提供了一种更高效、更清晰的方法来初始化成员变量,特别是对于常量成员、引用成员以及没有默认构造函数的类类型成员。

常见使用场景如下:

  • 常量成员变量:常量成员变量必须在构造函数的成员初始化列表中初始化,因为它们不能在构造函数体内被赋值。
  • 引用成员变量:引用成员变量必须在构造函数的成员初始化列表中初始化,因为引用必须在定义时绑定到一个对象。
  • 没有默认构造函数的类类型成员:如果类成员变量是没有默认构造函数的类类型,那么必须在成员初始化列表中显式初始化它们。
  • 基类构造函数初始化:在派生类的构造函数中,必须使用成员初始化列表来调用基类的构造函数。
  • 提高效率:对于内置类型和有默认构造函数的类类型成员,使用成员初始化列表可以避免默认构造和再赋值的过程,提高效率。

使用限制如下:

  • 成员初始化列表中的成员变量初始化顺序与它们在类中声明的顺序相同,而不是按照成员初始化列表中的顺序。
  • 成员初始化列表不能用于初始化静态成员变量,静态成员变量需要在类外部单独初始化。
  • 如果一个成员变量在成员初始化列表中被初始化,就不能再在构造函数体内对其赋值,否则会报错。
class MyClass {
public:MyClass(int a, const std::string& s) : constantMember(42), referenceMember(s), intMember(a), 	objectMember(a, s) {// 构造函数体}
private:const int constantMember;const std::string& referenceMember;int intMember;SomeClass objectMember;
};

在上述示例中,MyClass的构造函数使用成员初始化列表来初始化常量成员constantMember、引用成员referenceMember、内置类型成员intMember以及类类型成员objectMember。成员初始化列表中的初始化顺序与成员变量在类中声明的顺序相同。

C++11引入了类内初始化(In-class Initialization)特性,允许在类内部直接为非静态成员变量提供默认初始值。这样可以简化构造函数的编写,同时提供了一种更清晰、更一致的方式来初始化成员变量。

class MyClass {
public:MyClass(int a) : intMember(a) {// 构造函数体}
private:int intMember = 0;std::string stringMember = "Default";std::vector<int> vectorMember{1, 2, 3};
};

在上述示例中,intMemberstringMembervectorMember都在类内部提供了默认初始值。如果构造函数没有显式初始化这些成员变量,它们将使用类内部指定的默认值。

需要注意的是,类内初始化不能用于常量成员、引用成员以及没有默认构造函数的类类型成员,这些成员变量仍然需要在成员初始化列表中显式初始化







Alt

Once Day

也信美人终作土,不堪幽梦太匆匆......

如果这篇文章为您带来了帮助或启发,不妨点个赞👍和关注,再加上一个小小的收藏⭐!

(。◕‿◕。)感谢您的阅读与支持~~~

相关文章:

C++(11)类语法分析(2)

C(10)之类语法分析(2) Author: Once Day Date: 2024年8月17日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 源码分析_Once-Day的博客-CSDN博客 …...

数字验证每日十问--(3)

深拷贝和浅拷贝的区别&#xff1f; 当只拷贝对象中的成员变量和声明的句柄时&#xff0c;称为浅拷贝。浅拷贝只把对象中的句柄复制了&#xff0c;却没有复制句柄b所指向的对象。这会导致复制后&#xff0c;a2中的句柄b 和 a1 中的句柄b指向同一个对象&#xff0c;如果a2中的句…...

22.给定 n 对括号,实现一个算法生成所有可能的正确匹配的括号组合

22. Generate Parentheses 题目 给定 n 对括号,编写一个函数生成所有可能的正确匹配的括号组合。 例如,当 n = 3 时,可能的组合集合为: ["((()))","(()())","(())()","()(())","()()()" ]题目大意 给出 n 代表生成…...

检测到目标URL存在http host头攻击漏洞

漏洞描述 修复措施 方法一&#xff1a; nginx 的 default_server 指令可以定义默认的 server 去处理一些没有匹配到 server_name 的请求&#xff0c;如果没有显式定义&#xff0c;则会选取第一个定义的 server 作为 default_server。 server { …...

C++奇迹之旅:手写vector模拟实现与你探索vector 容器的核心机制与使用技巧

文章目录 &#x1f4dd;基本框架&#x1f320; 构造和销毁&#x1f309;vector()&#x1f309;vector(const vector& v)&#x1f309;vector(size_t n, const T& value T())&#x1f309;赋值拷贝构造&#xff1a;vector<T>& operator(vector<T> v)&a…...

018、钩子函数 mounted和beforeDestroy、父组件向子组件传递参数 props 的使用

文章目录 1、mounted 和 beforeDestroy1.1、mounted1.2、beforeDestroy 2、父组件向子组件传递参数 props2.1、子组件定义2.2、父组件调用子组件并传参 3、完整例子3.1、父组件 Tags.vue3.2、子组件 TagsMenu.vue3.3、效果图 1、mounted 和 beforeDestroy 1.1、mounted mount…...

xlnt在Windows中的dll,lib生成

前言 花了半天时间想要把xlnt 集成到VS2022 Cmake项目中,以我目前掌握的能力,Cmake语法对于我来说难懂,对于只是使用过Cmake编译MySQL,或是其他lib,dll库的小白来说,不应该为了显示自己能力多么出众,强行去配置一些程序内容。 生活中没有绝对的事情,有舍有得. https://github…...

【网络】私有IP和公网IP的转换——NAT技术

目录 引言 NAT工作机制​编辑 NAT技术的优缺点 优点 缺点 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 公网被子网掩码划分为层状结构&#xff0c;一个公网IP的机器又可以用很多私有IP搭建内网。在日常生活场景中用的都是私有IP&#xff0c;例如手机&#xff0c;…...

java 面试 PDF 资料整理

“尊贵的求知者&#xff0c;作者特此献上精心编纂的Java面试宝典PDF&#xff0c;这份资料凝聚了无数面试精华与实战经验&#xff0c;是通往Java技术殿堂的钥匙。若您渴望在Java编程的求职之路上稳健前行&#xff0c;只需轻轻一点&#xff0c;完成这象征支持与认可的一键三联&am…...

初步认识Linux系统

前言 Linux系统具有许多优点&#xff0c;不仅系统性能稳定&#xff0c;而且是开源软件。其核心防火墙组件性能高效、配置简单&#xff0c;保证了系统的安全。在很多企业网络中&#xff0c;为了追求速度和安全&#xff0c;Linux不仅仅是被网络运维人员当作服务器使用&#xff0c…...

JavaScript AI 编程助手

JavaScript AI 编程助手 引言 随着人工智能技术的飞速发展&#xff0c;编程领域也迎来了前所未有的变革。JavaScript&#xff0c;作为全球最流行的编程语言之一&#xff0c;其与AI的结合为开发者带来了巨大的便利和无限的可能性。本文将探讨JavaScript AI编程助手的定义、功能…...

达梦数据库的系统视图v$datafile

达梦数据库的系统视图v$datafile 达梦数据库的V$DATAFILE 是一个重要的系统视图&#xff0c;提供了有关数据库数据文件的信息。 V$DATAFILE 系统视图 V$DATAFILE 视图用于显示数据库中每一个数据文件的详细信息。通过查询这个视图&#xff0c;数据库管理员可以了解数据文件的…...

Triton/window安装: triton-2.0.0-cp310-cp310-win_amd64.whl文件

下面这个github仓&#xff1a; https://github.com/PrashantSaikia/Triton-for-Windows/tree/main 安装命令也很简单&#xff0c;下载到本地后运行: pip install triton-2.0.0-cp310-cp310-win_amd64.whl...

应急响应-DDOS-典型案例

某单位遭受DDoS攻击事件如下 事件背景 2019年2月17日&#xff0c;某机构门户网站无法访问&#xff0c;网络运维人员称疑似遭受DDoS攻击&#xff0c;请求应急响应工程师协助。 事件处置 应急响应工程师在达到现场后&#xff0c;通过查看流量设备&#xff0c;发现攻击者使用僵…...

JAVA学习之知识补充(下)

六&#xff1a;File类与IO流&#xff1a; 这里给出三种常见的初始化方法&#xff1a; 通过文件路径初始化: File file new File("C:/example/test.txt");这种方法用于创建一个文件对象&#xff0c;该文件对象表示指定路径的文件或目录。例如&#xff1a;File fil…...

qt生成一幅纯马赛克图像

由于项目需要&#xff0c;需生成一幅纯马赛克的图像作为背景&#xff0c;经过多次测试成功&#xff0c;记录下来。 方法一&#xff1a;未优化方法 1、代码&#xff1a; #include <QImage> #include <QDebug> #include <QElapsedTimer>QImage generateMosa…...

python循环——九九乘法表(更加轻松的理解循环结构)

感受 首先&#xff0c;得明确意识到这个问题&#xff0c;就是我的循环结构学的一塌糊涂&#xff0c;完全不能很好的使用这个循环来实现各种九九乘法表达输出&#xff0c;这样的循环结构太差了&#xff0c;还需要我自己找时间来补充一下循环的使用&#xff0c;来拓宽自己的思考方…...

UDS诊断系列之十八故障码的状态掩码

在谈19服务的子功能之前&#xff0c;先说一下故障码&#xff08;DTC&#xff09;的状态掩码是什么。 一、状态掩码 状态掩码由八个状态位构成&#xff0c;客户端利用它向服务器请求与其状态相匹配的DTC信息。当服务器接收到来自客户端的请求时&#xff0c;它会通过过滤匹配的…...

【jvm】直接引用

目录 1. 说明2. 形式3. 特点4. 生成过程5. 作用 1. 说明 1.在Java虚拟机&#xff08;JVM&#xff09;中&#xff0c;直接引用&#xff08;Direct Reference&#xff09;是相对于符号引用&#xff08;Symbolic Reference&#xff09;而言的&#xff0c;它是指向内存中实际存在的…...

PythonStudio 控件使用常用方式(二十七)TActionList

PythonStudio是一个极强的开发Python的IDE工具&#xff0c;官网地址是&#xff1a;https://glsite.com/ &#xff0c;在官网可以下载最新版的PythonStudio&#xff0c;同时&#xff0c;在使用PythonStudio时&#xff0c;它也能及时为用户升到最新版本。它使用的是Delphi的控件&…...

PDF 转Word 开源库

1. Apache PDFBox Apache PDFBox 是一个开源的 Java 库&#xff0c;用于创建和操作 PDF 文档。虽然 PDFBox 本身没有直接支持 PDF 转 Word 的功能&#xff0c;但它可以提取 PDF 内容&#xff0c;你可以结合其他方法将这些内容写入 Word。 添加依赖 <dependency><gr…...

Docker - 深入理解Dockerfile中的 RUN, CMD 和 ENTRYPOINT

RUN docker file 中的 RUN 命令相对来教容易理解 RUN 指令用于在构建镜像时执行命令&#xff0c;这些命令会在 Docker 镜像的构建过程中执行。常用于安装软件包、设置环境变量、创建目录等。RUN 指令会在镜像构建中创建新的镜像层&#xff0c;每个 RUN 指令都会创建一个新的镜…...

Python 函数式编程 内置高阶函数及周边【进阶篇 3】推荐

前面我们已经总结并实践了用python获取到了数据。也介绍了python中http网络请求的几种方式&#xff0c;正在学习python开发语言或者对python3知识点生疏需要回顾的请点这里 &#xff0c;本章主要总结了函数式编程及特点 和 python中内置的高阶函数及周边知识&#xff0c;方便自…...

【Rust光年纪】探秘Rust GUI库:从安装配置到API概览

Rust语言GUI库全方位比较&#xff1a;选择适合你的工具 前言 在现代软件开发中&#xff0c;图形用户界面&#xff08;GUI&#xff09;库扮演着至关重要的角色。随着Rust语言的不断发展&#xff0c;越来越多的优秀的GUI库也相继问世&#xff0c;为Rust开发者提供了更多选择。本…...

Element plus部分组件样式覆盖记录

文章目录 一、el-button 样式二、Popconfirm 气泡确认框三、Popover 气泡卡片四、Checkbox 多选框五、Pagination 分页六、Form 表单七、Table 表格 一、el-button 样式 html&#xff1a; <el-button class"com_btn_style">button</el-button>样式覆盖…...

重塑业务生态,Vatee万腾平台:引领行业变革的新引擎

在数字经济浪潮汹涌的今天&#xff0c;传统行业的边界正被不断模糊与重塑&#xff0c;新兴技术如云计算、大数据、人工智能等正以前所未有的速度改变着商业世界的面貌。在这一背景下&#xff0c;Vatee万腾平台应运而生&#xff0c;以其独特的创新模式和强大的技术实力&#xff…...

标准术语和定义中的【架构】应该如何描述

一、参考国家标准和国际标准中对“架构”的描述 &#xff08;1&#xff09;GB/T 8566-2022 国家标准 架构的术语描述&#xff1a;(系统)在其环境中的一些基本概念或性质,体现在其元素关系,以及设计与演进原则中。 &#xff08;2&#xff09;ISO/IEC/IEEE 42010 国际标准 架构的…...

华为鸿蒙Core Vision Kit 骨骼检测技术

鸿蒙Core Vision Kit 是华为鸿蒙系统中的一个图像处理框架&#xff0c;旨在提供各种计算机视觉功能&#xff0c;包括物体检测、人脸识别、文本识别等。骨骼检测是其中的一项功能&#xff0c;主要用于检测和识别人类身体的骨骼结构。 骨骼检测的关键点 骨骼点检测&#xff1a;通…...

Table API SQL系统(内置)函数System (Built-in) Function详解

目录 函数类型 引用函数 函数精确引用 函数模糊引用 函数解析顺序 精确的函数引用 模糊的函数引用 系统函数 标量函数(Scalar Functions) 比较函数(Comparison Functions) 逻辑函数(Logical Functions) 算术函数(Arithmetic Functions) 字符串函数(Strin…...

一键运行RocketMQ5.3和Dashboard

一键运行RocketMQ5.3和Dashboard 目录 一键运行RocketMQ5.3和Dashboard通过Docker Compose 来一键启动运行的容器包括docker-compose.yml文件运行命令启动本地效果查看 参考信息 通过Docker Compose 来一键启动 运行的容器包括 NameServerBrokerProxyDashBoard docker-compo…...

HAL STM32 SG90舵机驱动控制

HAL STM32 SG90舵机驱动控制 &#x1f516;测试对象&#xff1a;STM32F103SG90舵机 &#x1f33c;功能实现&#xff1a;通过串口指令&#xff0c;控制SG90舵机转动到指定角度。 ✨在实际硬件舵机驱动过程中&#xff0c;使用SG90普通舵机空载运转情况下&#xff0c;电流在180mA…...

【Kubernetes】k8s集群图形化管理工具之rancher

目录 一.Rancher概述 1.Rancher简介 2.Rancher与k8s的关系及区别 3.Rancher具有的优势 二.Rancher的安装部署 1.实验准备 2.安装 rancher 3.rancher的浏览器使用 一.Rancher概述 1.Rancher简介 Rancher 是一个开源的企业级多集群 Kubernetes 管理平台&#xff0c;实…...

AI编程系列一1小时完成链家房价爬虫程序

背景 AI编程实在太火&#xff0c;写了很多年的Java&#xff0c;现在Python 和Go 简单好用&#xff0c;今天结合智谱清言快速完成一个程序爬虫程序&#xff0c;没有任何Python 编程经验&#xff0c;只需要会提问&#xff0c;熟悉简单HTML结构即可。未来一定是有业务能力者的福…...

【JavaEE初阶】文件内容的读写—数据流

目录 &#x1f4d5; 引言 &#x1f334; 数据流的概念 &#x1f6a9; 数据流分类 &#x1f333; 字节流的读写 &#x1f6a9; InputStream&#xff08;从文件中读取字节内容) &#x1f6a9; OutputStream&#xff08;向文件中写内容&#xff09; &#x1f384; 字符流的…...

Spring Boot项目中使用Sharding-JDBC实现读写分离

Sharding-JDBC是一个分布式数据库中间件&#xff0c;它不仅支持数据分片&#xff0c;还可以轻松实现数据库的读写分离。下面是如何在Spring Boot项目中集成Sharding-JDBC并实现读写分离的详细步骤&#xff1a; 目录 1. 引入依赖 2. 配置数据源 3. 配置Sharding-JDBC相关参数…...

【网络安全】SSO登录过程实现账户接管

未经许可,不得转载。 文章目录 正文正文 登录页面展示了“使用 SSO 登录”功能: 经分析,单点登录(SSO)系统的身份验证过程如下: 1、启动SSO流程:当用户点击按钮时,浏览器会发送一个GET请求到指定的URL: /idp/auth/mid-oidc?req=[UNIQUE_ID]&redirect_uri=[REDI…...

Admin.NET源码学习(3:LazyCaptcha使用浅析)

Admin.NET项目前端登录页面的验证码图片默认使用动态图&#xff0c;且图形内容为阿拉伯数字运算&#xff08;如下图所示&#xff09;&#xff0c;用户输入正确的计算结果才能正常登录。项目采用LazyCaptcha模块生成验证码及动态图。   在Admin.NET.Core项目中添加了Lazy.Cap…...

在原生未启用kdump的BCLinux 8系列服务器上启用kdump及报错处理

本文记录了在原生未启用kdump的BCLinux 8系列操作系统的服务器上手动启用kdump服务及报错处理的过程。 一、问题描述 BCLinux 8系列操作系统&#xff0c;系统初始化安装时未启用kdump服务&#xff0c;手动启动时报以下“No memory reserved for crash kernel”或“ConditionK…...

Android架构组件中的MVVM

Android架构组件中的MVVM&#xff08;Model-View-ViewModel&#xff09;模式是一种广泛应用的设计模式&#xff0c;它通过将应用程序分为三个主要部分&#xff08;Model、View、ViewModel&#xff09;来分离用户界面和业务逻辑&#xff0c;从而提高代码的可维护性、可扩展性和可…...

走向绿色:能源新选择,未来更美好

当前&#xff0c;全球范围内可再生能源正经历着从辅助能源向核心能源的深刻转型&#xff0c;绿色能源日益渗透至居住、出行、日常应用等多个领域&#xff0c;深刻影响着我们的生活方式&#xff0c;使我们能够更加充分地体验清洁能源所带来的优质生活。 一、绿色能源与“住” …...

鸿蒙装饰器的介绍

State装饰器&#xff0c; State装饰的变量&#xff0c;称为状态变量&#xff0c;与声明式范式中的其他被装饰变量一样&#xff0c;是私有的&#xff0c;只能从组件内部访问&#xff0c;在声明时&#xff0c;必须指定其类型和本地初始化。 Provide装饰器和Consume装饰器&#…...

零基础5分钟上手亚马逊云科技核心云架构知识 - 权限管理最佳实践

简介&#xff1a; 欢迎来到小李哥全新亚马逊云科技AWS云计算知识学习系列&#xff0c;适用于任何无云计算或者亚马逊云科技技术背景的开发者&#xff0c;通过这篇文章大家零基础5分钟就能完全学会亚马逊云科技一个经典的服务开发架构方案。 我会每天介绍一个基于亚马逊云科技…...

[数据库][知识]SQL Server、MySQL 和 Oracle 的默认端口和数据库链接

SQL Server、MySQL 和 Oracle 的默认端口号、连接 URL 和驱动类名。以下是对每个数据库连接信息的简要说明&#xff1a; SQL Server 默认端口号&#xff1a;1433JDBC URL 格式&#xff1a;jdbc:sqlserver://localhost:1433;DatabaseNamedbnameJDBC 驱动类名&#xff1a;com.mic…...

【Unity教程】使用 Animation Rigging实现IK制作程序化的动画

在 Unity 开发中&#xff0c;为角色创建逼真且自适应的动画是提升游戏体验的关键。在本教程中&#xff0c;我们将结合 Animation Rigging 工具和 IK&#xff08;Inverse Kinematics&#xff0c;反向运动学&#xff09;插件来实现程序化的动画。 视频教程可以参考b战大佬的视频 …...

OBS混音器(Mixers)的重要性和配置指南

在进行直播或录制时,音频管理是非常关键的一环,特别是在需要同时处理多个音频源的复杂设置中。OBS Studio提供了强大的音频管理工具,其中“混音器”功能扮演了核心角色。混音器(Mixers)在OBS中用于控制不同音频源的输出路由,允许用户精确控制哪些音源出现在最终的直播或录…...

Ubuntu安装Anaconda3

本文详细阐述了在 Ubuntu 系统中安装 Anaconda3 的完整流程。包括 Anaconda3 安装包的获取途径&#xff0c;具体安装过程中的每一个步骤及注意事项&#xff0c;还有安装后的环境变量设置和安装成功的验证方法。旨在为 Ubuntu 用户提供清晰、易懂且准确的 Anaconda3 安装指南&am…...

数据类型解码:INT、VARCHAR、DATETIME的深度解析与实践

标题&#xff1a;数据类型解码&#xff1a;INT、VARCHAR、DATETIME的深度解析与实践 在软件开发和数据库设计中&#xff0c;数据类型是构建数据模型的基础。准确理解和使用数据类型&#xff0c;如INT、VARCHAR、DATETIME&#xff0c;对于确保数据的完整性、性能和安全性至关重…...

基于单片机的智能晾衣系统设计

摘 要 &#xff1a;在网络信息技术的推动下&#xff0c;智能家居得到了广泛应用&#xff0c;文章根据当前的市场动态&#xff0c;针对基于单片机的智能晾衣系统设计展开论述&#xff0c;具体包括两个方面的内容———硬件设计和软件设计。 关键词 &#xff1a;单片机&#xff…...

Python实战项目:天气数据爬取+数据可视化(完整代码)

一、选题的背景 随着人们对天气的关注逐渐增加&#xff0c;天气预报数据的获取与可视化成为了当今的热门话题&#xff0c;天气预报我们每天都会关注&#xff0c;天气情况会影响到我们日常的增减衣物、出行安排等。每天的气温、相对湿度、降水量以及风向风速是关注的焦点。通过…...

知识改变命运 数据结构【链表面试题】

1. 删除链表中等于给定值 val 的所有节点。 OJ链接 public ListNode removeElements(ListNode head, int val) {if (headnull) {return null;}ListNode curhead.next;ListNode prehead;while(cur!null) {if(cur.valval) {pre.nextcur.next;curcur.next;}else {precur;curcur.ne…...