【c++】cpp类和对象

(1)类的封装

封装的多层含义

  • 把属性和⽅法进⾏封装
  • 对属性和⽅法进⾏访问控制
  • 类的内部和类的外部
  • 类的访问控制关键字
    • public:  修饰的成员变量和函数,可以在类的内部和类的外部访问
    • private:  修饰的成员变量和函数,只能在类的内部被访问,不能在类的外部访问
    • protected:  修饰的成员变量和函数,只能在类的内部被访问,不能在类的外部访问,⽤ 在继承⾥⾯

案例:设计⽴⽅体类(cube),求出⽴⽅体的⾯积和体积。求两个⽴⽅体,是否相等(全局函数和成员函数都要实现)。

#include <iostream>class Cube
{
public:void setA(int a){m_a = a;}void setB(int b){m_b = b;}void setC(int c){m_c = c;}void setABC(int a = 0, int b = 0, int c = 0){m_a = a;m_b = b;m_c = c;}int getA(){return m_a;}int getB(){return m_b;}int getC(){return m_c;}
public:int getV(){m_v = m_a * m_b * m_c;return m_v;}int getS(){m_s = 2 * (m_a * m_b + m_a * m_c + m_b * m_c);return m_s;}int judgeCube(Cube &v1, Cube &v2) //不建议这样写{if ((v1.getA() == v2.getA()) && (v1.getB() == v2.getB()) && (v1.getC() == v2.getC()))return 1;return 0;}int judgeCube(Cube &v2) //成员函数 函数重载{if ((m_a == v2.getA()) && (m_b == v2.getB()) && (m_c == v2.getC()))return 1;return 0;}
private:int m_a;int m_b;int m_c;int m_v;int m_s;
};// 全局函数 PK 成员函数
// 1相等 0不相等
int judgeCube(Cube &v1, Cube &v2)
{if ((v1.getA() == v2.getA()) && (v1.getB() == v2.getB()) && (v1.getC() == v2.getC()))return 1;return 0;
}int main()
{Cube v1, v2;v1.setABC(1, 2, 3);std::cout << v1.getS() << std::endl;std::cout << v1.getV() << std::endl;// 用成员函数判断两个立方体是否相等v2.setABC(1, 2, 4);if (v1.judgeCube(v1, v2) == 1)std::cout << "v1 = v2" << std::endl;elsestd::cout << "v1 != v2" << std::endl;// 用成员函数判断两个立方体是否相等v1.setABC(1, 2, 4);if (v1.judgeCube(v2) == 1)std::cout << "v1 = v2" << std::endl;elsestd::cout << "v1 != v2" << std::endl;// 用全局函数判断两个立方体是否相等if (judgeCube(v1, v2) == 1)std::cout << "v1 = v2" << std::endl;elsestd::cout << "v1 != v2" << std::endl;return 0;
}

(2)类的声明和实现分开

设计.h和.cpp,一个声明,一个实现。为了避免同⼀个头⽂件被include多次带来重复编译,头⽂件要么用#ifndef 宏名  #define 宏名  #endif编写头文件,要么用#pragma once。#ifndef由语⾔⽀持移植性更好,推荐使用。

案例:带有数组成员的类

myarrray.h

#ifndef _MYARRAY_H_
#define _MYARRAY_H_class Array
{
public:Array(int length);Array(const Array &obj); //加了const更好~Array();
public:void setdata(int index, int value);int getdata(int index);int getLenth();
private:int m_length;int *m_space;
};#endif

myarray.cpp

#include <iostream>
#include "myarray.h"//作用域不要忘写
//构造函数
Array::Array(int length)  
{if (length < 0){length = 0;}m_length = length;m_space = new int[length];// this->m_length = length;// this->m_space = new int[length];
}
//构造函数的重载
Array::Array(const Array &obj) 
{m_length = obj.m_length;m_space = new int[m_length];for (int i = 0; i < m_length; i++)m_space[i] = obj.m_space[i];
}
//析构函数
Array::~Array()
{if (m_space != NULL){delete[] m_space;m_space = NULL;m_length = -1;}
}
//成员函数
void Array::setdata(int index, int value)
{if (0 <= index && index <= m_length)m_space[index] = value;
}
int Array::getdata(int index)
{if (0 <= index && index <= m_length)return m_space[index];return -1;
}
int Array::getLenth()
{return m_length;
}

main.cpp

#include <iostream>
#include "myarray.h"int main()
{Array array1(4);for (int i = 0; i < array1.getLenth(); i++){array1.setdata(i, i + 100);std::cout << array1.getdata(i) << "\t";}std::cout << std::endl;Array array2 = array1;for (int i = 0; i < array2.getLenth(); i++){std::cout << array2.getdata(i) << "\t";}std::cout << std::endl;return 0;
}

编译运行

[root@centos1 test]# g++ -o main main.cpp myarray.cpp
[root@centos1 test]# ./main
100     101     102     103
100     101     102     103
[root@centos1 test]# 

(3)对象的构造和析构

定义和调用说明

1 构造函数定义

  • C++中的类可以定义与类名相同的特殊成员函数,这种与类名相同的成员函数叫做构造函数。
  • 构造函数默认是无参数的,当类中没有定义构造函数时,编译器默认提供⼀个⽆参构造函数, 并且其函数体为空。也可以在定义时自行设计有参数和函数体。
  • 没有任何返回类型的声明。

2 构造函数的调⽤

  • ⾃动调⽤:⼀般情况下C++编译器会⾃动调⽤构造函数
  • ⼿动调⽤:在⼀些情况下则需要⼿⼯调⽤构造函数

3 析构函数定义及调⽤

  • C++中的类可以定义⼀个特殊的成员函数清理对象,这个特殊的成员函数叫做析构函数
  • 语法:~ClassName()
  • 析构函数没有参数也没有任何返回类型的声明
  • 析构函数在对象销毁时⾃动被调⽤
  • 析构函数调⽤机制:C++编译器⾃动调⽤

有参数的构造函数,构造函数重载,拷贝构造函数

⼆个特殊的构造函数:

  • 默认无参构造函数。当类中没有定义构造函数时,编译器默认提供⼀个⽆参构造函数, 并且其函数体为空。
  • 默认拷贝构造函数。当类中没有定义拷⻉构造函数时,编译器默认提供⼀个默认拷⻉构造函数,简单的进⾏成员变量的值复制。

示例代码

#include <iostream>
#include <cstring>class Test
{
public:Test() //无参数构造函数{age = 0;strcpy(name, "tom");}Test(int age) //有参数构造函数 //构造函数重载{this->age = age;strcpy(name, "tom");}Test(int age, char *name) //有参数构造函数  //构造函数重载{this->age = age;strcpy(this->name, name);}Test(const Test &obj) // 拷贝构造函数{this->age = obj.age;this->name = obj.name;}~Test()  //析构函数{std::cout << "object destroyed" << std::endl;}
public:void printT(){std::cout << "name = " << name << std::endl;std::cout << "age = " << age << std::endl;std::cout << "---------------" << std::endl;}
private:char *name = new char[20];int age;
};int main()
{// 1.c++编译器自动的调用构造函数Test t0; // 自动调用无参数构造函数t0.printT();char name1[] = "hello";Test t1(10, name1); // 自动调用参数构造函数t1.printT();// 2.手动调用构造函数char name2[] = "world";Test t2 = Test(100, name2); t2.printT();strcpy(name2, "good");Test t3 = Test(1000, name2); //t4对象的初始化t2 = t3;t2.printT();// 3.对象赋值t0 = t1; std::cout << &t0 << "," << &t1 << std::endl;  // 不同t0.printT();//对象的初始化 和 对象的赋值 是两个不同的概念// 4.拷贝构造函数Test t4 = Test(t3);//Test t4 = t3; // 等价的方式 // 对象的初始化t4.printT();std::cout << &t3 << "," << &t4 << std::endl; // 不同return 0;
}

编译运行

[root@centos1 test]# g++ main.cpp -o main -std=c++11
[root@centos1 test]# ./main
name = tom
age = 0
---------------
name = hello
age = 10
---------------
name = world
age = 100
---------------
name = good
age = 1000
---------------
0x7ffd41eaa4e0,0x7ffd41eaa4c0
name = hello
age = 10
---------------
name = good
age = 1000
---------------
0x7ffd41eaa490,0x7ffd41eaa480
object destroyed
object destroyed
object destroyed
object destroyed
object destroyed
[root@centos1 test]# 

匿名对象的去和留

可以用函数返回对象,为匿名对象。关于匿名对象的去和留,结论如下:

  • 返回的匿名对象,若没人接盘,则这个匿名对象构造后会直接析构。
  • 返回的匿名对象,若赋值给另外一个同类型的对象,那么匿名对象在构造后会被析构。
  • 返回的匿名对象,若直接来初始化另外一个同类型的对象,那么匿名对象会直接转成新的对象。

示例代码

#include <iostream>class Location
{
public:Location(int xx = 0, int yy = 0){X = xx;Y = yy;std::cout << "Object Created\n";}Location(const Location &p) //拷贝构造函数{X = p.X;Y = p.Y;std::cout << "Object Copy" << std::endl;}~Location(){std::cout << "(" << X << "," << Y << ") "<< "Object Destroyed" << std::endl;}
public:int GetX() { return X; }int GetY() { return Y; }
private:int X, Y;
};void PrintLocation(Location p) //打印对象的属性
{std::cout << "Funtion:" << p.GetX() << "," << p.GetY() << std::endl;
}Location GenLocation() //返回一个匿名对象
{Location A(1, 2);return A;
}// 匿名对象的去和留,关键看,返回时如何接盘
// = 在赋值和初始化这两种情况时有所不同
int main()
{// (1)若返回的匿名对象,赋值给另外一个同类型的对象,那么匿名对象会被析构std::cout << "--------B--------" << std::endl;Location B;  // 调用一次构造函数B = GenLocation(); // 调用构造函数  // 然后调用析构函数//(2)若返回的匿名对象,直接来初始化另外一个同类型的对象// 那么匿名对象会直接转成新的对象std::cout << "--------C--------" << std::endl;Location C = GenLocation();  // 调用一次构造函数//(3)没人接盘 //这个匿名对象构造后会直接析构std::cout << "----------------" << std::endl;GenLocation(); // 调用一次构造函数  // 然后调用析构函数std::cout << "--------end--------" << std::endl;// 程序结束时// B调用一次析构函数// C调用一次析构函数return 0;
}

编译运行

[root@localhost test]# g++ main.cpp -o main
[root@localhost test]# ./main
--------B--------
Object Created
Object Created
(1,2) Object Destroyed
--------C--------
Object Created
----------------
Object Created
(1,2) Object Destroyed
--------end--------
(1,2) Object Destroyed
(1,2) Object Destroyed
[root@localhost test]# 

类中嵌套对象的初始化与对象初始化列表

情况描述:如果我们设计的类中有一个成员,它本身是另一个类,而且这个成员构造函数只有带参数的构造函数,没有默认构造函数。这时要对这个类成员进行初始化,就必须调用这个类成员的带参构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。

解决办法:C++在构造函数中提供初始化列表对成员变量进行初始化。

语法规则作用域::类名(参数1, 参数2, ...):成员类名1(实参值a, 实参值b,...), 成员类名2((实参值m, 实参值n,...)

构造函数和析构函数调用顺序

  • 构造函数顺序:先执行被组合对象的构造函数 。如果组合对象有多个,按照定义顺序,,而不是按照初始化列表的顺序。初始化列表先于构造函数的函数体执行。
  • 析构函数 : 和构造函数的调用顺序相反

示例:在B类中,组合了一个 A类对象,A类设计了构造函数,但构造函数只有带参的构造函数,根据构造函数的调用规则,必须要调用A类的带参构造函数。

示例代码

#include <iostream>
#include <cstring>class A
{
public:A(int _a){a = _a;std::cout << "generate A " << a << std::endl;}~A(){std::cout << "destroy A " << a << std::endl;}
protected:
private:int a;
};class B
{
public://B(int _b1, int _b2): a1(_b1), a2(_b2)B(int _b1, int _b2): a1(1), a2(2){b1 = _b1;b2 = _b2;std::cout << "generate B " << std::endl;}B(int _b1, int _b2, int m, int n):a1(m), a2(n){b1 = _b1;b2 = _b2;std::cout << "generate B " << std::endl;}~B(){std::cout << "destroy B " << std::endl;}
protected:
private:int b1;int b2;A a2;A a1;
};void objplay()
{B(1, 2);
}int main()
{objplay();return 0;
}

运行结果

generate A 2
generate A 1
generate B 
destroy B 
destroy A 1
destroy A 2

类中const常量初始化与对象初始化列表

当类成员中含有⼀个const对象时,或者是⼀个引⽤时,他们也必须要通过成员初始化列表进⾏初始化,因为这两种对象要在声明后⻢上初始化,⽽在构造函数中,做的是对他们的赋值,这样是不被允许的。

示例代码

#include <iostream>
#include <cstring>class A
{
public:A(int _a){a = _a;std::cout << "generate A " << a << std::endl;}~A(){std::cout << "destroy A " << a << std::endl;}
public:int geta(){return a;}
protected:
private:int a;
};class B
{
public:B(int _b1, int _b2): a1(_b1), a2(_b2), c(_b2)// B(int _b1, int _b2): a1(1), a2(2), c(0){b1 = _b1;b2 = _b2;std::cout << "generate B " << std::endl;}B(int _b1, int _b2, int m, int n):a1(m), a2(n), c(0){b1 = _b1;b2 = _b2;std::cout << "generate B " << std::endl;}~B(){std::cout << "destroy B " << std::endl;}
public:void print(){std::cout << "---------" << std::endl;std::cout << b1 << std::endl;std::cout << b2 << std::endl;std::cout << a2.geta() << std::endl;std::cout << a1.geta() << std::endl;std::cout << c << std::endl;}
protected:
private:int b1;int b2;A a2;A a1;const int c;
};void objplay()
{B obj_b1 = B(1, 2);obj_b1.print();B obj_b2(3, 4);obj_b2.print();
}int main()
{objplay();return 0;
}

运行结果

generate A 2
generate A 1
generate B 
---------
1
2
2
1
2
generate A 4
generate A 3
generate B 
---------
3
4
4
3
4
destroy B 
destroy A 3
destroy A 4
destroy B 
destroy A 1
destroy A 2

(4)new和delete用法

在软件开发过程中,常常需要动态地分配和撤销内存空间。在C语⾔中是利⽤库函数malloc和 free来分配和撤销内存空间的。C++提供了较简便⽽功能较强的运算符new和delete来取代 malloc和free函数。

注意:new和delete是运算符,不是函数,因此执⾏效率⾼。

虽然为了与C语⾔兼容,C++仍保留malloc和free函数,但建议⽤户不⽤malloc和free函数,⽽ ⽤new和delete运算符。

new用法举例

  • new int;  //开辟⼀个存放整数的存储空间,返回⼀个指向该存储空间的地址(即指针)
  • new int(100);  //开辟⼀个存放整数的空间,并指定该整数的初值为100,返回⼀个指向该 存储空间的地址
  • new char[10];  //开辟⼀个存放字符数组(包括10个元素)的空间,返回⾸元素的地址
  • new int[5][4];  //开辟⼀个存放⼆维整型数组(⼤⼩为5*4)的空间,返回⾸元素的地址
  • float *p=new float(3.14159);  //开辟⼀个存放单精度数的空间,并指定该实数的初值为 3.14159,将返回的该空间的地址赋给指针变量p
  • Box *pt;  //定义⼀个指向Box类对象的指针变量pt
  • pt=new Box;  //在pt中存放了新建对象的起始地址
  • Box *pt = new Box ;
  • Box *pt=new Box(12,15,18);

注意⽤new分配数组空间时不能指定初值。如果由于内存不⾜等原因⽽⽆法正常分配空间,则new会 返回⼀个空指针NULL,⽤户可以根据该指针的值判断分配空间是否成功。

delete用法

若P是⼀个指向数组的指针,则delete p表示清空内存⾸地址,delete[] p表示清空整个数组 对应的堆中内存空间。

malloc-free和new-delete区别

  • malloc不会调⽤类的构造函数,new能执⾏类型构造函数
  • free不会调⽤类的析构函数,delete操作符 能执⾏类的析构函数

示例代码

#include <iostream>
#include <stdlib.h>class Test
{
public:Test(int _a){a = _a;std::cout << "generate A" << std::endl;}~Test(){std::cout << "destroy A" << std::endl;}
protected:
private:int a;
};int main()
{// 1.基础类型// 用malloc这个函数int *p1 = (int *)malloc(sizeof(int));*p1 = 10;free(p1);// 用new这个运算符int *p2 = new int;*p2 = 20;free(p2);int *p3 = new int(30);delete p3;// 2.数组// mallocint *p4 = (int *)malloc(sizeof(int) * 10); // int array[10];p4[0] = 1;free(p4);// newint *pArray = new int[10];pArray[1] = 2;delete[] pArray; char *pArray2 = new char[25];delete[] pArray2;// 3.给对象分配堆内内存空间std::cout << "---------malloc------------" << std::endl;Test *testp1 = (Test *)malloc(sizeof(Test));std::cout << "---------free------------" << std::endl;free(testp1);std::cout << "----------new-----------" << std::endl;Test *testp2 = new Test(1);std::cout << "----------delete-----------" << std::endl;delete testp2;return 0;
}

运行结果

---------malloc------------
---------free------------
----------new-----------
generate A
----------delete-----------
destroy A

(5)static与静态成员变量(函数)

静态成员变量

思考:每个变量,拥有属性。有没有⼀些属性,归所有对象拥有?

把⼀个类的成员修饰为 static 时,这个类⽆论有多少个对象被创建,这些同类对象共享这个 static 成员。

  • 静态成员在类的内部声明,但要在类的外部初始化。静态成员局部于类,它不是对象成员。
  • 静态不初始化时,只要不调⽤这个静态成员编译就不会报错,但只有调⽤时才会报错。
  • 静态成员只有在初始化后,才会分配内存空间。
#include <iostream>class counter
{
public:static int num; //声明静态数据成员
public:void setnum(int i) { num = i; } //成员函数访问静态数据成员void shownum() { std::cout << num << std::endl; }
};// 在类的外部初始化静态数据成员
// 只能初始化一次
int counter::num = 0; int main()
{counter a, b;//调用成员函数访问私有静态数据成员a.shownum(); //0b.shownum(); //0//只要有一个对象改变了静态成员的值//则所有对象调用该静态成员时的值也会变a.setnum(10);a.shownum(); //10b.shownum(); //10//若静态数据成员是public的//还可以直接通过类访问静态成员std::cout << counter::num << std::endl;return 0;
}

静态成员函数

用static修饰成员函数,成为静态函数。

对于静态成员函数,是全部对象公有函数,提供不依赖于类数据结构的共同操作,它没有this指针。

  • 在类外调⽤静态成员函数⽤ “类名::静态函数”作限定词,或通过对象调⽤。
  • 注意静态函数中,不能使用普通成员变量,也不能调用普通成员函数,只能使用静态成员变量

#include <iostream>class Worker
{
public:void company_age_add(){company_age++;}void print_company_age1(){std::cout << "normal print: company_age=" << company_age << std::endl;}static void print_company_age2() //静态成员函数{std::cout << "static print: company_age=" << company_age << std::endl;// std::cout << "age:" << age << std::endl; // error C2597: 对非静态成员“Worker::age”的非法引用// 静态函数中 不能使用 普通成员变量 普通成员函数}
protected:
private:int age;int salary;static int company_age; //静态成员变量
};int Worker::company_age = 10;int main()
{Worker w1, w2, w3;// 1.普通成员函数调用静态成员变量w1.print_company_age1(); // normal print: company_age=10w2.company_age_add();w3.print_company_age1(); // normal print: company_age=11// 2.调用静态成员函数// 第一种:用对象.w3.print_company_age2();  // static print: company_age=11 // 第二种:类::Worker::print_company_age2(); // static print: company_age=11 return 0;
}

(6)c++编译器对成员变量和函数的处理机制

内存占用机制

C++类对象中的成员变量和成员函数是分开存储的。

  • 成员变量:
    • 普通成员变量:存储于对象中,与struct变量有相同的内存布局和字节对⻬⽅式
    • 静态成员变量:存储于全局数据区中
  • 成员函数:存储于代码段中。
#include <iostream>
#include <stdio.h>class C1
{
public:int i; // 4个字节int j; // 4个字节int k; // 4个字节
protected:
private:
}; //共12个字节class C2
{
public:int i;int j;int k;static int m;
public:int getK() const { return k; }  void setK(int val) { k = val; } 
protected:
private:
};struct S1
{int i;int j;int k;
}; // 12struct S2
{int i;int j;int k;static int m;
}; // 12int main()
{printf("c1:%d \n", sizeof(C1)); //12printf("c2:%d \n", sizeof(C2)); //12printf("s1:%d \n", sizeof(S1)); //12printf("s2:%d \n", sizeof(S2)); //12return 0;
}

this指针

C++中类的普通成员函数都隐式包含⼀个指向当前对象的this指针。比如类成员函数Test(int a, int b)其实是Test(Test *this, int a, int b)。

静态成员函数与普通成员函数的区别:静态成员函数不包含指向具体对象的指针,普通成员函数 包含⼀个指向具体对象的指针。

#include <iostream>class Test
{
public:Test(int a, int b){this->a = a;this->b = b;}void print1(int a) //这个a是函数形参的a{std::cout << "----------print1----------" << std::endl;for (int i = 0; i < a; i++){std::cout << "a: " << this->a << std::endl; //打印对象的属性a的值std::cout << "b: " << this->b << std::endl;}}void print2() {std::cout << "----------print2----------" << std::endl;// 当函数形参没有与成员变量同名的形参时// 函数内部可以不用this,直接访问成员变量std::cout << "a: " << a << std::endl; //打印对象的属性a的值std::cout << "b: " << b << std::endl;}protected:
private:int a;int b;
};int main()
{Test t1(1, 2);t1.print1(3);t1.print2();return 0;
}

⽤const限定this指针

C++中类的普通成员函数都隐式包含⼀个指向当前对象的this指针。比如类成员函数Test(int a, int b)其实是Test(Test *this, int a, int b)。

将const写在成员函数处,比如void OperateVar(int a, int b) const,将会对this指针和this下的成员进行修饰,只有只读属性,使得this和this成员不能被改变。

注意:

  • const 无论写在函数什么位置,都没有关系,像下面这样都可以
    • void OperateVar(int a, int b) const

    • const void OperateVar(int a, int b)

    • void const OperateVar(int a, int b)

  • const修饰的是谁?

    • const修饰的是形参a吗?不是

    • const修饰的是属性this->a  this->b

    • const修饰的是this指针所指向的内存空间, 修饰的是this指针

#include <iostream>class Test
{
public:Test(int a, int b) //---> Test(Test *this, int a, int b){this->a = a;this->b = b;}void printT(){std::cout << "a: " << a << "\t";std::cout << "b: " << this->b << std::endl;}void OperateVar(int a, int b) const// void const OperateVar(int a, int b)  // const void OperateVar(int a, int b){a = 100;// this->a = 100; //因为const,会报错// this->b = 200; //因为const,会报错// this = 0x11;   //因为const,会报错std::cout << "a: " << this->a << "\t";std::cout << "b: " << this->b << std::endl;}
protected:
private:int a;int b;
};int main()
{int *m_space = new int[0];if (m_space == NULL){return -1;}Test t1(1, 2);t1.printT();//a: 1  b: 2t1.OperateVar(100, 200);//a: 1  b: 2return 0;
}

end

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

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

相关文章

L1-098 再进去几个人 - java

L1-098 再进去几个人 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB 题目描述&#xff1a; 数学家、生物学家和物理学家坐在街头咖啡屋里&#xff0c;看着人们从街对面的一间房子走进走出。他们先看到两个人进去。时光流逝。他们又看到三个人出来。 物理…

锐捷网络闪耀高博会:智慧教育数字基座引领教育数字化新浪潮

4月15日,第61届中国高等教育博览会(简称“高博会”)在福州盛大开幕,在这次教育高端装备展示、教学改革成果交流、校企云集的行业盛会上,围绕构建智慧教育数字基座,锐捷网络携全场景智慧教育方案亮相,极简以太全光网、高校桌面云、5G多网融合等创新方案纷纷登场,吸引了众多观众驻…

【Python_PySide6学习笔记(三十六)】基于QGroupBox和QScrollArea实现带有滚动条的QGroupBox(分组框)

基于QGroupBox和QScrollArea实现带有滚动条的QGroupBox分组框 基于QGroupBox和QScrollArea实现带有滚动条的QGroupBox(分组框)前言正文1、创建QGroupBox并创建其内部布局2、创建QScrollArea并将QGroupBox设置为其内容3、将QScrollArea添加到主窗口的中心部件的布局中4、完整代码…

Linux实现文件共享

#nfs-utils、rpcbind 软件包来提供 NFS 共享服务 #客户端创建共享文件夹&#xff1a; nmcli c reload nmcli c up ens160 systemctl stop firewalld systemctl disable firewalld rpm -q nfs-utils rpcbind #查看是否安装 systemctl enable rpcbind systemctl enable nfs…

JavaEE初阶之IO流快速顿悟一(超详细)

目录 题外话 正题 IO流 Java.io.FileInputStream int read() int read(byte[] b) 关于异常 Java7的新特性: try-with-resources ( 资源自动关闭) Java.io.FileOutputStream void write(int b) void write(byte[] b) 小结 题外话 十年青铜无人问,一朝顿悟冲王者 前天…

C#控制台相关方法

控制台相关方法 文章目录 控制台输入1、清空2、设置控制台3、设置光标位置&#xff0c;1y 2x4、设置颜色相关5、光标显隐6、关闭控制台思考 移动方块 控制台输入 //如果ReadKey(true)不会把输入的内容显示再控制台上 char c Console.ReadKey(true).KeyChar;1、清空 ​ Cons…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(二)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 3 - 4节&#xff09; P3《开发准备-了解ArkTS》 鸿蒙开发主要是用来开发移动端应用的。 以前我们开发移动端应用的代码&#xff…

Linux 认识与学习Bash——2

1 read 从键盘读取变量的值 read 后面不带变量&#xff0c;那么默认会给REPLY变量赋值 #!/bin/bash echo -n "请输入你的名字&#xff1a;" read name echo "欢迎您 $name" echo "----------------"echo -n "请输入你的名字2&#xff1a;&q…

[MoeCTF-2022]Sqlmap_boy

title:[MoeCTF 2022]Sqlmap_boy 查看网页源代码&#xff0c;得到提示 <!-- $sql select username,password from users where username".$username." && password".$password.";; --> 用万能密码绕过&#xff0c;用’"闭合 爆数据库…

华锐双柜台系统超越快速通道!

很多朋友除了使用快速通道&#xff0c;但是一般资金量都不满足独立单元交易格&#xff0c;共享不够满足自己&#xff0c;那么是可以选择双柜台系统。我们一起来了解下&#xff01; 首先为什么我们使用华锐双柜台系统更快呢&#xff1f; 我们都知道&#xff1a;极速柜台的交易…

多模态模型和大型语言模型(LLM):概念解析与实例探究

在人工智能的世界中&#xff0c;我们经常遇到各种模型来解决不同类型的问题。最近&#xff0c;特别引人注意的是多模态模型和大型语言模型&#xff08;LLM&#xff09;。尽管这两种模型都是AI技术的当前前沿&#xff0c;但它们在功能和设计上有显著差异。本文旨在阐释这两种模型…

HOOPS Commuicator:基于Web的交互式2D/3D图形轻量化引擎

在当前数字化时代&#xff0c;Web基础的3D应用程序正在成为行业标准&#xff0c;尤其是在工程和制造领域。Tech Soft 3D公司旗下的HOOPS Communicator正是针对这一需求设计的高级解决方案&#xff0c;提供了一套全面的工具&#xff0c;旨在帮助开发者构建复杂的3D工程应用程序。…

Android 单一音量控制

1、关闭/开启单一音量控制 frameworks/base/core/res/res/values/config.xml <!-- Flag indicating whether all audio streams should be mapped toone single stream. If true, all audio streams are mapped toSTREAM_MUSIC as if its on TV platform. --><bool n…

Springboot+Vue项目-基于Java+MySQL的图书馆管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

RabbitMQ spring boot TTL延时消费

关于延时消费主要分为两种实现&#xff0c;一种是rabbitmq的TTL机制&#xff0c;一种是rabbitmq的插件实现。 实现一&#xff1a;TTL 1、设置队列的过期时间 2、设置消息的过期时间 添加相关maven依赖 <dependency><groupId>org.springframework.boot</grou…

【信号处理】基于CNN的心电(ECG)信号分类典型方法实现(tensorflow)

关于 本实验使用1维卷积神经网络实现心电信号的5分类。由于数据类别不均衡&#xff0c;这里使用典型的上采样方法&#xff0c;实现数据类别的均衡化处理。 工具 方法实现 数据加载 Read the CSV file datasets: NORMAL_LABEL0 , ABNORMAL_LABEL1,2,3,4,5 ptbdb_abnormalpd.…

C++:函数符(一)

正文 函数对象也叫函数符&#xff0c;函数符是可以以函数方式与()结合使用的任意对象。这包括函数名、指向函数的指针和重载了()运算符的类对象。 上面这句话的意思是指&#xff1a;函数名、指向函数的指针和重载了括号运算符的类对象与括号结合&#xff0c;从而以函数方式实…

【行为型模式】解释器模式

一、解释器模式概述 解释器模式定义&#xff1a;给分析对象定义一个语言&#xff0c;并定义该语言的文法表示&#xff0c;再设计一个解析器来解释语言中的句子。也就是说&#xff0c;用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口&#xff0c;该接口…

python高级进阶

目录 一、str字符串 1. 字符串定义 2. 获取字符串中元素 3. 遍历字符串 4. 字符串常见操作 二、set集合 1. 集合的创建 2. 遍历集合中的元素 3. 集合中添加元素 4. 集合删除元素 三、字典 1. 字典的定义 2. 字典的特点 3. 字典增删改查 4. 字典遍历 四、slice切片…

【经验总结】Ubuntu 源代码方式安装 Microsoft DeepSpeed

1. 背景介绍 使用 DeepSpeed 在多服务器上分布式训练大模型 2. 安装方法 2.1 查看显卡参数 ~$ CUDA_VISIBLE_DEVICES0 python -c "import torch; print(torch.cuda.get_device_capability())" (8, 0) ~$ CUDA_VISIBLE_DEVICES0 python -c "import torch; pr…