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

c++ 类和对象(全)

本文只是把之前上中下三篇文章集合了起来后面跟着补充一点示例代码也只是为了方便大家一下子全部观看。类和对象上一.类的定义1.类定义格式我们可以先看一个类的例子(栈)class Stack { private: int* a; int top; };class 为定义类的关键字Stack为类的名字{ }里的内容是类的主体需要注意的是类定义结束后的 } 后面要跟着分号。类里面的变量称之为类的属性或者是成员变量类里面的函数称为类的方法或成员函数。为了区分成员变量一般习惯上成员变量会有一个特殊的标识一般习惯上在成员变量前面加上_或者是m开头这个只是建议并不是强制要求。class A { int a; int _b; int mc; }; //三种都可以在c 里struct 也可以定义类c 兼容c 语言里的struct 用法同时struct 升级成了类即struct 里面也可以定义函数了但是一般还是用class 来定义类。定义在类里面的成员函数都默认是inline 的不了解inline 的可以看c 到c 过渡里面提到的。2.访问限定符c 里一种实现封装的方式类的三大特性封装继承和多态后面会专门出文章。用类将对象的属性与方法结合在一起让对象更加完善通过访问权限选择性的将其接口提供给外部的用户使用。第一个举的例子里面有private 除此之外还有public和protected。public 修饰的成员在类的外面可以直接被访问private 和protected 修饰的在类外面不能直接访问。而这两个的差距是在后面的继承里面体现的。需要注意虽然被private 和protected 修饰的成员变量不可以在类外直接被使用但是在类里面的成员函数可以直接使用改变。访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现为止如果后面没有访问限定符了那么就会到 } 也就是类结束了再停下来。class 定义成员没有被访问限定符修饰的默认是private 即私有的struct 里面默认的是public。一般成员变量都会被限制为private 或者 protected 需要让别人使用的成员函数会被放在public 里。3.类域类定义了一个新的作用域类的所有成员都在类的作用域里在类外面定义成员时需要用:: 作用域操作符指明成员是属于哪个类域。类域影响的是编译器的查找规则一个定义在类里面的函数在外面想要使用时如果不加 :: 就会被编译器默认为全局里的函数然后就会报错找不见这个函数的定义和声明。使用了:: 之后编译器就会明白这个函数是类里面的函数会自行去类域里面找这个函数并使用。二.实例化1.实例化概念用类类型在物理内存里创建对象的过程结束类实例化出对象。类是对象进行一种抽象描述是一个模型一样的东西限定了类有哪些成员变量这些成员变量只是声明并没有开辟空间存放有效数据用类实例化出对象时才会分配空间。就像c 语言里面的创建变量时的那样创建变量就像实例化对象一样在内存里开辟空间存放你需要的数据。一个类可以实例化多个对象实例化出的对象占用的是实际的物理空间物理上的“内存”存储类成员变量。这里其实和struct 很像或者可以想象成创建的类就是一个新的我们自己定义的类型就像那些整数类型浮点数类型一样我们可以用这个类型创建不同的变量区别在于我们自己定义的类型可以使用类里面自己定义的函数即我们定义的类的每个变量都是可以使用我们写的成员函数的这些成员函数就是用来“服务”类变量的。2.对象大小不需要特殊的计算方法函数的大小函数会被放在一个公共的区域里而计算成员的大小当对类创建对象时不同的对象引用同一个函数会去那个公共地址函数指针是一个地址调用函数被编译成汇编指令[call地址]其实编译器在编译链接时就要找到函数的地址不是在运行时找只有动态多态是在运行时找就需要存储函数地址。内存对齐规则内存对齐上 struct 与 class 相同。第一个成员在与结构体偏移量为0的地址处。其他成员变量要对齐到某个数字对齐数的整数倍的地址处。这里的对齐数在之前的文章里结构体与位段详解有提到。是编译器默认对齐数与成员大小的较小值不同的软件默认对齐数会不同。需要注意结构体的总大小必须是所有对齐数里面最大的那一个的整数倍就算会有空间浪费也要取整数倍。如果是嵌套类结构体的情况嵌套的结构体对齐到自己最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体的对齐数的整数倍。特别对于只有函数的类或者什么都没有的类类的变量大小为1因为如果 1 个字节都没有无法证明对象存在所以会给 1 个字节用于占位标识对象存在。下面是一个计算类的大小的例子class PersonBirthday { private: char name[15]; int year; int month; int day; };这是一个人的生日的类下面是计算该类的对象的大小3.this指针this 指针一般存储在栈里面有些寄存器优化会存在寄存器里面。在编译器编译过程中类的成员函数默认都会在形参的第一个位置增加一个当前类型的指针就是 this 指针也就是说函数会用默认传过去的 this 指针来确定并访问对应的类变量。当我们创建类变量后调用该类变量的成员函数时可能会有人疑惑一个“ . ”是如何让那个类变量确定是 a 这个类变量不是 b 这个类变量类的成员函数访问成员变量是通过 this 指针访问的。c 规定不能在实参和形参的位置显示的写 this 指针编译时编译器会自行添加默认的 this 指针但是在函数体内部可以直接使用 this 指针。4.c和c语言对比面向对象具有三大特性封装多态和继承。下面初步了解一下封装c 中数据和函数都放在了类里面通过访问限定符进行了限制不能再随意通过对象直接修改数据这是c的封装的一种体现这里的封装的本质是一种更严格的规范的管理避免出现乱访问的修改的问题当然封装不仅仅是这样的。c 中有一些相对方便的语法比如缺省参数会方便很多成员函数每次不需要传地址对象因为this 指针隐含的传递方便了很多使用类型不再需要typedef用类名就很方便。类和对象中类的默认成员函数默认成员函数是用户没有自己实现编译器会自动实现的成员函数这些函数被称为默认成员函数。默认成员函数有以下 6 种前四种是比较重要的。c11之后还新增了两种默认成员函数移动构造和移动赋值。下面介绍这 6 种函数1.构造函数构造函数可以理解为初始化函数是特殊化的成员函数需要注意的是构造函数虽然叫做构造但并不是开辟空间创建变量(我们经常使用的局部对象是栈帧创建时空间就开好了)它仅仅是对已经存在的变量进行初始化。构造函数会在对象创建时自动调用。在了解构造函数之前需要确定什么是内置类型什么是自定义类型内置类型就是系统已经定义好的变量的类型像intchardoublefloat等类型就是内置类型而我们自己定义的类结构体等自己定义的类型。构造函数有以下特点1.函数名与类名相同构造函数的函数名就是类名。2.没有返回值构造函数不用写 void int double 等表明返回类型那一块直接空下。3.对象实例化时系统会自动调用对应的构造函数。4.构造函数可以重载5.如果类中没有显示定义构造函数则c 编译器会自动生成一个无参的默认函数一旦用户显式定义编译器将不再生成即码农觉得编译器默认的构造函数不合心意可以自己写构造函数不写也可以有部分特殊情况必须写。6.无参构造函数全缺省构造函数编译器默认生成的构造函数都叫做默认构造函数但是这三个只能存在一个不能同时存在无参构造函数和全缺省构造函数同时存在会导致混乱因为两者都是没有参数的函数编译器不能确定你要调用哪个。无参构造函数和全缺省构造函数虽然构成函数重载但是调用时会存在歧义可以认为不传递参数的构造函数就称为默认构造函数。7.我们不写编译器默认生成的构造函数对内置类型成员变量并没有要求也就是说是否初始化这个要看编译器对于自定义的成员变量编译器会调用该变量的默认构造函数如果没有默认构造函数就会报错。这里需要注意的是不是所有的自定义类型都需要我们自己去写构造函数如果你定义的自定义类型里面只有内置类型那么也是不用写默认构造函数的可以依靠编译器自行处理但是有其他的变量比如动态开辟内存的变量等就需要我们自己写。我们初始化这个自定义变量需要初始化列表这部分内容和一部分构造函数的补充会放在后面的一篇文章 类和对象下 里面说明。下面是一个简单的我们自己手写默认构造函数的例子class PersonBirthday { private: char name[15]; int year; int month; int day; public: PersonBirthday() { std::strcpy(name, ); year0; month0; day0; } //两种手写的默认构造函数如果实际中写的话只选其中一种就行这里只是为了列出来 PersonBirthday(const char* n , int y 0, int m 0, int d 0) { std::strcpy(name, n); year y; month m; day d; } };2.析构函数析构函数与构造函数功能相反析构函数不是对对象本身的销毁比如局部对象是存在栈帧的函数结束后栈帧就会销毁就会自动释放不需要我们管c规定对象在销毁时会自动调用析构函数完成对象中资源的清理释放。下面是析构函数的特点1.析构函数的函数名是类名前加 ~ 。2.与构造函数相同析构函数没有返回值同时也没有参数。3.一个类只能有一个析构函数若为显式定义系统会自动生成默认的析构函数。4.对象生命周期结束时系统会自动调用析构函数不需要我们手动调用。5.跟构造函数类似我们不写析构函数时编译器对内置类型成员不做处理自定义类型成员会调用它的析构函数。6.自定义类型成员无论我们写不写析构函数它都会自动调用。7.如果类中的对象没有申请资源时析构函数可以不写直接使用编译器生成的默认析构函数但是如果有申请资源就必须写析构函数否则会造成资源泄漏。也就是说大部分的析构函数其实都不需要我们自己写仅仅靠编译器生成的就可以只有申请资源需要我们特殊关注之外。8.对于多个对象的析构顺序c规定先定义的后析构后定义的先析构。类的析构函数调用一般按照构造函数调用的相反顺序进行调用但是要注意static对象的存在 因为static改变了对象的生存作用域需要等待程序结束时才会析构释放对象。全局对象先于局部对象进行构造局部对象按照出现的顺序进行构造无论是否为static。3.拷贝构造函数拷贝构造函数可以理解为把一个已有的数据类拷贝一份给新的变量如果一个构造函数的第一个参数是自身类型的引用且任何额外的参数都有默认值则此构造函数也叫拷贝构造函数即拷贝构造函数是一种特殊的构造函数。下面是拷贝构造函数的特点1.拷贝构造函数是构造函数的一个重载。2.拷贝构造函数的第一个参数必须是类类型对象的引用一般加上const避免产生对原来数值的改变使用传值方式编译器直接报错因为语法逻辑上会引发无穷递归调用拷贝构造函数也可以多个参数但是第一个参数必须是类类型对象的引用后面的参数必须有缺省值。c 规定函数里参数的传值传参传类对象的时候要调用拷贝构造可以理解为开辟一个空间存放要传参对象的数据然后用这个新开辟的空间作为临时变量去执行函数体c 相当于把这一部分直接调用拷贝构造函数实现。3.c 规定自定义类型对象进行拷贝行为必须调用拷贝构造所以这里自定义类型传值传参和传值返回都会调用拷贝构造完成大部分人会觉得这种行为有些浪费空间有些麻烦因此在后面会有对编译器的优化。4.若未显式定义拷贝构造编译器会自动生成拷贝构造函数自动生成的拷贝构造函数对内置类型成员变量会完成值拷贝浅拷贝一个一个字节的拷贝对自定义类型的成员变量会调用他的拷贝构造。5.对于类成员变量全是内置类型且没有指向什么资源编译器自动生成的拷贝构造函数就已经完全够用了不需要我们显式实现。但是像Stack栈这样的类虽然也有内置类型但是对于指向资源编译的变量编译器自动生成的拷贝构造完成的值拷贝浅拷贝就不符合我们的需求就需要自己写拷贝构造函数。6.传值返回会产生一个临时对象调用拷贝构造传值引用返回的是返回对象的别名引用没有产生拷贝但是如果返回对象是一个当前函数局部域的局部对象函数结束就销毁了那么使用引用返回是有问题的。这时的引用相当于一个野引用类似一个野指针一样传引用返回可以减少拷贝但是一定要确保返回对象在当前函数结束后还在才能引用返回。4.赋值运算符重载1.运算符重载当运算符被用于类类型的对象时c 允许我们通过运算符重载的形式来指定新的含义。举个例子创建一个日期的类类成员变量是年月日然后我们可以重载加号使得类对象加一个数字返回的是一个新的日期对象。c 规定类类型的对象使用运算符的时候必须转换成调用对应的运算符重载如果你没有写这个运算符重载那么就会报错。运算符重载可以看成有特殊名字的函数他的名字是operator 要重载的运算符按之前的例子来说就是operator这里加号就是指我们要重载的就是加号运算符和其他函数一样运算符重载也具有返回类型和参数列表和函数体。还是按加号为例日期加数字返回一个新的日期所以这个函数的返回值是日期类。重载运算符函数的参数个数和该运算符作用的运算对象数量一样多一元运算符有一个参数二元运算符有两个参数二元运算符的左侧运算对象传给第一个参数右侧运算对象传给第二个参数。还是按加号为例加号是有左右两个参数的所以括号里的参数列表就要写两个一个写日期类一个写整数数字顺序就是按从左到右即可。如果一个重载运算符函数是成员函数则它的第一个运算对象默认传给隐式的this 指针也就是说这个时候传参个数比运算对象个数少一个。还是按加号为例我们把加号重载写在类里面的时候就可以省略第一个日期类对象的参数只写第二个数字的参数。运算符重载之后并不会改变它的优先级依旧是按照重载之前的那个符号的优先级。不能凭空创建新的符号只能重载已经存在的运算符。重载运算符至少需要一个类类型的参数不能全部都是内置类型比如int operator (int x, int y)有五个运算符不能进行重载..*sizeof? :: :。重载 运算符的时候需要区分前置和后置c 规定后置增加一个int 形参用于区分前置: int operator () 后置: int operator ( int )。重载 和 时要重载到全局函数因为类函数默认第一个参数是 this 指针是符号左侧的那个参数但是一般这两个用到的是 cin 和 cout 并且都是在左边因此需要写成全局函数第二个参数就可以写类类型对象。2.赋值运算符重载赋值运算符重载也是一个默认函数用于完成已经存在的两个对象直接的拷贝赋值这里需要注意和拷贝构造的区别。拷贝构造是用于创建对象时的初始化我们可以新创建一个对象并将一个已经存在的类对象赋值给这个新创建的对象这个时候就是拷贝构造。而赋值运算符重载则是两个已经存在的类对象A B把 A 的值赋值给 B 就是 B A 。下面是赋值运算符重载的特点:赋值运算符重载在没有显式实现的时候编译器会自动生成一个默认的赋值运算符重载默认的赋值运算符重载跟默认的拷贝构造函数类似对内置类型变量会完成值拷贝也就是浅拷贝(用一个字节一个字节的拷贝) 对自定义类型成员变量会调用其赋值重载函数。需要注意的是没有指向资源的变量默认的已经够用但是如果有变量是我们申请了资源的(动态开辟内存的)就需要自己写。赋值运算符重载是一个运算符重载规定必须重载为成员函数。赋值运算符重载的参数建议写成const 当前类型引用否则传值传参会有临时拷贝造成空间浪费。赋值运算符重载有返回值并且建议写成当前类类型引用写成引用可以提高效率写返回值则是为了连续赋值。5.取地址运算符重载取地址运算符重载函数包括了两种一个是普通默认取地址运算符重载另一个是 const 取地址成员函数。1.const成员函数将 const 修饰的成员函数称之为 const 成员函数修饰成员函数放到成员函数参数列表的后面。const 实际修饰该成员函数隐含的this 指针表明在该成员函数中不能对类的任何成员变量进行修改。2.取地址运算符重载取地址运算符重载分为普通和const 取地址重载一般这两个函数编译器自动生成的就可以够我们使用不需要去显式实现。类和对象下一.构造函数补充在之前我们实现构造函数时初始化成员变量主要用在构造函数体内赋值而构造函数初始化还有另一种方式就是使用初始化列表初始化列表的使用方式是以一个冒号开头接着一个以逗号分隔的数据成员列表每个成员列表后面跟一个放在括号里的初始化值或者表达式。class Stack { private: int* arr; int top; int capacity; public: Stack() :arr(new int[4]) ,top(0) ,capacity(4) { //可能进行的操作 } }这里开辟动态内存用的是 new 这点会在后面内存管理的地方讲现在可以简单的理解为开辟动态内存空间并且初始化了一下。每个成员变量在初始化列表中只出现一次语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。引用成员变量 const 成员变量没有默认构造函数的类类型变量都必须放在初始化列表里面初始化否则会编译报错。内置类型可以自己选择是在初始化列表还是在函数里面初始化。c11支持在成员变量声明的位置给缺省值这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。一般都尽量用初始化列表初始化因为那些你不在初始化列表初始化的成员也会走初始化列表如果你给了缺省值那么初始化列表就会用这个初始化如果没有给则是否初始化就会取决于编译器类似于默认构造函数那里的。初始化列表中按照成员变量在类中声明private顺序进行初始化跟成员在初始化列表出现的先后顺序无关建议两者的顺序保持一致。二.static成员用 static 修饰的成员变量称为静态成员变量也是属于类的成员静态成员变量必须在类的外面初始化。静态成员变量是被所有的该类对象所共享的不属于单独的类对象存放在静态区。并且该静态成员变量是唯一的不会随着类变量的创建或销毁增加或减少而变动只会随着我们专门访问和改变时才会改变。用 static 修饰的成员函数称之为静态成员函数静态成员函数没有 this 指针。静态成员函数可以访问其他的静态成员变量但是不能访问非静态成员变量因为静态成员函数不像其他成员函数的参数中有默认的 this 指针。而非静态的成员函数就可以访问任意的静态成员变量和静态成员函数。访问静态成员变量或者静态成员函数的时候就是像正常访问成员函数一样用类变量名.静态成员或者类变量名.静态成员函数来访问。亦或者是用类名:: 的方式访问。需要注意静态成员变量不能在声明位置给缺省值初始化(const static 可以给缺省值因为 const 修饰表明该变量无法改变)缺省值初始化是我们正常创建类变量初始化的一种是按照初始化列表的步骤进行的但是静态成员变量是公共的不属于单独对象的不会参与对象的初始化列表过程。局部静态成员变量是在代码运行到那里的时候才会创建初始化静态变量的生命周期是全局的可以理解生命周期类似于全局变量在程序结束前才会销毁。三.友元我们之前说到的类和对象的成员变量一般是在private限定符下面的用于防止类以外的函数使用或者修改成员变量这也是封装的一种可以保证数据的安全。而我们想要让非类成员函数也可以访问类成员变量时就需要友元了友元分为了友元函数和友元类在函数声明或者类声明的前面加 friend 并且把友元声明放在你想要访问的类里面就可以然后这个友元类或者友元函数就可以访问想访问类里面的 private 和 protected 修饰的成员变量了。下面是示例class people { private: char* name; int age; char* sex; friend void printpeo( people a ); friend class student; } void printpeo( people a ) { cout a.name a.age a.sex endl; } class student { private: char* school; char* studentnum; }这里我并没有写引用头文件和类里面的函数什么的仅仅是为了展示一下友元的写法。下面我用友元函数来泛指友元函数和友元类。友元函数可以在类里面的任何限符下面声明不会受到限定符的影响。同一个函数可以是多个类的友元函数。友元类中的成员函数都是那个类的友元函数都可以访问那个类的私有和保护成员。友元关系不能传递A是B的友元B是C的友元A不是C的友元。并且友元关系单向不能相互交换A是B的友元A可以访问B的但是B不能访问A的。虽然友元让人觉得便利但是友元实际上会破坏封装不建议多用。四.内部类如果一个类A定义在另一个类B的内部那么A就是B的内部类A可以访问B的私有和保护的成员变量(这里就像是友元类一样)。需要注意A是一个独立的类受外部类类域限制和访问限定符限制B的成员变量并不包括A这个类。内部类默认是外部类的友元类。内部类也是一种封装还是A类是B类的内部类如果A是放在 private 或者protected 的限定符下那么A就是B的专属内部类B类外面就不能使用A类的成员变量了(B类外面的友元也不可以)。一般B类和A类是紧密相关的就拿生物里的界门纲目科属种来举例子B是目A是科A有着B的特点并且A又独自发展出独属于A的特点。五.匿名对象用类型(实参)直接定义出来的对象就叫做匿名对象我们之前的类型 对象名(实参)定义出来的就叫有名对象。匿名对象主要是为了方便生命周期只有创建出来对象的当前一行就是为了即用即弃。下面是定义示例六.对象拷贝时的编译器优化在正常用等于号拷贝变量时过程其实是比较复杂的。还是例子A和BA和B都是是已经创建好初始化完的类对象类的名字叫做 student 然后我们想要B变量和A一样的数据就要用等于号。那么就是B A(这里一般类都需要重载等于号)这里编译器会先创建一个临时变量(视编译器不一定)存储A的数据然后再把临时变量的数据传给B里面。这里就多了一个临时变量的消耗。或者是传值传参的时候编译器会先对参数创建一个临时变量然后用这个临时变量来运行函数体(因此我们传参一般采用引用可以直接改变参数数据的同时也不会有临时变量的消耗)而返回值返回的时候也是如此 int a func( 1 )func 的返回值会先创建一个临时变量然后再赋给 a 这些临时变量如果数据小点还好说一旦数据大或者多次调用函数那么浪费的空间是非常恐怖的因此编译器会进行优化。现代编译器为了尽可能提高效率在不影响正确性的情况下会尽可能减少一些传参和返回值的过程中可以省略的拷贝。对于如何优化c 并没有严格规定因此不同的编译器优化的程度方法会有不同。大部分的是合并优化减少临时变量或者其他不必要的变量的创建减少空间使用提高效率。代码示例后面这里作者添加了点模拟栈类的代码做个示例//这里是Stack.h文件里的 #pragma once //类栈 #includeiostream #includeassert.h using namespace std; class Stack { private: char* _arr; size_t _top; //依旧指向栈顶元素的下一个位置(一开始没有元素指向0) size_t _capacity; public: //迭代器前提 typedef char* iterator; typedef const char* const_iterator; iterator begin() { return _arr; } iterator end() { return _arr _top; } //默认构造 Stack(char* arr nullptr, size_t top 0, size_t capacity0) :_arr(new char[capacity ]) ,_top(top) ,_capacity(capacity) { if (arr ! nullptr) { for (int i 0;i top;i) { _arr[i] arr[i]; } } } //拷贝构造 Stack(Stack s1) :_arr(new char[s1._capacity ]) , _top(s1._top) , _capacity(s1._capacity) { int num 0; for (auto ch : s1) { _arr[num] ch; } } //析构函数 ~Stack() { delete[] _arr; _top 0; _capacity 0; } //判断空间是否足够并按需扩容(按照1.5倍扩) void JudgeTop(); //插入数据 void Push_Back(char a); //删除数据 void Pop_Back(); //返回栈顶 char RetTop(); //栈的遍历 void PrintStack(); //重载输入输出 friend istream operator (istream in, Stack s); friend ostream operator (ostream out, Stack s); //重载赋值运算符返回值用于确保连续赋值的可能性 Stack operator (const Stack s); }; istream operator (istream in, Stack s); ostream operator (ostream out, Stack s);//这里是Stack.cpp文件里的 #define _CRT_SECURE_NO_WARNINGS 1 #includeStack.h //判断空间是否足够并按需扩容(按照1.5倍扩) void Stack::JudgeTop() { if (_top _capacity _top!0) { char* narr new char[_capacity _capacity / 2]; int num 0; for (auto ch : (*this)) { narr[num] ch; } _capacity _capacity / 2; delete[] _arr; _arr narr; } else if (_top 0) { char* narr new char[4]; delete[] _arr; _arr narr; _capacity 4; } } //插入数据 void Stack::Push_Back(char a) { JudgeTop(); _arr[_top] a; } //删除数据 void Stack::Pop_Back() { assert(_top ! 0); _top--; } //返回栈顶 char Stack::RetTop() { assert(_top ! 0); return _arr[_top - 1]; } //栈的遍历 void Stack::PrintStack() { int num 0; for (auto ch : (*this)) { cout ch; } cout endl; } //重载输入输出 istream operator (istream in, Stack s) { char* arr new char[256]; //有输入字符串限制长度(正常来说一般不会太长)可以后面在学了string 之后改进 in arr; int top strlen(arr); Stack ns(arr, top, top); s ns; delete[] arr; return in; } ostream operator (ostream out, Stack s) { s.PrintStack(); return out; } //重载赋值 Stack Stack::operator (const Stack s) { if (this ! s) { delete[] this-_arr; this-_arr new char[s._capacity]; for (int i 0;i s._top;i) { _arr[i] s._arr[i]; } this-_top s._top; this-_capacity s._capacity; } return *this; }作者这里仅仅是做了一个简单的大概的模拟没有模拟太多方法可能代码有误希望及时指出。

相关文章:

c++ 类和对象(全)

本文只是把之前上中下三篇文章集合了起来,后面跟着补充一点示例代码,也只是为了方便大家一下子全部观看。 类和对象(上) 一.类的定义 1.类定义格式 我们可以先看一个类的例子(栈): class Stack { private:int* a;in…...

优化Docker镜像下载速度:国内镜像源配置指南

1. 为什么需要配置国内Docker镜像源 第一次用Docker拉取镜像时,看着进度条像蜗牛一样缓慢移动,我盯着屏幕足足等了半小时。后来才发现,默认的Docker Hub服务器在国外,国内直接访问速度感人。这就像你在北京点外卖,却非…...

学生专属福利:如何免费获取JetBrains和Navicat全家桶

1. 学生专属福利:为什么你需要它们? 还在为开发工具的高昂费用发愁吗?作为一个过来人,我太懂学生时代那种“想学技术,却被工具卡住”的窘迫了。一套正版的JetBrains全家桶(比如IntelliJ IDEA、PyCharm、Web…...

Markdown写作技巧:LaTeX公式+代码块高亮全攻略

Markdown写作技巧:LaTeX公式代码块高亮全攻略 在技术文档和学术研究的写作中,Markdown因其简洁性和强大功能已成为首选工具。但对于需要表达复杂数学公式或展示多语言代码的专业作者来说,如何充分利用Markdown的高级功能仍是一个挑战。本文将…...

基于PEX88096的PCIe 4.0八盘M.2扩展卡设计

1. 项目概述PCIe 4.0 M.2扩展卡长期面临市场定价畸高问题,主流商用产品普遍标价数千元,严重制约了高性能存储系统在DIY、边缘计算及小型服务器场景中的普及应用。本项目以PEX88048 PCIe 4.0交换芯片为核心,构建一款支持8路独立M.2 NVMe插槽的…...

Python+Selenium实现抖音博主批量监控:300+账号实时更新通知(附完整代码)

PythonSelenium构建高可用抖音博主监控系统:从零到一的实战架构与性能调优 最近在技术社群里,经常看到有朋友在讨论如何批量追踪抖音博主的更新动态。无论是做内容分析、竞品研究,还是个人兴趣追踪,手动刷新几百个主页显然不现实。…...

告别数据孤岛:基于WebDAV的Zotero与InfiniCLOUD跨平台同步实战

1. 为什么需要跨平台文献同步? 作为一名常年泡在实验室的研究生,我经历过无数次这样的崩溃瞬间:在实验室电脑上整理好的文献库,回到宿舍打开笔记本发现参考文献全乱了;出差路上想用平板查篇论文,却发现最新…...

【解刊】IEEE Trans系列新宠:中科院1区TOP期刊,国人作者占比近八成领跑全球!

1. IEEE Transactions on Cybernetics:控制论领域的黄金期刊 最近在学术圈里,IEEE Transactions on Cybernetics(IEEE控制论汇刊)成了热门话题。这本期刊不仅稳居中科院1区TOP,更让人惊讶的是,中国学者在这…...

社区分享 | 从零开始学习 TinyML(三)

1. TinyML模型部署后的性能优化挑战 当你第一次把训练好的TinyML模型部署到Arduino或Cortex-M系列MCU上时,可能会遇到一些令人头疼的问题。我清楚地记得自己早期的一个项目,模型在PC上测试时运行良好,但移植到开发板上后,推理速度…...

基于Mirage Flow的个性化学习推荐系统构建

基于Mirage Flow的个性化学习推荐系统构建 1. 引言 你有没有过这样的经历?同一个班级,同样的老师,同样的教材,但有的同学学得飞快,有的同学却总是卡在某个知识点上,怎么都绕不过去。传统的在线教育平台&a…...

FPGA选型指南:如何为LED大屏控制器挑选性价比最高的芯片(附Xilinx/Lattice对比)

FPGA选型指南:如何为LED大屏控制器挑选性价比最高的芯片(附Xilinx/Lattice对比) 当一块巨大的户外广告屏在夜幕下亮起,播放着流畅震撼的视频时,很少有人会想到,驱动这背后数百万乃至上千万像素点精准发光的…...

Win11组播通信故障排查:为什么关闭防火墙后还是收不到组播数据?

Win11组播通信深度排障:当防火墙不再是“罪魁祸首” 最近在调试一个分布式数据采集系统时,遇到了一个颇为典型的网络问题:几台运行Windows 11的工控机之间,组播(Multicast)通信死活不通。按照最常规的思路&…...

避开Doze模式坑!Android 6.0+保活终极方案:JobScheduler与推送SDK混合使用指南

深入解析Android 6.0应用保活:融合JobScheduler与厂商推送的实战策略 在Android生态中,应用保活一直是个让开发者又爱又恨的话题。爱的是,它能确保即时通讯、后台同步、位置追踪等核心功能稳定运行;恨的是,从Android …...

Fish Speech 1.5镜像交付物清单:含启动脚本、日志、配置、证书模板

Fish Speech 1.5镜像交付物清单:含启动脚本、日志、配置、证书模板 1. 镜像概述与技术规格 Fish Speech 1.5是由Fish Audio开源的新一代文本转语音模型,基于LLaMA架构与VQGAN声码器,支持零样本语音合成。用户只需提供10-30秒的参考音频&…...

Z-Image Turbo性能评测:不同硬件下的生成速度对比

Z-Image Turbo性能评测:不同硬件下的生成速度对比 1. 评测背景与目的 Z-Image Turbo作为一款基于Turbo架构的高性能AI绘图工具,以其极速生成能力在本地AI绘画领域备受关注。本次评测旨在通过实际测试,展示不同硬件配置下的生成速度表现&…...

PP-DocLayoutV3内网穿透部署方案

PP-DocLayoutV3内网穿透部署方案 1. 引言 在企业内部网络环境中,如何安全高效地部署和访问AI服务是一个常见的技术挑战。PP-DocLayoutV3作为新一代文档布局分析引擎,能够精准识别表格、公式、文本等文档元素,但传统的部署方式往往受限于内网…...

嘉立创EDA专业版多账号管理技巧:如何避免激活文件冲突

嘉立创EDA专业版多账号管理实战:告别激活文件冲突,实现高效协同 在电子设计领域,尤其是团队协作或自由职业者同时处理多个客户项目时,一个常见且棘手的问题是如何在同一台工作电脑上优雅地管理多个嘉立创EDA专业版账号。你可能遇到…...

游戏原画师福音:Kook Zimage真实幻想Turbo保姆级入门教程

游戏原画师福音:Kook Zimage真实幻想Turbo保姆级入门教程 1. 引言:从零开始,十分钟拥有你的专属幻想引擎 如果你是一位游戏原画师,或者对创作奇幻、仙侠风格的角色充满热情,那么今天这篇文章就是为你准备的。我们不再…...

Chandra OCR快速部署:基于vLLM的开箱即用方案,5分钟搞定环境

Chandra OCR快速部署:基于vLLM的开箱即用方案,5分钟搞定环境 1. 为什么选择Chandra OCR? 如果你正在寻找一个能真正“理解”文档的OCR工具,而不是简单地把图片上的字抠出来,那么Chandra很可能就是你需要的答案。 想…...

AIGlasses OS Pro智能视觉系统在操作系统课程教学中的应用:资源监控与可视化

AIGlasses OS Pro智能视觉系统在操作系统课程教学中的应用:资源监控与可视化 操作系统这门课,很多学生都觉得抽象又枯燥。CPU调度、内存管理、进程通信……这些概念听起来就让人头大,更别说理解它们在实际系统中是怎么“动”起来的了。传统的…...

基于STC Ai8051U的太阳能户外便携灯开源硬件设计全解析

基于STC Ai8051U的太阳能户外便携灯开源硬件设计全解析 大家好,我是老陈,一个喜欢捣鼓硬件的嵌入式工程师。最近用STC最新的Ai8051U单片机做了一个太阳能户外灯,从电路设计到程序调试,踩了不少坑,也积累了不少经验。今…...

零基础玩转YOLOFuse:RGB+红外双流融合检测保姆级教程

零基础玩转YOLOFuse:RGB红外双流融合检测保姆级教程 你是不是遇到过这样的问题:在夜晚、雾天或者光线不好的时候,摄像头拍出来的画面一片模糊,根本看不清有没有人或者车?传统的目标检测模型这时候就“瞎”了&#xff…...

Qwen-Image-Edit-2511进阶指南:利用LoRA模型,解锁更多修图风格

Qwen-Image-Edit-2511进阶指南:利用LoRA模型,解锁更多修图风格 你是不是已经用Qwen-Image-Edit-2511完成了基础的换装、换背景,觉得它很厉害,但又隐隐感觉少了点什么?比如,你想生成一套赛博朋克风格的服装…...

大学想进ai行业的看过来

大学想进ai行业的看过来 大一迷茫、大二焦虑、大三慌神——如果你是计算机、大数据、人工智能相关专业,或者对AI感兴趣,想毕业后顺利进入AI行业,这篇文章一定要收藏好! 作为过来人,我太懂大学生想进AI行业的困惑&…...

现代机器人:力学、规划与控制3-刚体运动

3 刚体运动 3.1 刚体运动的介绍 I Introduction to Rigid-Body Motions 在第三章中,我们将学习构型、速度和力的表示方法,这些内容将贯穿本书的其余部分。正如上一章所讨论的,我们将使用关于构型空间(C-space)的隐式表示。换句话说,我们的构型表示不会使用最小坐标集,速…...

第 4 周:Boost 与 Buck-Boost 的陷阱

V2设置V3设置day2...

GPU 算力翻倍,AI 反而变慢了?FlashAttention-4 给出了惊人的答案

如果你最近在关注大模型训练,可能会发现一个很反常的现象。GPU 一代比一代强。算力翻倍、Tensor Core 更快、AI 芯片越来越猛。但很多研究人员却发现: 模型训练速度并没有等比例提升。 问题出在哪里?答案其实藏在一个很多人忽略的地方&…...

基于智慧校园的大学生综合能力测评系统毕业论文+PPT(附源代码+演示视频)

文章目录 一、项目简介1.1 运行视频1.2 🚀 项目技术栈1.3 ✅ 环境要求说明 前台运行截图后台运行截图项目部署源码下载 一、项目简介 项目基于SpringBoot框架,前后端分离架构,后端为SpringBoot前端Vue。本研究旨在设计并实现一个基于智慧校园…...

金融问答合规最后窗口期:Dify 0.12+版本强制启用的3项新审计日志字段,错过将无法通过Q3银保监现场检查

第一章:金融问答合规最后窗口期的监管背景与紧迫性近年来,金融行业智能问答系统爆发式增长,但其输出内容的准确性、可追溯性与风险提示完整性持续引发监管关注。2023年10月《金融领域生成式人工智能应用监管指引(试行)…...

Qwen-Image-Lightning与SpringBoot集成指南:企业级图像生成API开发

Qwen-Image-Lightning与SpringBoot集成指南:企业级图像生成API开发 1. 引言 在当今内容为王的时代,企业对于高质量图像生成的需求日益增长。无论是电商平台的商品海报、营销活动的宣传素材,还是内部文档的配图,都需要快速、高效…...