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

【C++从0到王者】第六站:类和对象(下)

文章目录

  • 一、再谈构造函数
    • 1.构造函数体赋值
    • 2.初始化列表
      • 1>初始化列表的使用
      • 2>初始化列表的注意事项
    • 3.explicit关键词
  • 二、static成员
    • 1.如何统计当前程序中变量的个数
    • 2.static的特性
    • 3.从1加到n
    • 4.设计一个类,只能在栈或者堆上开辟空间
  • 三、友元
    • 1.友元函数
    • 2.友元类
  • 四、内部类
    • 1.内部类的概念
    • 2.内部类的特性
    • 3.从1加到n
  • 五、匿名对象
  • 六、拷贝构造中编译器的一些优化
  • 七、再次理解类和对象

一、再谈构造函数

1.构造函数体赋值

如下代码所示,当我们写构造函数的时候,我们通常会在函数体内进行赋值。这就是构造函数体赋值

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};

虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。

2.初始化列表

1>初始化列表的使用

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。初始化列表是构造函数的一部分
如下所示是初始化列表的基本使用

class Date
{
public:Date(int year = 2023, int month = 1, int day = 1):_year(year),_month(month),_day(day){}
private:int _year;int _month;int _day;
};

2>初始化列表的注意事项

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
  2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
    引用成员变量
    const成员变量
    自定义类型成员(且该类没有默认构造函数时)

这三种情况必须使用初始化列表的原因就是因为他们初始化后就不能被修改了,而构造函数体赋值并不是初始化,是一个赋值操作。初始化列表其实就是对象的成员定义的位置
如下代码所示

class A
{
public:A(int a,int b){cout << "A" << endl;}
private:int a;
};
class B
{
public:B(int i, int& ref):_ref(ref), i(i),aa(1,2){cout << "B" << endl;}
private:int& _ref;const int i;A aa;
};
int main()
{int n=0;B b(1, n);return 0;
}

事实上,我们的构造函数中,即便不写,也有初始化列表。只不过对于内置类型而言这个初始化列表什么也不做,对于自定义类型,他的初始化列表就相当于调用它对于的默认构造函数,而一旦该自定义类型没有默认构造函数的时候,那么就必须要有初始化列表了。
在这里插入图片描述我们有时候也会给成员变量缺省值,这个缺省值的作用其实就是给初始化列表,当我们没有显示的在初始化列表上赋值的时候,那么缺省值就会给初始化列表

有了初始化列表,我们就可以这样做,在之前的栈实现队列中,我们就可以显示的指定栈的容量进行初始化

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}private:DataType* _array;size_t _size;size_t _capacity;
};class MyQueue
{
public:MyQueue(){}MyQueue(int capacity):_pushst(capacity),_popst(capacity){}private:Stack _pushst;Stack _popst;
};int main()
{MyQueue q1;MyQueue q2(100);return 0;
}
  1. 初始化列表是构造函数的一部分,它与函数体赋值是相辅相成的,并不能相互替代
    这是我们需要注意的一点,因为有些时候在函数体中有其他事情要做,比如检查内存申请是否成功等

如下所示,是需要检查是否申请内存成功

class Stack
{
public:Stack(int capacity = 4):_arr((int*)malloc(sizeof(int)* capacity)), _top(0), _capacity(capacity){if (_arr == nullptr){perror("malloc fail");exit(-1);}memset(_arr, 0, sizeof(int) * _capacity);}
private:int* _arr;int _top;int _capacity;
};

如下所示是为了动态开辟一个二维数组

class AA
{
public:AA(int row = 10, int col = 5):_row(row),_col(col){_aa = (int**)malloc(sizeof(int*) * _row);int i = 0;for (i = 0; i < _col; i++){_aa[i] = (int*)malloc(sizeof(int) * _col);memset(_aa[i], 0, sizeof(int) * _col);}}
private:int** _aa;int _row;int _col;
};
  1. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
  2. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

我们可以看这段代码的运行结果

class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2;int _a1;
};
int main() {A aa(1);aa.Print();
}

在这里插入图片描述这是因为初始化列表是按照成员变量的顺序走的,也就是先初始化_a2,由于_a1并不知道,所以就是被初始化为了随机值。然后才将_a1初始化为1

3.explicit关键词

我们先来看这段代码

class A
{
public:A(int a):_a2(a),_a1(a){}void Print(){cout << _a1 << " " << _a2 << endl;}
private:int _a2;int _a1;
};
int main() {A aa1(1);A aa2 = 2;return 0;
}

这段代码我们可能会疑惑:A aa2=2这个语句。这里其实是隐式的类型转换。整型转化为了自定义类型
我们在之前说过,在发生类型转换时候,会产生一个临时变量,如下代码所示,将i类型转换为double类型,然后拷贝给d

int i=1;
double d=i;

所以前面的代码也是同理的:2先构造一个A的临时对象,在将这个临时变量拷贝构造给A
但是现在的编译器都会在这里进行一次优化,优化用2直接构造给A,只需要构造一次,跳过了拷贝构造环节
在这里插入图片描述我们可以从下面的代码验证拷贝构造的存在
在这里插入图片描述在这里插入图片描述第一个报错的原因是,临时变量具有常性,1构造出来的A临时对象,使用aa3作为别名的时候,类型是A&,权限放大。所以报错
第二个正确是因为,aa3此时是const A&类型,可以直接引用这个临时变量。权限平移

当然我们有时候也期望说能不能不要发生这些隐式类型转换,我们就可以加上explicit关键词,这个关键词加在构造函数的前面在这里插入图片描述

二、static成员

1.如何统计当前程序中变量的个数

我们最容易想到的方法就是创建一个全局变量,当调用构造和拷贝构造的时候,全局变量++,当调用析构函数的时候,全局变量–

int _scount = 0;
class A
{
public:A(){_scount++;}A(const A& a) { _scount++;}~A() { _scount--; }
private:
};
A a0;
A Func(A a)
{cout << __LINE__ << ":" << _scount << endl;A a4;cout << __LINE__ << ":" << _scount << endl;return a4;
}
int main()
{cout << __LINE__ << ":" << _scount << endl;A a1;static A a2;Func(a1);cout << __LINE__ << ":" << _scount << endl;return 0;
}

在这里插入图片描述还有如下的程序,下面的程序是在函数中使用了静态的变量,这样的话它这个变量就放在了静态区,只会被创建一次

int _scount = 0;
class A
{
public:A() { _scount++; }A(const A& a) { _scount++; }~A() { _scount--; }
private:
};
A a0;
void  Func()
{static A a4;cout << __LINE__ << ":" << _scount << endl;
}
int main()
{cout << __LINE__ << ":" << _scount << endl;A a1;static A a2;Func();Func();return 0;
}

在这里插入图片描述

但是上面两个代码都有一个劣势,那就是全局变量极其容易被修改。导致出现问题。为了避免这个问题,我们可以采用静态的方法,将这个变量放在成员变量用static修饰。也就是静态成员变量

成员变量和静态成员变量还是存在区别的。成员变量属于每一个类对象。静态成员变量不是属于某个对象,而是属于类的,属于每个类的对象共享,存储在静态区。生命周期是全局的。

  1. 由于静态成员变量并不属于某个类对象,所以它不可以在初始化列表进行初始化,更不可能使用缺省值。
  2. 他在类中仅仅只是一个声明,定义它的初始值需要在全局位置:类外进行定义。在类外进行定义的时候,该静态成员变量可以是私有的,可以是公有的,这里可以突破一次。
  3. 但是定义之后,再次使用这个静态成员变量。可以是将其设置为公有的,然后直接使用域作用限定符进行调用。或者利用一个对象调用它。
  4. 但是大多数时候是私有的,我们可以通过一个公有的成员函数进行获取它的值。这里又牵扯到一个问题:如果调用公有的成员函数?如果有对象,那自然可以借助对象来调用成员函数。如果没有对象呢?我们就需要使用静态成员函数了。静态成员函数是没有this指针的,只需要类域和访问限定符就可以访问这个函数了
  5. 还需要注意的是,静态成员函数里面是不可以访问到非静态的成员变量。因为它没有this指针
class A
{
public:A() { _scount++; }A(const A& a) { _scount++; }~A() { _scount--; }static int GetScount(){return _scount;}
private://成员变量int a;int b;
//public://静态成员变量static int _scount;
};
int A::_scount = 0;
A a0;
void  Func()
{static A a4;cout << __LINE__ << ":" << A::GetScount() << endl;
}
int main()
{cout << __LINE__ << ":" << A::GetScount() << endl;A a1;static A a2;Func();Func();cout << __LINE__ << ":" << a2.GetScount() << endl;return 0;
}

2.static的特性

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
  6. 类成员函数可以访问静态成员函数,但是静态成员函数不可调用非静态的,因为非静态需要this指针,而静态没有this指针

3.从1加到n

我们来看这样一道题:从1加到n
这道题有很多的限制。我们假定在限制掉递归和位操作符。那么如何解决这道题呢?其实这就和前面的计算有多少个对象有异曲同工之妙。
如下代码所示,是我们给出的解法:我们在定义一个类,这个类有两个静态成员变量。我们先将其在类外初始化为0,当每调用一次构造函数的时候,count++,然后让ret加上count。最后我们直接在原来的类里面创建n个对象即可。就能得出最终结果,创建n个对象我们可以使用数组或者new来实现,但是不可以使用malloc。因为malloc不调用构造函数

class A
{
public:A(){count++;ret+=count;}static int Getret(){return ret;}
private:static int count;static int ret;
};
int A::count=0;
int A::ret=0;
class Solution {
public:int Sum_Solution(int n) {A a[n];return A::Getret();}
};

4.设计一个类,只能在栈或者堆上开辟空间

这个要求听起来是比较奇怪的,要求我们只能在栈区或者堆区开辟空间的话,就得先想办法控制住其他的开辟不了空间。我们可以直接将构造函数放到私有区域中,直接让开辟不了空间,然后我们在创建两个静态成员函数,这两个静态成员函数可以在栈区和堆区开辟空间。然后我们直接返回即可。这同样是应用了静态成员函数的特点

class A
{
public:static A GetStack(){A a;return a;}static A* GetHeap(){return new A;}
private:A(){};
};
int main()
{A a = A::GetStack();A* b = A::GetHeap();return 0;
}

三、友元

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元分为:友元函数和友元类

1.友元函数

我们在前面实现日期类的时候,对于流插入和流提取运算符的重载,我们不能在类内进行定义,因为this指针默认占据了第一个形参。为了交换参数的顺序,我们必须得将这两个运算符重载写到全局中。但是这样的话我们又出现了一个问题,我们无法访问成员变量。所以我们就使用了友元函数声明,你是我的朋友,所以可以来使用我的成员变量
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。

  1. 友元函数可访问类的私有和保护成员,但不是类的成员函数
  2. 友元函数不能用const修饰,因为没有this指针
  3. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  4. 一个函数可以是多个类的友元函数
  5. 友元函数的调用与普通函数的调用原理相同

2.友元类

** 友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。**

  1. 友元关系是单向的,不具有交换性。
  2. 比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time
  3. 类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
  4. 友元关系不能传递
  5. 如果B是A的友元,C是B的友元,则不能说明C时A的友元。
  6. 友元关系不能继承
class Time
{friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){}
private:int _hour;int _minute;int _second;
};
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}void SetTimeOfDate(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}
private:int _year;int _month;int _day;Time _t;
};

四、内部类

1.内部类的概念

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,它不属于外类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。

2.内部类的特性

特性:

  1. 内部类可以定义在外部类的public、protected、private都是可以的。内部类都可以访问外部类的成员。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。访问外部类的非静态成员就需要使用对象了。
  3. sizeof(外部类)=外部类,和内部类没有任何关系。
  4. 如果想要在类外定义内部类的对象,那么就需要通过作用限定符来找到内部类,在定义对象。如果内部类是私有的,那么就无法定义内部类的对象
class A
{
private:static int k;int h;
public:class B // B天生就是A的友元{public:void foo(const A& a){cout << k << endl;//OKcout << a.h << endl;//OK}};
};
int A::k = 1;
int main()
{cout << sizeof(A) << endl;A a;A::B b;b.foo(A());return 0;
}

3.从1加到n

我们继续看前面的这道题,我们可以借助内部类的特性,将原来的A类定义在Solution类里面,将A类的静态成员给Solution类。这样我们就利用内部类可以访问外部类的成员变量特性。从而实现我们的题目

class Solution {class A{public:A(){count++;ret += count;}};
public:int Sum_Solution(int n) {A a[n];return ret;}
private:static int count;static int ret;
};
int Solution::count=0;
int Solution::ret=0;

五、匿名对象

所谓匿名对象,就是没有名字的对象,它的声明周期只有那一行,即用即销毁

class A
{
public:A(int a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}int ADD(int x ,int y){cout << "int ADD(int x ,int y)" << endl;return x + y;}
};
int main()
{A a(10);//有名对象A(10);//匿名对象a.ADD(1, 2);A(10).ADD(1, 2);
}

在这里插入图片描述还需要注意的是:匿名对象具有常性
在这里插入图片描述并且加上const以后声明周期被延长了,声明周期延长为当前函数的局部域
在这里插入图片描述

六、拷贝构造中编译器的一些优化

如下类所示,我们将对下面的这个类做出一些操作

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a = aa._a;}return *this;}~A(){cout << "~A()" << endl;}
private:int _a;
};

我们知道如下几个比较简单的情况

  1. 传值调用需要调用拷贝构造函数,而传引用调用不需要拷贝构造函数
    在这里插入图片描述
  2. 当我们在函数内定义了A类型对象以后,返回这个对象的时候,是需要拷贝构造出一个临时对象的。
    在这里插入图片描述
  3. 当我们传引用返回的时候是没有拷贝构造的
    在这里插入图片描述

上面是一些比较简单的场景,下面就是一些比较复杂的场景了

  1. 像下面这种写法是错误的,因为返回的是一个临时变量。临时变量具有常性。涉及权限放大

在这里插入图片描述为了处理这个权限放大,我们可以在a的前面使用const进行修饰

在这里插入图片描述

  1. 同一行一个表达式中连续的构造+拷贝构造优化合二为一

下面这种写法是几次拷贝?

A Func5()
{A a;return a;
}
int main()
{A a= Func5();
}

我们会认为拷贝了两次,一次是返回的时候要生成临时变量,这是一次拷贝构造,在一次就是将临时变量拷贝构造出a。也就是两次。
但是现在的编译器会认为这个是比较浪费的,所以现在的编译器会处理这两次拷贝为一次拷贝
在这里插入图片描述在这里插入图片描述

  1. 连续的两个构造或两个拷贝构造或一个拷贝构造和一个构造会进行优化

在这里插入图片描述

如果我们分开写,先定义一个对象,在进行赋值的话,这样的代价大大提升了
前者合起来的只有一次拷贝构造。后者先进行构造,然后拷贝构造,然后赋值运算符重载。开销大大提升
在这里插入图片描述

七、再次理解类和对象

类是对某一类实体(对象)来进行描述的,描述该对象具有那些属性,那些方法,描述完成后就形成了一种新的自定义类型,才用该自定义类型就可以实例化具体的对象。
在这里插入图片描述


好了,本期内容就到这里了
如果对你有帮助的话,不要忘记点赞加收藏哦!!!

相关文章:

【C++从0到王者】第六站:类和对象(下)

文章目录 一、再谈构造函数1.构造函数体赋值2.初始化列表1>初始化列表的使用2>初始化列表的注意事项 3.explicit关键词 二、static成员1.如何统计当前程序中变量的个数2.static的特性3.从1加到n4.设计一个类&#xff0c;只能在栈或者堆上开辟空间 三、友元1.友元函数2.友…...

AJax和Axios的讲解

目录 Ajax Ajax基本介绍 同步异步 原生Ajax 原生的Ajax使用方式 Axios 基本介绍 Axios的基本使用 发送 get 请求 发送 post 请求 Axios快速入门 请求方法的别名 练习 Ajax Ajax基本介绍 Ajax: 全称Asynchronous JavaScript And XML&#xff0c;异步的JavaScript和XML…...

企业落地数字化转型,如何部署战略规划

当前环境下&#xff0c;各领域企业通过数字化相关的一切技术&#xff0c;以数据为基础、以用户为核心&#xff0c;创建一种新的&#xff0c;或对现有商业模式进行重塑就是数字化转型。这种数字化转型给企业带来的效果就像是一次重构&#xff0c;会对企业的业务流程、思维文化、…...

新的网络钓鱼即服务平台让网络犯罪分子生成令人信服的网络钓鱼页面

至少从2022年中期开始&#xff0c;网络犯罪分子就利用一个名为“伟大”的新型网络钓鱼即服务(PhaaS或PaaS)平台来攻击微软365云服务的企业用户&#xff0c;有效地降低了网络钓鱼攻击的门槛。 思科Talos研究员蒂亚戈佩雷拉表示:“目前&#xff0c;Greatness只专注于微软365钓鱼…...

MySQL的隐式转换

隐式转换 若字符串是以数字开头&#xff0c;并且全部都是数字&#xff0c;则转换的数字结果是整个字符串&#xff1b;部分是数字&#xff0c;则转换的数字结果是截止到第一个不是数字的字符为止 若字符串不是以数字开头&#xff0c;则转换的数字结果是 0 varchar str "…...

LeetCode:23. 合并 K 个升序链表

23. 合并 K 个升序链表 1&#xff09;题目2&#xff09;过程3&#xff09;代码1. 最开始2.初步优化 4&#xff09;结果1. 最开始2. 初步优化 1&#xff09;题目 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合…...

js:正则表达式常用方法总结test、exec、match、matchAll、replace、replaceAll、search

文章目录 正则使用testmatch/matchAll不加g加ggroup 的使用 matchAll不加g加g exec不加g加g searchreplace 正则使用 常用的几种方法有&#xff1a;test、exec、match、matchAll、replace、replaceAll、search test // 匹配返回true&#xff0c;不匹配false /e/.test("…...

分析车载蓝牙通话只有前喇叭声音,后面喇叭无声背后原因

车载蓝牙通话只有前喇叭声音&#xff0c;后面喇叭无声背后原因 大家有没有注意到车载蓝牙连接后通话的时候只有前喇叭的有声音&#xff0c;后面喇叭没声音呢&#xff1f;特别是后装的车载多媒体上基本都是这样&#xff0c;细思下为什么这样的原因&#xff0c; 采访后装车载技术…...

高性能ADC/DAC FMC子卡推出-FMC164

FMC164 子卡集成 4 通道 1Gsps 采样率&#xff0c;16 位 高性能ADC采样&#xff0c;板载4 通道1.25Gsps 16 位DA。板载时钟芯片 HMC7044&#xff0c;可以提供 JESD204B所需要的各种时钟。具有同步/触发功能&#xff0c;模拟信号采用 SSMC 射频连接器输入和输出。板载时钟芯片为…...

Agisoft Metashape 红外影像处理

系列文章目录 文章目录 系列文章目录前言一、加载红外影像二、对齐照片三、构建 DEM四、生成 DOM五、温度值可视化前言 Agisoft Metashape 专业版支持处理来自 AscTec(ARA 格式)、WIRIS(TIFF 格式)热成像仪和以 R-JPEG(FLIR 数据)格式保存数据的热成像数据。 在本文中,…...

Mybatis从入门到入土

一、什么是Mybatis 1&#xff09;MyBatis 是一款优秀的持久层&#xff08;DAO层&#xff09;框架 2&#xff09;MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程 3&#xff09;MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c;将…...

修为 - 人生感悟

人不为己&#xff0c;天诛地灭。 说明一下&#xff0c;上面说的为己&#xff0c;指的是人的修为。 一个人&#xff0c;在成年之后&#xff0c;需要不断的对自己进行修为的提高。在经历了世事之后&#xff0c;对人生的感悟要不断地进行总结&#xff0c;提高自己的修为。 老祖宗给…...

UnityWebSocket | 双端通信支持Text/Binary

跳转官方仓库地址 有多个项目使用该库&#xff0c;平台有PC、WebGL。 一、说明 1&#xff09;原理 WebSocket是H5提供的一种浏览器与服务器进行全双工通讯的网络技术&#xff0c;属于应用层协议。数据通常在两个站&#xff08;点对点&#xff09;之间进行传输&#xff0c;按照…...

lazada详情

{“api”: “”, “data”: {“module”: “{“seller”:{“chatResponsiveRate”:{“labelText”:“Chat Response”,“value”:“100%”},“chatUrl”:“https://pages.lazada.com.my/wow/i/my/im/chat?brandId30768”,“hideAllMetrics”:false,“imEnable”:true,“imUser…...

企业为什么要数字化转型?

数字化转型是使用数字技术从根本上改变企业运营方式并为客户创造价值的过程。企业进行数字化转型&#xff0c;常见因素包括&#xff1a; 提高效率&#xff1a;数字化转型可以简化流程并自动执行重复性任务&#xff0c;从而减少执行这些任务所需的时间和精力。可以节省成本并提高…...

Excel 设置只能输入指定的字符

目录 1. 创建你要用的表格 2. 确定你要限定输入的行/ 列 3. 创建另一个sheet&#xff0c;用来保存限制输入的配置信息 4. 选中【是否外包】列&#xff0c;并选择数据验证 5. 设置数据限制 6. 确认结果 7. 不想设置配置sheet怎么办&#xff1f; 在工作中&#xff0c;你们…...

Web开发介绍

Web开发介绍 1 什么是web开发 Web&#xff1a;全球广域网&#xff0c;也称为万维网(www World Wide Web)&#xff0c;能够通过浏览器访问的网站。 所以Web开发说白了&#xff0c;就是开发网站的&#xff0c;例如下图所示的网站&#xff1a;淘宝&#xff0c;京东等等 那么我们…...

多语言APP的外包开发流程及注意事项

近些年国内越来越多的公司走向海外&#xff0c;有些互联网项目即可以为国内用户使用&#xff0c;也可以为国外用户使用&#xff0c;尤其是一些智力类小游戏&#xff0c;这些小游戏不需要特别的运营&#xff0c;只要在设计和玩法上把握好&#xff0c;那就可以推广到全球用户。今…...

CMAKE介绍和使用(Windows平台)

CMake是一个跨平台的安装&#xff08;编译&#xff09;工具&#xff0c;可以用简单的语句来描述所有平台的安装(编译过程)。 Windows平台 cmake工具的下载 cmake工具下载官网&#xff1a; Download | CMake 下载压缩包后解压&#xff0c;解压后的bin文件路径加到电脑系统环境…...

宝塔面板webhook 使用教程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 背景1、介绍一下Webhook2、使用步骤1.安装git2.安装WebHook3.添加WebHook4.配置git 钩子 &#xff08;码云示例&#xff09;5.私有项目还需要做以下操作 背景 最近…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)

说明&#xff1a; 想象一下&#xff0c;你正在用eNSP搭建一个虚拟的网络世界&#xff0c;里面有虚拟的路由器、交换机、电脑&#xff08;PC&#xff09;等等。这些设备都在你的电脑里面“运行”&#xff0c;它们之间可以互相通信&#xff0c;就像一个封闭的小王国。 但是&#…...

C++_核心编程_多态案例二-制作饮品

#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为&#xff1a;煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例&#xff0c;提供抽象制作饮品基类&#xff0c;提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

命令行关闭Windows防火墙

命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)​方法二:CMD命令…...