C++:类和对象(从底层编译开始)详解[前篇]
目录
一.inline内联的详细介绍
(1)为什么在调用内联函数时不需要建立栈帧:
(2)为什么inline声明和定义分离到两个文件会产生链接错误,链接是什么,为什么没有函数地址:
二.类,实例化和this指针
1.类的介绍(class):
2.实例化:
(1)实例化的概念:
(2)实例化的空间分配:
3.this指针:
4.关于空指针访问成员变量的注意点:
三.类的默认成员函数
1.构造函数:
2.析构函数:
3.拷贝构造函数:
4.运算符重载:
四.日期类实现
一.inline内联的详细介绍
为了更清楚的明白类的定义与底层运行逻辑,我先从inline内联开始讲起:
• ⽤inline修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧了,就可以提高效率 //(1)为什么不需要建立栈帧
• inline对于编译器⽽⾔只是⼀个建议,也就是说,你加了inline编译器也可以选择在调⽤的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定,inline适用于频繁调⽤的短⼩函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略(因为内联的展开在需要频繁调用短小函数的代码里,可以大限度上减少函数调用指令(call)的使用,而在其他函数体本身较大的情况下,inline不展开的调用指令的方法可能会显得更为简便)
• C语言实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不⽅便调 试,C++设计了inline⽬的就是替代C的宏函数
• vs编译器debug版本下⾯默认是不展开inline的,这样方便调试
• inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错//(2)为什么会产生链接错误,链接是什么,为什么没有函数地址
(内联的使用示例)
#include <iostream>// 显式声明为内联函数 inline int add(int a, int b) {return a + b; }int main() {std::cout << add(3, 5) << std::endl; // 编译器可能将 add(3,5) 展开为 `3 + 5`return 0; }
上述的阐述乍看总有种似懂非懂的感觉,但一旦深入想想就还有好些东西不明不白,下面我将对这段话中可能会产生的疑问做出一一解答:
(1)为什么在调用内联函数时不需要建立栈帧:
(a).在理解这个问题之前,我们需要先搞明白函数的栈帧是怎么一回事:
简而言之栈帧是程序执行过程中用于保存函数调用状态的临时数据结构,它在函数调用时被创建,返回时销毁。每个栈帧对应一次函数调用,记录了函数的执行上下文信息
以下这张图片就展示了函数Add在调用时所创建的栈帧,而其中的push等相关汇编命令我也附在下面:
(b).再让我们区别以下函数的栈帧与整体代码的编译和链接的关系:
据上述代码编译的过程而言,函数栈帧的创建属于程序运行时的动态数据结构,虽与编译链接过程的静态代码无关,但编译与链接依旧会在其运行时对其产生影响:如编译阶段为栈帧的创建和销毁生成正确的指令,以及链接阶段确定函数的位置以及符号引用,因此,一般情况下较小的函数被inline展开时,其函数名并不会进入符号表,而是直接在调用处替换代码(发生在预处理中,编译之前),自然也就跟栈帧的创建销毁没啥关系了
(2)为什么inline声明和定义分离到两个文件会产生链接错误,链接是什么,为什么没有函数地址:
inline之所以不建议声明定义分离,是因为当我们假设在head.h头文件里定义了内联函数add(自定义函数名)然后分别在a.cpp里定义add函数然后在b.cpp里调用add函数然后运行,那么在对程序进行编译时,会发现对于add函数头文件里只有声明而没有定义,因此编译器会假设add为一个外部函数(这里类似于一般函数的跨文件调用),但与一般函数调用不同的是,一般函数在假设外部函数时会同时在符号表生成一个对函数的引用(包含了未解析的地址),然后再在链接过程中通过对各文件的链接重新补全符号表里未解析的地址,从而实现函数声明定义的分开,但inline函数却不一样,它同样会在符号表里生成一个未解析的地址,但由于inline函数的性质就是对函数体代码的整体替换从而实现对指令代码的节约使用,而且需要明确的内联点才可以进行替换,因此这样导致了其无法在链接时找到对应的内联点进而不能像一般函数那样在链接过程中补全对应的符号表里未解析的地址(内联需要替换的代码都找不到更别说地址了),从而发生链接的报错
二.类,实例化和this指针
1.类的介绍(class):
其中有两点需要特别注意:
(a) 类中的成员函数默认为内联
(b)关于访问限定符:
如下代码:public和private是访问限定符,在public后面的成员函数和成员变量可以直接在类的外部使用,private后面的成员函数和成员变量不能被直接使用。
通常我们把成员函数定义为public,把成员变量定义为private
#include<iostream> using namespace std; class TEST { public://成员函数void test(){return;} private://成员变量int _a;int _b; }; //以上class为类的关键字,TEST为类的名字,{}中的为类的主体//但同样的,C++由于相当于C的pro max版,同时也可以兼容C中的struct结构: typedef struct ListNodeC {struct ListNodeC* next;int val; }LTNode;int main() {return 0; }
关于类域:
#include<iostream> using namespace std;class TEST { public://成员函数声明int test(int a, int b);private://成员变量int _a;int _b; }; //类定义了一个新的作用域,类的所有成员函数都在类的作用域中。在类体外定义成员时,需要使用类域名::来访问成员 //如果不指定类域的话,在定义函数时,程序在全局域找不到函数的声明就会报错。编译器不会主动去类域中寻找函数定义 int TEST::test(int a, int b) {return a + b; } int main() {TEST A;int c = 10; int d = 20;cout << A.test(c, d) << endl;return 0; }
2.实例化:
(1)实例化的概念:
(2)实例化的空间分配:
对象的大小只包含成员变量的大小,成员函数不占内存空间
打个比方,现在实例化出了两个类,分别为A,B但A和B的成员变量和地址是不同的,但如果访问这两个类的成员函数,他们都会链接到一个地址(只读存储区,静态存储),所以说我们sizeof(类对象)只用统计成员变量占用的空间
成员变量占用的空间也符合内存对齐规则:
关于这个对齐其实有点比较容易遗忘,因此我再简述一下:
1. 基本概念
对齐:数据类型的起始地址必须是该类型大小的整数倍
例如: int (4字节)的地址必须是 0x4, 0x8, 0xC...
未对齐:数据起始地址不满足对齐规则,可能导致性能下降或硬件错误(如 ARM 架构)
2. 内存对齐规则
a. 自然对齐
规则:每个数据类型的地址必须是其自身大小的整数倍
示例:struct AlignedStruct {char a; // 1字节 → 地址 0x0int b; // 4字节 → 地址 0x4(填充3字节)double c; // 8字节 → 地址 0x8(填充7字节) };
b. 结构体对齐
成员顺序:成员按声明顺序排列,每个成员按自然对齐对齐举例:
struct CompactStruct {int a; // 0x0char b; // 0x4(填充3字节)short c; // 0x8 }; // 总大小:12字节(而非 16字节)
3.this指针:
• Date类中有Init与Print两个成员函数,函数体中没有关于不同对象的区分,那当d1调⽤Init和 Print函数时,该函数是如何知道应该访问的是d1对象还是d2对象呢?那么这⾥就要看到C++给了 ⼀个隐含的this指针解决这⾥的问题
• 编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个当前类类型的指针,叫做this 指针。⽐如Date类的Init的真实原型为, void Init(Date* const this, int year, int month, int day)
• 类的成员函数中访问成员变量,本质都是通过this指针访问的,如Init函数中给_year赋值, this- >_year = year;
• C++规定不能在实参和形参的位置显示的写this指针(编译时编译器会处理),但是可以在函数体内显示使⽤this指针
另外需要注意一点,this指针其实存放在栈区,而不是对象里面
#include<iostream> using namespace std; class Date { public:// void Init(Date* const this, int year, int month, int day)void Init(int year, int month, int day){// this->_year = year;_year = year;this->_month = month;this->_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;} private:// 这⾥只是声明,没有开空间 int _year;int _month;int _day; };int main() {Date A;return 0; }//成员函数在传参时都有一个类的指针类型的this指针,这个this指针编译器不会显示出来,但实际上他是存在的,看上边这串代码,如果再函数调用赋值的时候,可以手动把this指针加上去,这样其实并不会报错。这就说明这个this指针是真实存在的
4.关于空指针访问成员变量的注意点:
先看一下下面这两个代码:
这两串代码运行的结果并不相同,已知第一个是正常运行,第二个是运行崩溃,首先我们应该知道不管是C语言中还是C++中,解引用空指针并不会编译报错,只会运行崩溃
其次再来分析问什么第二个是运行崩溃
首先成员函数不会占用物理内存,只有成员变量会,实例出nullptr说明没开空间,但仔细看第一个程序是不需要访问成员变量的,所以不开空间也没有报错,而第二个程序访问了开空间的成员变量:_a,所以运行崩溃了
三.类的默认成员函数
默认成员函数就是⽤⼾没有显式实现,编译器会⾃动⽣成的成员函数称为默认成员函数:
接下来我会对其中的几个做出详细介绍:
1.构造函数:
构造函数也是一种成员函数,但他和我们写的普通构造函数不同的是,他是在我们实例化类的对象是默认调用的,也就是说,实例化对象是他自己会去主动调用这个构造函数,其本质是要替代我们以前Stack和Date类中写的Init函数的功能,构造函数⾃动调⽤的 特点就完美的替代的了Init
接下来说说它的基本特点:
函数名和类名相同;
没有返回值:
#include<iostream> using namespace std; class DATE { public:DATE(int year = 2000, int mouth = 11, int day = 1){_year = year;_mouth = mouth;_day = day;} private://成员函数//private成员函数不能直接访问,可以通过成员函数访问int _year;int _mouth;int _day; }; int main() {DATE d1;return 0; }//上面这串代码中定义了一个日期类,并实例化出一个对象d1,调试可以看到,实例化d1自动调用了DATE这个构造函数,给d1的三个成员变量进行了赋值//构造函数也有很多种,第一种无参构造函数。第二种是全缺省构造函数,第三种就是不写构造时编译器默认的构造函数(接下来我会具体说说这三种函数),如果我们在实例化的时候只写这个对象就像上面这串代码这样:DATE d1; 这样调用的构造函数叫默认构造
//无参构造函数 DATE() {_year = 1;_mouth = 1;_day = 1; }//全缺省构造函数 DATE(int year = 2000, int mouth = 11, int day = 1) {_year = year;_mouth = mouth;_day = day; }// 带参构造函数 Date(int year, int month, int day) {_year = year;_month = month;_day = day; }
除了以上几点还有一点需要额外注意:如果类中没有显式定义构造函数,则C++编译器会⾃动⽣成⼀个⽆参的默认构造函数,⼀旦用户显式定义编译器将不再⽣成,也就是说我们不写,编译器默认⽣成的构造,对内置类型成员变量的初始化没有要求,也就是说是是否初始化是不确定的,看编译器。对于⾃定义类型成员变量,要求调⽤这个成员变量的默认构造函数初始化, 如果这个成员变量,没有默认构造函数,那么就会报错,我们要初始化这个成员变量,需要⽤初始化列表才能解决,初始化列表的问题,本文先放一下,下一篇文章再作详细介绍
读到这里,会发现一个问题就是既然系统会自动生成默认构造函数,那为什么我们还需要自己去写构造函数?举个例子:
当类需要动态分配内存(如 new 或 malloc )时,默认构造函数无法自动释放资源,必须手动管理:
class Buffer { public:int* data; // 动态内存// 自定义构造函数:初始化 dataBuffer(int size) : data(new int[size]) {std::cout << "Buffer initialized with size " << size << std::endl;}// 析构函数:释放资源~Buffer() {delete[] data;std::cout << "Buffer destroyed" << std::endl;} };int main() {Buffer buf(1024); // 调用自定义构造函数return 0; }
默认构造函数不会初始化 data ,导致未定义行为(如悬空指针),自定义构造函数确保 data 正确分配内存
2.析构函数:
析构函数可以在类对象销毁时自动调用,释放我们的内存空间。就好比之前实现的栈这个数据结构,我们需要把我们malloc出来的空间都free掉,那么这个时候如果是使用c++里面的类来完成的话,在我们的栈销毁时(该对象生命周期结束时)就可以自动调用析构函数,释放内存
~Stack() {cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0; }
析构的特点也很明显:
1. 析构函数名是在类名前加上字符~
2.不需要写返回值
3.和构造函数一样,我们不写编译器⾃动⽣成的析构函数对内置类型成员不做处理,⾃定类型成员会调⽤他的析构函数
4.一个类只有一个析构且当类成员不需要释放空间时,不需要自己写析构函数
#include<iostream> using namespace std; typedef int STDataType; class Stack { public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0;} private:STDataType* _a;size_t _capacity;size_t _top; };
3.拷贝构造函数:
如果⼀个构造函数的第⼀个参数是⾃⾝类类型的引⽤,且任何额外的参数都有默认值,则此构造函数 也叫做拷贝构造函数,也就是说拷贝构造是⼀个特殊的构造函数
#include<iostream> using namespace std;class DATE { public:DATE(int year, int mouth, int day){_year = year;_mouth = mouth;_day = day;}void Print(){cout << _year << "年" << _mouth << "月" << _day << "日" << endl;} private://成员函数//private成员函数不能直接访问,可以通过成员函数访问int _year;int _mouth;int _day; }; int main() {DATE d1(10,10,10);DATE d2(d1);//调用拷贝构造d1.Print();d2.Print();return 0; } //注意,第一个参数必须是引用。否则编译器会报错。为什么会报错呢?理解一下,如果说我们传入的第一个参数没有引用,那么这个形参是得拷贝一份我们的实参,怎么拷贝呢?他还是得调用我们的拷贝构造函数去拷贝,那这就形成了闭环,而这样无限拷贝下去编译器是不允许的//对于没有主动写拷贝构造的类,编译器也会默认生成一个拷贝构造,对于内置类型进行浅拷贝,也就是只拷贝值,对于自定义类型成员会调用他的拷贝构造。
但还有几点需要注意:
1.像Date这样的类成员变量全是内置类型且没有指向什么资源,编译器⾃动⽣成的拷⻉构造就可以完 成需要的拷⻉,所以不需要我们显⽰实现拷⻉构造,但像Stack这样的类,虽然也都是内置类型,但 是_a指向了资源,编译器⾃动⽣成的拷⻉构造完成的值拷⻉/浅拷⻉不符合我们的需求,所以需要我们⾃⼰实现深拷⻉(对指向的资源也进⾏拷⻉),像MyQueue这样的类型内部主要是⾃定义类型 Stack成员,编译器⾃动⽣成的拷⻉构造会调⽤Stack的拷⻉构造,也不需要我们显⽰实现 MyQueue的拷⻉构造(前提是Stack这个类有析构)
2.传值返回会产⽣⼀个临时对象调⽤拷⻉构造,传值引⽤返回,返回的是返回对象的别名(引⽤),没有产⽣拷⻉。但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使⽤ 引⽤返回是有问题的,这时的引⽤相当于⼀个野引⽤,类似⼀个野指针⼀样。传引⽤返回可以减少拷⻉,但是⼀定要确保返回对象,在当前函数结束后还在,才能⽤引⽤返回
4.运算符重载:
运算符重载简而言之就是赋予我们常见的运算符以新的定义与使用场景,比如+号原来只可以用于数字之间的运算,但经过运算符重载之后,使其可以进行日期之间的计算,诸如此类:
bool operator==(DATE x) {return _year == x._year && _mouth == x._mouth && _day == x._day; }
以下是几个注意点:
1.不能对c++没有的符号进行重载
2、以下五个运算符不能进行重载:
.* :: sizeof ? : .
3.运算符重载的参数列表至少要含有一个自定义类型,不能通过运算符重载改变内置类型对象的含义,如: int operator+(int x, int y)
4.重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,无法很好的区分。 C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,方便区分
四.日期类实现
//Date.h
#pragma once
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
class DATE
{
public:DATE(int year = 2000, int mouth = 11, int day = 1){_year = year;_mouth = mouth;_day = day;}//短小多次调用函数使用inline//clase默认inlineint GetMouthDay(int year, int mouth){assert(mouth > 0 && mouth < 13);static int mouthDayArray[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };//多次访问直接定义静态数组if (mouth == 2 && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))//让容易不通过的条件放前面{return 29;}else return mouthDayArray[mouth];}DATE& operator+=(int day);//声明运算符重载DATE& operator+(int day);void Print(){cout << _year << "年" << _mouth << "月" << _day << "日" << endl;}//日期比较bool operator>(DATE x){if (_year > x._year) return true;else if (_year < x._year) return false;if (_mouth > x._mouth) return true;else if (_mouth < x._mouth) return false;if (_day > x._day) return true;else return false;}bool operator==(DATE x){return _year == x._year && _mouth == x._mouth && _day == x._day;}bool operator < (DATE x){return !(*this > x) && !(*this == x);}bool operator!=(DATE& d2){return !(*this == d2);}DATE operator++(int){//后置加加返回原值//注意这个临时变量出了这个函数就销毁了所以不能引用返回DATE tmp(*this);_day++;if (_day > GetMouthDay(_year, _mouth)){_day = 1; _mouth++;}if (_mouth > 12){_year++;_mouth = 1;}return tmp;}//两日期相减int operator-(DATE& d1);
private://成员函数//private成员函数不能直接访问,可以通过成员函数访问int _year;int _mouth;int _day;
};
//text.cpp#include"DATE.h"DATE& DATE::operator+=(int day)//表明所属类
{//由于更改了自身所以重载的是+=//引用返回可以避免拷贝,节省开销//不能返回空值,不然无法解决这种问题(a+=10)+=10//对于这种情况如果传dATE返回的话也无法改变原值,不符合预期。_day += day;while (_day > GetMouthDay(_year, _mouth)){_day -= GetMouthDay(_year, _mouth);++_mouth;if (_mouth == 13){_year++;_mouth = 1;}}return *this;
}
DATE& DATE::operator+(int day)
{//DATE tmp(*this);//拷贝//默认构造函数DATE tmp = *this;///同样也是调用默认构造函数tmp += day;return tmp;
}
int DATE::operator-(DATE& d1)
{int cnt = 0;int flag = 1;DATE max = *this;DATE min = d1;if (max < min){flag = -1;max = d1;min = *this;}while (max != min){cnt++;min++;}return cnt * flag;
}
以上就是关于日期类相关的函数代码了
欧克,时间也不晚了,就到这里吧
全文终
相关文章:
C++:类和对象(从底层编译开始)详解[前篇]
目录 一.inline内联的详细介绍 (1)为什么在调用内联函数时不需要建立栈帧: (2)为什么inline声明和定义分离到两个文件会产生链接错误,链接是什么,为什么没有函数地址: 二.类&…...
Deny by project hooks setting ‘default‘: size of the file
问题描述 gitcode.com提交代码时候发现出现文件大于默认10MB后不能上传 错误显示内容如下: Total 43 (delta 1), reused 0 (delta 0), pack-reused 0 remote: Start Git Hooks Checking [FAILED] remote: Error: Deny by p…...
【Flutter】数据库实体类构造函数加密注意事项
源代码: AccountEntity( {required String account, required String password,}) : account encrypter.encrypt(account,iv: iv).base64, password encrypter.encrypt(password,iv: iv).base64,; 解密代码: static final encrypter Encrypter(AES…...
如何在PHP中实现数据加密与解密:保护敏感信息
如何在PHP中实现数据加密与解密:保护敏感信息 在现代Web开发中,数据安全是一个至关重要的议题。无论是用户的个人信息、支付数据,还是其他敏感信息,都需要在存储和传输过程中进行加密,以防止数据泄露和恶意攻击。PHP作…...
【Pyqt5】水平布局与垂直布局及其交叉展示及实战音乐播放器UI
感受一下Pyqt5的水平布局与垂直布局及其交叉展示 需求: 4个按钮水平排放4个按钮垂直排放水平排放与垂直排放并用实战:音乐播放器UI 水平排放 import sys from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayoutclass MyWindo…...
Java 中 getCanonicalName、getSimpleName、getName、getTypeName 的区别
1. 核心区别总结 方法作用数组类型示例非数组类型示例getName()返回 JVM 内部格式的类全名,适用于反射操作(如 Class.forName())int[] → [IString → java.lang.StringgetTypeName()返回更友好的类型名称,对数组递归处理组件类型…...
uni-app打包h5并部署到nginx,路由模式history
uni-app打包有些坑,当时运行的基础路径填写了./,导致在二级页面刷新之后,页面直接空白。就只能换一个路径了,nginx也要跟着改,下面是具体步骤。 manifest.json配置web 运行路径写/h5/,或者写你们网站的目…...
数据结构与算法(哈希表——两个数组的交集)
原题 349. 两个数组的交集 - 力扣(LeetCode) 给定两个数组 nums1 和 nums2 ,返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1: 输入:nums1 [1,2,2,1], nums2 […...
P1259 黑白棋子的移动【java】【AC代码】
有 2n 个棋子排成一行,开始为位置白子全部在左边,黑子全部在右边,如下图为 n5 的情况: 移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也可以右移到空位上去,但…...
一些docker命令
一、基础命令 查看 Docker 版本 docker --version 或 docker version:显示 Docker 客户端和服务器的版本信息。 查看 Docker 系统信息 docker info:显示 Docker 系统的详细信息,包括镜像、容器数量、存储驱动类型等。 Docker 服务管理 s…...
云服务器新手配置内网穿透服务(frp)
首先你得有一个公网服务器,有了它你就可以借助它,将自己电脑进行配置内网穿透,让自己内网电脑也可以异地轻松访问。网上教程较多,特此记录我自己的配置,避免迷路,我这里只记录我自己云服务小白,…...
linux ptrace 图文详解(二) PTRACE_TRACEME 跟踪程序
目录 一、基础介绍 二、PTRACE_TRACE 实现原理 三、代码实现 四、总结 (代码:linux 6.3.1,架构:arm64) One look is worth a thousand words. —— Tess Flanders 一、基础介绍 GDB(GNU Debugger&…...
Maven安装、idea集成Maven、Maven依赖管理、Maven生命周期
一. Maven介绍 1. Maven是一款用于管理和构建Java项目的工具,是Apache旗下的一个开源项目,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建 2. Maven作用: (1) 依赖管理:方便快捷的管理项目依赖的资…...
【xv6操作系统】系统调用与traps机制解析及实验设计
【xv6操作系统】系统调用与traps机制解析及实验设计 系统调用相关理论系统调用追溯系统调用实验设计Sysinfo🚩系统调用总结(结合trap机制) traptrap机制trap代码流程Backtrace实验alarm实验 系统调用 相关理论 隔离性(isolation)…...
S7-1200 G2移植旧版本S7-1200程序的具体方法示例
S7-1200 G2移植旧版本S7-1200程序的具体方法示例 前期概要: S7-1200 G2必须基于TIA博途V20,之前的程序可通过移植的方式在新硬件上使用。 该移植工具可自动将TIA Portal 项目从 S7-1200 移植到更新的S7-1200 G2。 注意: 该插件支持在同一TIA Portal项目实例内将软件和/或硬…...
海量数据查询加速:Presto、Trino、Apache Arrow
1. 引言 在大数据分析场景下,查询速度往往是影响业务决策效率的关键因素。随着数据量的增长,传统的行存储数据库难以满足低延迟的查询需求,因此,基于列式存储、向量化计算等技术的查询引擎应运而生。本篇文章将深入探讨 Presto、Trino、Apache Arrow 三种主流的查询优化工…...
vscode远程连接服务器并运行项目里的.ipynb文件 如何在 Jupyter Notebook 中切换/使用 conda 虚拟环境?
【最全指南】如何在 Jupyter Notebook 中切换/使用 conda 虚拟环境? 最好用的方法! 使用 nb_conda_kernels 添加所有环境 第二种方法其实也挺不错的。有个缺点是,你新建一个环境,就要重复操作一次。 而这个方法就是一键添加所有…...
二阶优化方法详解
前言 本文隶属于专栏《机器学习数学通关指南》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和参考文献请见《机器学习数学通关指南》 ima 知识库 知识库广场搜索&#…...
C++中通过虚函数实现多态的原理
C中通过虚函数实现多态的原理 我们都知道C是通过虚函数实现多态的,那么其中的原理是什么呢? 在C中,多态性是一种重要的特性,它允许通过基类指针或引用来调用派生类中的函数。多态性主要分为两种:编译时多态ÿ…...
阿里云服务器购买及环境搭建宝塔部署springboot和vue项目
云服务器ECS_云主机_服务器托管_计算-阿里云 一、前言 对于新手或者学生党来说,有时候就想租一个云服务器来玩玩或者练练手,duck不必花那么多钱去租个服务器。这些云服务厂商对学生和新手还是相当友好的。下面将教你如何快速搭建自己的阿里云服务器&…...
【学习笔记】中缀表达式转后缀表达式及计算
C实现中缀表达式转后缀表达式及后缀表达式的计算 在C中,实现中缀表达式转换为后缀表达式(逆波兰表达式)以及后缀表达式的计算是一个非常经典的问题。它不仅涉及到栈(Stack)数据结构的使用,还涉及到对运算符…...
【机器人-基础知识】标定 - 相机标定全解
https://blog.csdn.net/MengYa_Dream/article/details/120233806 1. 相机标定的定义 相机标定是确定相机成像过程中各个参数的过程,它的核心目标是建立从三维世界坐标系到二维图像坐标系的数学映射关系。这一过程包括求解: 内参:描述相机内部光学特性(如焦距、主点位置、像…...
Java 8 + Tomcat 9.0.102 的稳定环境搭建方案,适用于生产环境
一、安装 Java 8 安装 OpenJDK 8 bash sudo apt update sudo apt install openjdk-8-jdk -y 验证安装 bash java -version 应输出类似: openjdk version “1.8.0_412” OpenJDK Runtime Environment (build 1.8.0_412-8u412-ga-1~22.04-b08) OpenJDK 64-Bit Server VM (bui…...
探索 C 语言枚举类型的奇妙世界
目录 一、枚举类型的定义二、枚举类型变量的声明和初始化2.1 先定义枚举类型,再声明变量2.2 定义枚举类型的同时声明变量 三、自定义枚举常量的值四、枚举类型的特点五、注意事项 在C语言中,枚举类型( enum)是一种用户自定义的数…...
buu-ciscn_2019_ne_5-好久不见50
1. 背景分析 目标程序是一个存在漏洞的二进制文件,我们可以通过以下方式利用漏洞获取 shell: 程序中存在 system() 函数,但没有明显的 /bin/sh 字符串。 使用工具(如 ROPgadget)发现程序中有 sh 字符串,可…...
HCIA-ACL实验
前提条件:实现底层互通 转发层面 1、基本ACL ①要求PC3不能访问网段192.168.2.0的网段,PC4和客户端能正常访问服务器 ②AR2配置 acl 2000 rule deny source 192.168.1.1 0 匹配流量 int g 0/0/0 traffic-filter inbound acl 2000 接口调用…...
Java入职篇(2)——开发流程以及专业术语
Java入职篇(2)——开发流程以及专业术语 开发流程 开发术语 测试用例(用例) 测试人员写的测试方案,基本上就是编写的测试过程,以及测试的预取结果 灰度测试 现在小部分范围内使用,然后逐步…...
三相逆变器不控整流场景简要分析
0 三相逆变器拓扑 LCL三相逆变器简要拓扑如下图所示,其他类型如多电平逆变器类似。 1 原理说明 软件在进行直流母线电压Udc的给定取值时,考虑到电压利用率,通常会比电网线电压的峰值稍微高些,比如取线电压峰值的1.0x倍&#x…...
语言识别模型whisper学习笔记
语言识别模型whisper学习笔记 Whisper 是由 OpenAI 于 2022年9月 推出的开源自动语音识别(ASR)系统,旨在实现高精度、多语言的语音转文本及翻译任务。其核心目标是解决传统语音识别模型在噪声环境、口音多样性及多语言场景下的局限性。 一、…...
centos 换阿里云yum
1、备份原有的Yum源配置文件 在更换Yum源之前,先备份CentOS系统中默认的Yum源配置文件,以便在需要时恢复。默认的Yum源配置文件位于 /etc/yum.repos.d/ 目录下,通常包含 CentOS-Base.repo、CentOS-Debuginfo.repo、CentOS-Vault.repo 等文件…...
Jmeter的简单使用
前置工作 确保java8 版本以上jmeter下载路径(选择Binaries):https://jmeter.apache.org/download_jmeter.cgi直接解压,找到bin下面的文件:jmeter.bat(可选)汉化,修改 jmeter.proper…...
CSS元素层叠顺序规则
CSS元素层叠顺序规则 看图说话总结: background/borderz-index(<0)blockfloatinline/inline-blockz-index(0,auto)z-index (>0)...
用Maven创建只有POM文件的项目
使用 mvn 创建一个仅包含 pom.xml 文件的父项目,可以借助 maven-archetype-quickstart 原型,然后移除不必要的文件,或者直接通过命令生成最简的 pom.xml 文件。以下是具体操作步骤: 一、方法一:使用原型创建后清理 1…...
使用Python在Word中生成多种不同类型的图表
目录 工具与环境配置 在 Word 中创建图表的步骤 在Word中创建柱形图 在Word中创建条形图 在Word中创建折线图 在Word中创建饼图 在Word中创建散点图 在Word中创建气泡图 在 Word 文档中插入图表不仅能更直观地呈现数据,还能提升文档的可读性和专业性。常见的…...
Webpack构建流程详解优化前端性能\Dev-Server与Proxy\网络攻击\HMR
简版 核心流程图 根据,Webpack的构建流程分为初始化、编译和输出三个阶段。初始化阶段读取配置、加载插件、实例化Compiler。编译阶段(构建依赖关系)涉及Compiler类的运行,生成Compilation对象,处理模块依赖。输出阶…...
Python 实现的采集诸葛灵签
Python 实现的采集诸葛灵签 项目介绍 这是一个基于 Python 开发的诸葛灵签数据采集和展示项目。通过爬虫技术获取诸葛神签的签文和解签内容,并提供数据存储和查询功能。 项目结构 zhuge/├── zhuge_scraper.py # 爬虫主程序├── zhuge_pages/ # 数据存储目录…...
ESP-IDF ubuntu版本 V5.2
1.MobaXterm 这个软件方面粘贴,文件拷贝 MobaXterm 2.安装之前请确保你安装了Python 和 pip V5.2需要python3.8和pip mkdir esp32 cd esp32 git clone https://gitee.com/EspressifSystems/esp-gitee-tools.git cd esp-gitee-tools ./jihu-mirror.sh set cd .. git clone …...
Opencv之掩码实现图片抠图
掩码实现图片抠图 目录 掩码实现图片抠图1 掩码1.1 概念1.2 创建掩码1.3抠图思路 2 代码测试 1 掩码 1.1 概念 掩码(Mask)是一种用于指定图像处理操作区域的工具。掩码通常是一个与图像尺寸相同的二值图像,其中像素值为0表示不处理ÿ…...
警惕!Ollama大模型工具的安全风险及应对策略
文章目录 **Ollama的安全隐患:不容忽视的风险****未授权访问:门户洞开的风险****数据泄露:敏感信息的外泄****漏洞利用:历史遗留的隐患** **安全加固:守护数据与服务的防线****限制监听范围:内网隔离的保护…...
MySQL -- 表的约束
概念引入:真正的约束表字段的是数据类型,但是数据类型的约束方式比较单一的,所以需要一些额外的一些约束,用于表示数据的合法性,在只有数据类型一种约束的情况下,我们比较难保证数据是百分百合法。通过添加…...
详解数据库范式
范式 1. 第一范式(1NF)2. 第二范式(2NF)3. 第三范式(3NF)4. BC范式(BCNF,Boyce-Codd Normal Form)5. 第四范式(4NF)6. 第五范式(5NF&a…...
Nginx + Keepalived 高可用集群
一、NginxKeepalived 原理 1.1.Nginx 负载均衡机制 Nginx 是一款轻量级且高性能的 Web 服务器和反向代理服务器,在负载均衡方面有着卓越的表现。其具备强大的七层流量管理能力,能够基于 URL、Cookie、HTTP 头信息等对请求进行精准路由。例如࿰…...
循环遍历 Java 集合中元素的方法总结
循环遍历 Java 集合中元素的方法 在 Java 中,有多种方法可以遍历集合中的元素。以下是几种常见的遍历方法及其优缺点: 1. for-each 循环 语法: for (ElementType element : collection) {// 处理 element }适用场景:所有集合类型…...
树莓派上的 TensorFlow Lite:从零开始的摄像头图像识别
**** 1. 引言 随着人工智能(AI)和机器学习(ML)的发展,越来越多的开发者希望在嵌入式设备(如树莓派)上运行 AI 模型,实现目标检测、人脸识别等功能。TensorFlow Lite(TF…...
金融时间序列分析(Yahoo Finance API实战)
这里写目录标题 金融时间序列分析(Yahoo Finance API实战)1. 引言2. 项目背景与意义3. 数据集介绍4. GPU加速在数据处理中的应用5. 交互式GUI设计与加速处理6. 系统整体架构7. 数学公式与指标计算8. 完整代码实现9. 代码自查与BUG排查10. 总结与展望金融时间序列分析(Yahoo …...
Python 正则表达式模块 re
Python 正则表达式模块 re flyfish 一、正则表达式基础 1. 什么是正则表达式? 正则表达式(Regular Expression, RE)是一种用于匹配、查找和替换文本模式的工具,由普通字符(如字母、数字)和特殊字符&…...
Vue生命周期
一、Vue的生命周期及其阶段 Vue生命周期:一个Vue实例从 创建 到 销毁 的整个过程。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。 生命周期的四个阶段:① 创建 ② 挂…...
vue3数据双向绑定解析
Vue 3 的双向绑定原理主要基于 Proxy 和 Reflect,核心源码在 reactivity 模块中。 1. 核心模块:reactivity reactivity 模块负责响应式数据的实现,主要包括以下几个文件: reactive.ts:处理对象和数组的响应式。ref.t…...
Gemini 2.0 全面解析:技术突破、应用场景与竞争格局
摘要 2025年3月,谷歌正式发布Gemini 2.0大模型,凭借其在多模态处理、代码生成和长上下文理解等领域的突破性进展,迅速成为AI领域的焦点。本文将深入剖析Gemini 2.0的技术架构、应用场景及与Grok3、DeepSeek R1、ChatGPT-4.5等竞品的对比&…...
【Linux系统编程】管道
目录 1、什么是管道2、管道的种类3、数据的读写3.1、管道通信3.2、管道的命令实例: 4、无名管道4.1、pipe() 无名管道的创建示例:简单读写示例:加入进程示例:通过 管道(pipe) 实现 父子进程之间的双向通信 …...