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

news2024/11/20 7:40:31

文章目录

  • 一、再谈构造函数
    • 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;//OK
			cout << 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. 连续的两个构造或两个拷贝构造或一个拷贝构造和一个构造会进行优化

在这里插入图片描述

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

七、再次理解类和对象

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


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

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

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

相关文章

一个简化、落地的实时数据仓库解决方案

从传统的经验来讲&#xff0c;数据仓库有一个很重要的功能是记录数据变化历史。通常&#xff0c;数据仓库都希望从业务上线的第一天开始有数据&#xff0c;然后一直记录到现在。但实时处理技术&#xff0c;又是强调当前处理状态的一门技术&#xff0c;所以当这两个相互对立的方…

聚合数据证件识别接口-基于PHP示例代码

1、开通接口 以下代码示例基于聚合数据提供的证件识别接口&#xff0c;使用前需要先注册申请本接口&#xff0c;获得请求密钥key。 接口文档地址&#xff1a;https://www.juhe.cn/docs/api/id/153 2、功能介绍 通过自动识别的方式获取常规证件文字内容&#xff0c;免去用户…

react函数式组件转化为string---renderToString

需求 使用aggrid的过程中&#xff0c;某个自定义的图标需要传dom的字符串。 但在react的开发中&#xff0c;一般都是组件的概念&#xff08;ReactNode&#xff0c;JSX.Element&#xff09; 因此需要一个方法将dom组件转化为字符串 收获 找到了官网的API——renderToString 作…

虚拟主机部署ssl证书(https)流程

注意事项&#xff1a; 1、域名要做别名解析指向二级域名 2、证书已经申请完成&#xff0c;其他公司的证书要下载导入到西部数码。 虚拟主机部署教程如下&#xff1a; 部署证书 首先要将域名绑定到主机上&#xff0c;在主机控制面板找到【SSL部署】按钮。 在西部数码申请过证…

FFmpeg 媒体文件播放 格式变化流程简述

例如&#xff0c;要播放一个 MP4 文件&#xff0c;这个文件要经过啥呢&#xff1f; 一个 MP4 文件中包含了&#xff1a;视频压缩数据流&#xff08;如H.264、H.265&#xff09;和音频压缩数据&#xff08;如aac、MP3&#xff09; 首先需要经过解码成为原始数据&#xff0c;视频…

数据库原理及应用上机实验一

✨作者&#xff1a;命运之光 ✨专栏&#xff1a;数据库原理及应用上机实验报告整理 目录 ✨一、实验目的和要求 ✨二、实验内容与步骤 &#x1f353;&#x1f353;前言&#xff1a; 数据库原理及应用上机实验报告的一个简单整理后期还会不断完善&#x1f353;&#x1f353;…

HarmonyOS低代码开发-创建新工程方式

使用低代码开发应用或服务有以下两种开发方式&#xff1a; 创建一个支持低代码开发的新工程&#xff0c;开发应用或服务的UI界面。在已有工程中&#xff0c;创建Visual文件来开发应用或服务的UI界面。ArkTS工程和JS工程使用低代码的步骤相同&#xff0c;接下来以JS工程为例讲解…

Web自动化框架中验证码识别处理全攻略,自动化测试神器,让测试更得心应手。

目录 前言&#xff1a; 一. Web自动化测试框架搭建 1. 选择一个自动化测试工具 2. 安装环境 3. 初始化一个Selenium驱动 二. 添加自动化测试用例 1. 编写测试脚本 2. 运行测试脚本 三. 验证码识别与处理 1. 验证码种类 2. 验证码处理方式 四. 结语 Web自动化测试&#…

指针不可怕,请爱它呵护它(狗头)

&#x1f929;本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 &#x1f970;内容专栏&#xff1a;这里是《C知识系统分享》专栏&#xff0c;笔者用重金(时间和精力)打造&#xff0c;基础知识一网打尽&#xff0c…

opencv_c++学习(十一)

一、绘制基础图形 绘制直线&#xff1a; line(InputOutputArray img. Point pt1, Point pt2, const Scalar & color, int thickness 1,llineType int LINE_8, int shift 0pt1:直线起始点在图像中的坐标。 pt2:直线终点在图像中的坐标。 color:直线的颜色&#xff0c;…

《2023新一代数字办公白皮书》正式发布!| 爱分析报告

2023年5月12日&#xff0c;受北京市数字办公安全创新联合体委托&#xff0c;由自主可控新鲜事和爱分析联合撰写的《2023新一代数字办公白皮书》&#xff08;以下简称《白皮书》&#xff09;在“2023通明湖论坛 信创基础底座创新发展分论坛”上正式发布。 《白皮书》详细阐述了新…

box的符号距离函数

序 能用解析的方法算的&#xff0c;叫符号距离函数。只能数值解的&#xff0c;叫符号距离场。 它就是横平竖直的几个平面&#xff0c;点到平面的距离是很好算的。 初步认识 有个网页&#xff0c;可以玩一玩&#xff1a; About | Physics Simulation in Visual Computing (…

抖音seo源码开发,开源技术保姆式搭建

抖音seo源码优化逻辑 抖音SEO是通过一系列的技术手段和优化策略来提升视频内容在抖音平台内的曝光率和排名。其中主要包括以下几个方面&#xff1a; 1.关键词优化。通过对视频的标题、描述等元素的关键词进行优化&#xff0c;提高相关性和匹配度&#xff0c;让用户更容易搜索到…

文件权限属性八进制表示法,chmod(文件权限属性更改),chown,chgrp指令,默认/实际起始权限与umask权限掩码关系,文件删除与粘滞位问题等

文件权限属性的八进制表示法 这个其实非常简单&#xff0c;因为文件权限属性也就三种&#xff0c;也就是可读&#xff0c;可写或者可执行。然后对于这三种文件权限属性都是2元式的&#xff0c;要么行&#xff0c;要么不行&#xff0c;因此可以用0和1来表示&#xff0c;0表示没…

SAML协议— 理解SAML2 协议和联合身份验证流程

1、SAML协议概念 安全断言标记语言&#xff0c;简称SAML&#xff0c;是一个基于 XML 的开源标准数据格式&#xff0c;它在当事方之间交换身份验证和授权数据&#xff0c;尤其是在身份提供者和服务提供者之间交换。SAML解决的最主要的需求是基于Web的单点登录&#xff08;SSO&a…

100 个 Go 错误以及如何避免:1~4

协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【OpenDocCN 饱和式翻译计划】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 真相一旦入眼&#xff0c;你就再也无法视而不见。——《黑客帝国》 一、GO&#xff1a;学起来简单&…

再次比较以1为参照的6-3分布

( A, B )---1*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有1个节点&#xff0c;AB各由9张二值化的图片组成&#xff0c;让A中有3个0&#xff0c;6个1.B中全是1&#xff0c;排列组合A的所有可能&#xff0c;统计迭代次数的顺序。 得到数据 迭代次数平均值 A-B 迭代次数 F 9 …

5年经验还只会点点点,别等了,跳槽吧.....

随着工作年限的不断增长&#xff0c;感觉自己的技术水平与自己的工作年限严重不符。想跳槽出去换个新环境吧&#xff0c;又感觉自己的能力达不到心仪公司的标准&#xff0c;即使投了简历自己也没什么面试通知。就这样在原来的公司一天天的混日子&#xff0c;时间久了&#xff0…

「免费版Axure」原型设计工具!

Axure 是一款经典的原型设计工具&#xff0c;但需要下载电脑端软件使用&#xff0c;对新手要求较高&#xff0c;且在线协作效率低&#xff0c;使用成本较高。即时设计是一款免费在线原型设计工具&#xff0c;支持导入 Axure 文件进行二次布局、评审、演示和分享&#xff0c;让用…

GitLAB CI-CD入门

GitLab CI-CD入门 目录 1、GitLabCI/CD简介 GitLabCI/CD简介 GitLabCI/CD是GitLab内置的持续集成与持续部署系统 开源&#xff1a; CI/CD是开源GitLab社区版和专有GitLab企业版的一部分。(极狐)易于学习&#xff1a; 官方具有详细的学习操作文档。无缝集成&#xff1a; CI/CD…