【C++之类和对象】默认成员函数

news2024/12/24 2:44:52

目录

    • 前言
    • 一、默认成员函数
    • 二、构造函数
    • 三、析构函数
    • 四、拷贝构造函数
    • 五、赋值运算符重载

前言

前面我们学习了一些类和对象的基本知识,知道了什么是类,类中包括什么东西,以及能够使用一个类来实例化对象,并且会计算类对象的大小。这次我们重点是学习类中的一些非常重要的知识:默认成员函数和运算符重载。默认成员函数一共有6个,但是比较重要的就是四个:构造函数,析构函数,拷贝构造函数,赋值运算符重载。

一、默认成员函数

在学习类的几个默认成员函数之前,我们首先需要知道什么是默认成员函数,默认成员函数和普通成员函数有什么区别?

  • 默认成员函数也是一种成员函数,其之所以称为默认成员函数,是因为,就算我们不写,编译器也会帮我们生成一个以完成对应的功能,类中常见的默认成员函数有:构造函数析构函数拷贝构造函数赋值运算符重载函数
  • 普通成员函数也是一种成员函数,但是和默认成员函数的区别就是,只有我们定义实现的时候才是存在的,如果我们没有显示定义实现,那么就是不存在的,编译器不会帮助我们生成一个。像前面文章中实现的类中的初始化函数打印函数是我们自己定义实现的,不自己定义实现编译器也不会生成,所以是普通成员函数

二、构造函数

构造函数是C++类中提出来的一个概念,是类中的一个默认成员函数,其主要功能就是在类创建对象的时候自动调用该函数完成对类实例化的对象中成员变量的初始化工作。需要注意的是:此函数虽然叫做构造函数,但是其并不是完成对象的构造,只是完成对实例化出的对象中成员变量属性的初始化,其功能类似于前面实现的初始化函数

  • 构造函数的特性
  1. 函数名与类名相同
  2. 无返回值
  3. 对象实例化时编译器自动调用对象对应的类的构造函数完成对这个对象中成员变量的初始化
  4. 构造函数可以重载。参数中可以是无参,半缺省,全缺省。
    在这里插入图片描述
    当无参版本的构造函数和全缺省版本的构造函数同时存在时,当我们创建对象的时候没有进行传参,因为,无参版本的构造函数和全缺省参数的构造函数都可以不用传参就能够调用,所以此时编译器就会出现歧义,不知道调用哪一个,所以会报错。
    在这里插入图片描述
    在这里插入图片描述
  • 修改后代码:只留下全缺省版本
class Date
{
public:
	// 构造函数

	// 全缺省
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	 半缺省
	//Date(int year , int month, int day = 1)
	//{
	//	_year = year;
	//	_month = month;
	//	_day = day;
	//}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	d1.Print();
	return 0;
}
  • 调式
    在这里插入图片描述
  • 运行结果
    在这里插入图片描述

对于全缺省版本的构造函数,我们也可以在调用的时候进行传参
在这里插入图片描述
5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成
6. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数。

class Date
{
public:

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1;
	d1.Print();
	return 0;
}

上述代码中日期类中并没有实现构造函数,所以编译器会帮助我们自动生成一个,但是需要知道的是,编译器帮我们生成的默认构造函数对类中的内置类型成员是不会进行处理的,而只会处理自定义类型的成员
在这里插入图片描述
下面举一个类中有自定义成员的例子

在这里插入图片描述
从上面的例子中我们可以看出,我们在日期类中多加了一个A类的成员变量,A类属于自定义类型,年月日都属于整型,属于内置类型,我们在日期类中并没有实现构造函数,所以编译器会帮我们自动生成一个默认构造函数,这个默认构造函数对于对象中的内置类型并不会做任何处理,对于对象中的自定义类型就会去调用这个类型的默认构造函数,我们在A类中实现了一个默认构造函数对A类型中的成员变量进行了初始化,所以这个日期类中的A类型成员可以正常进行初始化。

  • 假如A类型中不实现构造函数
    在这里插入图片描述
    显然这个时候日期类去调用A类的默认构造函数时,编译器检测到A类中没有实现构造函数,所以编译器也会帮助A类实现一个默认构造函数,而我们知道编译器生成的默认构造函数对于内置类型不会进行任何处理,所以,此时日期类中的A类中的成员变量是随机值,并没有进行初始化。

  • A类中定义一个构造函数
    在这里插入图片描述
    在这里插入图片描述
    当A类中手动定义一个构造函数时,编译器识别到A类中存在构造函数,因此不会帮助A类生成一个默认构造函数,又因为日期类要调用A类的默认构造函数对A类的对象进行初始化,此时A类中的构造函数不是默认构造函数,因此就会报错。

  • 下面举一个比较经典的栈和队列的例子
    代码1:栈类中手动实现一个构造函数

class Stack
{
public:
	
	// 手动实现一个构造函数
	Stack(int capacity)
	{
		_a = (int*)malloc(sizeof(int) * capacity);
		if (_a == nullptr)
		{
			return;
		}
		_capacity = capacity;
		_size = _top = 0;
	}

	void Print()
	{
		cout << _capacity << endl;
		cout << _size << endl;
		cout << _top << endl;
	}

private:
	int* _a;
	int _size;
	int _capacity;
	int _top;
};

class Queue
{
public:
	// 对于队列类,类中的成员变量全部是自定义类型成员,所以可以不需要自己实现构造函数,编译器生成的默认构造函数就够用了
	void Print()
	{
		_st1.Print();
		_st2.Print();
	}

private:
	Stack _st1;
	Stack _st2;
};

int main()
{
	// 测试队列
	Queue q;// q中有两个栈类的成员变量
	q.Print();


	return 0;
}

结果:
在这里插入图片描述
在这里插入图片描述

分析:上述的代码中,有一个栈类,一个队列类,在队列中包含两个栈,全是自定义类型,此时是可以不实现构造函数的,编译器生成的默认构造函数就够用了,在栈类中,全是自定义类型,显然是需要实现一个构造函数的,但是我们在栈类中实现了一个非默认构造函数的版本,所以编译器不会再帮助栈类重新生成一个默认构造函数,所以栈类中不存在默认构造函数,当创建队列对象的时候,首先会去调用队列类的默认构造函数,但是队列中是两个栈类成员,所以队列的默认构造函数会去调用栈类成员的默认构造函数,又因为,栈类中不存在相应的默认构造函数,因此,此时就调用失败,故报错。

  • 代码2:栈类中不自己实现构造函数
class Stack
{
public:

	void Print()
	{
		cout << _capacity << endl;
		cout << _size << endl;
		cout << _top << endl;
	}

private:
	int* _a;
	int _size;
	int _capacity;
	int _top;
};

class Queue
{
public:
	// 对于队列类,类中的成员变量全部是自定义类型成员,所以可以不需要自己实现构造函数,编译器生成的默认构造函数就够用了
	void Print()
	{
		_st1.Print();
		_st2.Print();
	}

private:
	Stack _st1;
	Stack _st2;
};

int main()
{

	// 测试队列
	Queue q;// q中有两个栈类的成员变量
	q.Print();


	return 0;
}

结果:
在这里插入图片描述

分析:通过上面的结果,我们可以看到,此时队列中栈的成员全部是随机值。我们没有在队列中实现构造函数,所以编译器会生成一个队列的默认构造函数,队列中的成员变量是两个栈类型,所以当创建队列类的对象时,编译器会自动调用队列的默认构造函数,对于队列中的栈类型成员,队列的默认构造函数会去调用它们的默认构造函数,又因为我们没有在栈类中实现构造函数,所以编译器会在栈类中生成一个默认构造函数,因为编译器生成的默认构造函数对于类中的内置类型不会做处理,栈中的成员全部是内置类型,所以栈的默认构造函数不会对其进行处理,因此最终结果是随机值。
代码3:栈类中实现一个全缺省的默认构造函数

class Stack
{
public:
	// 对于栈类,类中的成员变量全部是内置类型成员,所以我们必须自己实现构造函数
	Stack(int capacity = 10, int size = 0)
	{
		_a = (int*)malloc(sizeof(int) * capacity);
		if (_a == NULL)
		{
			return;
		}
		_capacity = capacity;
		_size = size;
		_top = 0;
	}


	void Print()
	{
		cout << _capacity << endl;
		cout << _size << endl;
		cout << _top << endl;
	}

private:
	int* _a;
	int _size;
	int _capacity;
	int _top;
};

class Queue
{
public:
	// 对于队列类,类中的成员变量全部是自定义类型成员,所以可以不需要自己实现构造函数,编译器生成的默认构造函数就够用了
	void Print()
	{
		_st1.Print();
		_st2.Print();
	}

private:
	Stack _st1;
	Stack _st2;
};

int main()
{
	// 测试队列
	Queue q;// q中有两个栈类的成员变量
	q.Print();


	return 0;
}

结果:
在这里插入图片描述

分析:上述代码中显然队列中的栈成员中的成员变量不再是随机值。分析情况和上面两种情况是类似的,当创建队列类的对象时,编译器会去调用队列的默认构造函数,由于队列中没有实现构造函数,所以编译器会生成一个默认构造函数,这个默认构造函数又回去调用队列中栈成员的默认构造函数,我们在栈类中实现了一个全缺省的默认构造函数,所以编译器不会再生成栈类的默认函数,所以队列的默认构造函数就会调用我们实现的栈的默认构造函数对队列中的栈成员进行初始化,故最终结果不是随机值。

总结:一个类中的构造函数分为普通构造函数和默认构造函数,默认构造函数只有三种:无参构造函数,全缺省参数构造函数,不写编译器自动生成的默认构造函数,这三个默认构造函数在调用的时候是可以不进行传参的,其他在调用的时候需要传参的构造函数属于普通构造函数。默认构造函数在对对象中的成员变量进行初始化时会将对象中的成员变量分为内置类型的成员变量和自定义类型的成员变量,默认构造函数对于内置类型的成员变量不会进行任何处理,对于自定义类型的成员变量会去调用这个成员的默认构造函数,如果这个成员的类中没有默认构造函数(也就是手动实现了一个非默认构造函数),那么此时原来类中的默认构造函数就无法调用这个成员的默认构造函数,此时就会报错。

  • 什么时候需要手动实现构造函数,什么时候不需要手动实现构造函数,编译器帮助我们生成的默认构造函数就够用了呢?
    当一个类中的成员变量中只存在自定义类型时,此时编译器自动生成的默认构造函数就够使用了,当然,一定要确保,这些自定义类型中是存在默认构造函数的,并且能够对其自己的成员变量进行正确的初始化的。如果一个类中存在内置类型,因为编译器自动生成的默认构造函数是无法处理内置类型的成员变量的,所以此时我们就需要自己实现构造函数才能对这些内置类型的成员变量进行初始化。

三、析构函数

析构函数和前面我们实现的销毁函数的功能是类似的,其主要是完成类对象中资源的清理工作,并不会销毁对象。所谓的资源通常是指一个动态开辟的指针指向的空间。对于没有资源的类可以不需要实现析构函数。析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作

析构函数是特殊的成员函数。
其特征如下:

  1. 析构函数名是在类名前加上字符 ~
  2. 无参数无返回值。一个类中只能有一个析构函数,不能构成重载。
  3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数

前面写的一个栈类就需要实现自己实现析构函数

class Stack
{
public:
	// 对于栈类,类中的成员变量全部是内置类型成员,所以我们必须自己实现构造函数
	Stack(int capacity = 10, int size = 0)
	{
		_a = (int*)malloc(sizeof(int) * capacity);
		if (_a == NULL)
		{
			return;
		}
		_capacity = capacity;
		_size = size;
		_top = 0;
	}

	// 析构函数
	~Stack()
	{
		free(_a);
		_size = _capacity = _top = 0;
	}


	void Print()
	{
		cout << _capacity << endl;
		cout << _size << endl;
		cout << _top << endl;
	}

private:
	int* _a;
	int _size;
	int _capacity;
	int _top;
};
  1. 当我们没有自己实现析构函数时,编译器也会自动生成一个析构函数,编译器生成的析构函数对于类中的内置类型不会做任何处理,对于自定义类型的成员会去调用这个成员的析构函数
class String
{
public:
	String(const char* str = "jack")
	{
		_str = (char*)malloc(strlen(str) + 1);
		strcpy(_str, str);
	}
	~String()
	{
		cout << "~String()" << endl;
		free(_str);
	}
private:
	char* _str;
};
class Person
{
private:
	String _name;
	int _age;
};
int main()
{
	Person p;
	return 0;
}

分析:
在上述代码中,我们在Person类中没有实现析构函数,所以编译器会生成一个Person类的析构函数,Person类中的成员变量是名字和年龄,年龄是整型变量,是一个内置类型,所以编译器生成的析构函数不会处理,姓名是一个string类型,是一个自定义类型,所以析构函数会去调用这个成员的析构函数完成其中资源的清理工作。

四、拷贝构造函数

拷贝构造函数完成的工作主要是拷贝工作,通常是用一个同类型的对象去拷贝构造一个新的对象。构造函数:只有单个形参该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用

拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式
  2. 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。如果拷贝构造函数的参数不是采用引用传参,而是采用传值传参,当调用拷贝构造时,首先需要将拷贝对象传给函数的形参,而拷贝对象是一个自定义类型的对象,所以也是一次拷贝构造过程,所以会继续调用拷贝构造函数,所以就会出现源源不断地调用该类型的拷贝构造函数。
  3. 拷贝构造通常分为值拷贝和深拷贝。对于类型中没有动态开辟的指针,通常只需要实现浅拷贝即可,对于类型中存在动态开辟的指针,那么就需要实现成深拷贝。
  4. 如果我们没有在类型中实现拷贝构造函数,那么编译器会自动生成一个拷贝构造函数,编译器生成的拷贝构造函数是一个浅拷贝。
  5. 编译器生成的拷贝构造函数在处理类中成员时,同样将成员变量分成两类:内置类型和自定义成员。对于内置类型,实现浅拷贝,对于自定义类型,调用这个成员的拷贝构造函数。
    下面我们写一个日期类的拷贝构造函数

代码1:自己实现拷贝构造函数

class Date
{
public:
	// 对于日期类,因为其中的成员变量全部是内置类型,所以我们必须自己实现一个构造函数
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	// 拷贝构造函数
	Date(const Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}


private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023,2,3);
	Date d2(d1);

	d1.Print();
	d2.Print();

	return 0;
}

结果:
在这里插入图片描述

在实现拷贝构造函数时,我们需要注意一些细节:拷贝构造函数的参数必须是传引用传参,防止出现无限递归传参,如果可以确定被拷贝的对象不会发生改变,我们可以在形参前面加上const关键字,从而可以对形参在函数中实行保护,防止被拷贝的对象在拷贝构造函数中被改变。
代码2:自己不实现拷贝构造函数

class Date
{
public:
	// 对于日期类,因为其中的成员变量全部是内置类型,所以我们必须自己实现一个构造函数
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}


private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2023, 2, 3);
	Date d2(d1);

	d1.Print();
	d2.Print();

	return 0;
}

结果:
在这里插入图片描述

通过上面的结果,显然对于日期类,就算我们不自己实现一个拷贝构造函数,仍然能够完成拷贝过程,这是因为,当我们没有在类中实现拷贝构造函数时,编译器会帮我们自动生成一个,编译器生成的拷贝构造函数可以帮助实现浅拷贝,对于日期类,类中的成员变量没有动态开辟的指针,因此浅拷贝就能够实现拷贝过程了。

代码3:栈类型不实现拷贝构造函数

class Stack
{
public:
	// 对于栈类,类中的成员变量全部是内置类型成员,所以我们必须自己实现构造函数
	Stack(int capacity = 10, int size = 0)
	{
		_a = (int*)malloc(sizeof(int) * capacity);
		if (_a == NULL)
		{
			return;
		}
		_capacity = capacity;
		_size = size;
		_top = 0;
	}

	// 析构函数
	~Stack()
	{
		free(_a);
		_size = _capacity = _top = 0;
	}

	void Print()
	{
		cout << _capacity << endl;
		cout << _size << endl;
		cout << _top << endl;
	}

private:
	int* _a;
	int _size;
	int _capacity;
	int _top;
};

int main()
{
	Stack st1(10);
	Stack st2(st1);

	st1.Print();
	st2.Print();

	return 0;
}

结果:
在这里插入图片描述

通过上面结果我们可以看出程序发生崩溃,显然编译器生成的浅拷贝并不能够正确完成栈类型对象的拷贝过程,原因是栈类型中有一个动态开辟的指针,如果只是完成浅拷贝,那么最终就会导致两个栈中的指针指向了同一块空间,最后当对象要析构的时候,两个对象都需要调用析构函数,就会出现同一块空间被释放两次,所以程序会发生崩溃。除此之外,两个栈中的指针指向同一块空间,其中一个栈在修改数据时,显然也会影响到另一个栈的空间,显然是不正常的。
解决方法:对于栈类型的拷贝构造函数,需要自己实现深拷贝。

五、赋值运算符重载

赋值运算符重载需要使用一个新的关键字operator,并且重载之后其实是形成一个新的函数,所以运算符重载本身就是一种函数,其还可以增加代码的可读性,随着学习的深入,我们会慢慢体会到。赋值的运算符和拷贝构造有点类似,但是也有所不同。拷贝构造的过程是使用一个同类型的对象去拷贝构造一个新的对象,赋值是将一个同类型的对象去赋值另一个已经存在的对象,在实现赋值运算符重载的过程中需要注意几个细节:赋值给自己,支持连续赋值(考虑返回值的问题),下面以一个日期类的赋值运算符重载函数作为例子:

	// 赋值运算符重载
	Date& operator=(const Date& d)
	{
		if (this != &d)
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this;
	}

分析:其中的if条件判断就是可以解决对象自身赋值的情况,返回值是*this,就可以支持连续赋值了,并且,由于出了函数,*this还存在,所以这里可以考虑传引用返回,从而降低拷贝。

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

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

相关文章

Java Collection 接口下的 “ List 集合” 与 “ Set 集合 ”

Java Collection接口下的“ List 集合” 与 “ Set 集合 ” 每博一文案 一个人最好的底牌&#xff0c;就这两个字: 靠谱,是最高级的聪明。 师父说&#xff1a;人生一回&#xff0c;道义一场&#xff0c;你对人对事的态度&#xff0c;藏着你一生的福报。 千金难买好人缘&#x…

SpringBoot(三):日志文件

目录一、日志文件1.1 日志文件的作用1.2 Spring Boot内置了日志框架1.3 日志的格式说明1.4 自定义日志打印1.5 日志的持久化1.6 日志的级别1.6.1 日志级别有什么作用1.6.2 日志的级别划分1.6.3 日志级别的设置1.7 使用lombok输出日志1.7.1 lombok的原理1.7.2 lombok其他注解一、…

在JS文件中使用或扩展已有的vue文件

工作中遇到一个给现有项目增加一个超时重新登录的提醒框&#xff08;可在提醒框中直接登录本账户&#xff09;。 由于页面稍微复杂&#xff0c;本人又是脚手架一把梭过来的&#xff0c;对于直接使用 js 来完成一整个复杂还带逻辑的页面稍显吃力&#xff0c;所以决定先写一个 vu…

建模助手【有求必应】的正确打开方式

今天的话题主要想解除大家对[有求必应] 的一些误解。 因为在日常的反馈中用户似乎对于[提需求] 这玩意儿无论是从概念上还是动作上都很不 “熟悉”。 其实我们对软件认知的上限是一个软件功能的上限&#xff0c;产品以及行业的发展都要从打破固有认知开始。 期待更多的你们跳出…

《新华日报·科技周刊》聚焦蓝海彤翔与《流浪地球2》

瞄准世界科技前沿瞄准江苏科技创新瞄准日常科技生活《新华日报科技周刊》第203期聚焦《流浪地球2》中的大国重器其实就在我们身边重点报道了蓝海创意云渲染农场为《流浪地球2》提供了云计算渲染服务的重要成果“数字生命计划”就是元宇宙吗&#xff1f;电影中人类面临末日危机&…

0基础如何入门人工智能?

1.1 概念 根据维基百科的解释&#xff0c;人工智能是被机器展示的智力&#xff0c;与人类和其他动物的自然智能相反&#xff0c;在计算机科学中 AI 研究被定义为 “代理人软件程序”&#xff1a;任何能够感受周围环境并且能最大化它成功机会的设备。 1.2 重大事件 2016 年 3…

[Java]JavaWeb学习笔记(尚硅谷2020旧版)

文章目录&#x1f3c0; 视频及资料地址&#x1f3c0; XML⚽ XML 简介&#x1f3d0; xml 的作用⚽ XML 语法&#x1f3d0; 文档声明&#x1f3d0; 注释&#x1f3d0; 元素(标签)⚾ XML 命名规则⚾ xml 中的元素(标签)也分单双标签&#x1f3d0; xml 元素属性&#x1f3d0; 语法规…

PHP控制反转和依赖注入的理解(通俗易懂)

目录 1.IoC是什么 2.IoC能做什么 3.IoC和DI 4.IoC(控制反转) 5.DI(依赖注入) 6.我对IoC(控制反转)和DI(依赖注入)的理解 学习PHP各个框架的过程中&#xff0c;都会听过IoC(控制反转) 、DI(依赖注入)这两个概念&#xff0c;总觉得IoC 、DI这两个概念是模糊不清的&#xff…

WINSOFT JSEngine Delphi 6-D11

WINSOFT JSEngine Delphi 6-D11 WinsoftJSEngine被认为是一个海豚引擎&#xff0c;包括一个强大的JavaScript引擎。 Winsoft JSEngine的功能和特点&#xff1a; Microsoft ChakraCore JavaScript强大的引擎实用程序 支持32位和64位窗口 提供给海豚版本6 Eli 10.1和Lazarus 为产…

29岁,从餐饮到网络安全,大龄转行逆袭成功

大龄转行&#xff0c;一直在网络上备受讨论。 从学习能力、试错成本来考虑&#xff0c;转行一定是越早越好&#xff0c;而大龄转行风险极大。 大龄转行&#xff0c;固然并非一条绝路&#xff0c;苏老泉&#xff0c;二十七&#xff0c;始发愤&#xff0c;读书籍&#xff0c;有的…

C++学习记录——사 类和对象(1)

文章目录1、面向对象和面向过程的初步理解2、类的引入3、类的定义4、类的访问限定符及封装1、访问限定符2、封装5.类的实例化6、类对象模型7、this1、this指针2、空指针问题3、C语言和C简单对比1、面向对象和面向过程的初步理解 C语言是一个面向过程的语言&#xff0c;C是一个…

美颜sdk人脸识别代码技术分析

很多人问过小编&#xff0c;什么样的美颜sdk才算好&#xff1f;对于这个问题&#xff0c;小编认为至少要符合以下几个特点。 1、稳定性强&#xff1b;2、识别精准&#xff1b;3、功能多样&#xff1b;4、集成容易&#xff1b;5、离线使用&#xff1b;6、支持多端&#xff1b;7、…

新手入门,深入解析 python lambda表达式

lambda 表达式是 Python 中的匿名函数。它接受任意数量的参数&#xff0c;并返回一个单个表达式的值。它的语法格式如下&#xff1a; lambda arguments: expression 文章目录lambda 函数原型解释lambda 函数用作其它参数lambda 函数高级的技巧多个参数返回多个值条件表达式嵌套…

java基础巩固-宇宙第一AiYWM:为了维持生计,编程语言番外篇之机器学习(项目预测模块总结:线性回归算法、逻辑回归分类算法)~整起

机器学习一、机器学习常见算法&#xff08;未完待续...&#xff09;1.算法一&#xff1a;线性回归算法&#xff1a;找一条完美的直线&#xff0c;完美拟合所有的点&#xff0c;使得直线与点的误差最小2.算法二&#xff1a;逻辑回归分类算法3.算法三&#xff1a;贝叶斯分类算法4…

PythonWeb开发基础(一)B/S开发和http协议

文章目录PythonWeb开发基础&#xff08;一&#xff09;B/S开发和http协议请求响应连接PythonWeb开发基础&#xff08;一&#xff09; B/S开发和http协议 推荐书籍&#xff1a;《HTTP权威开发指南》 前端&#xff1a;数据的格式化呈现&#xff0c;python中的format函数其实就…

【MyBatis】查询语句汇总

定义一个Car类:/*** 封装汽车相关信息的 pojo类*/ public class Car {// 数据库表当中的字段应该和pojo类的属性一一对应// 建议使用包装类, 这样可以防止null的问题private Long id;private String carNum;private String brand;private Double guidePrice;private String pro…

MATLAB入门——线性规划、非线性规划、多目标规划

4-1 线性规划_哔哩哔哩_bilibili 4-2 非线性规划_哔哩哔哩_bilibili 4-3 多目标规划_哔哩哔哩_bilibili 1.线性规划 有限条件下&#xff0c;最大收益 1. 例题 例题&#xff1a;张麻子既要攻碉楼又要追替身&#xff0c;他们一伙6人&#xff0c;总共1200发子弹;每有一人攻确…

【GCC】1: RTCP RR接收端生成

m79 代码。参考bytewoods 大神的以下文章:WebRTC 基于GCC的拥塞控制(上) WebRTC 基于GCC的拥塞控制(下)虽然可以拿到估算的带宽但是rtcp 总是malformed packet个 有必要带着问题跟进下整个过程 RR报文 基于丢包率的码率控制运行在发送端,依靠RTCP RR报文进行工作。* report b…

Vue2低代码平台搭建(一)

前言 大家好,我是L丶Y,这一次,我们来聊一聊前端低代码平台的构建。近些年来,随着Saas行业的高速发展,低代码的概念也逐渐流行了起来,而低代码产品也越来越多的出现在我们的身边,像国外的Mendix,国内的宜搭、苍穹、简道云等等,想通过这篇文章与大家对于前端低代码平台…

如何使用Baklib搭建企业内部wiki

Wiki 是一个协同著作平台或称开放编辑系统。我们可以用Wiki来建设帮助系统&#xff0c;知识库系统。国内公共wiki最著名就是百度百科&#xff0c;国外则是基维百科&#xff1b;Wiki最著名的例子之一是维基百科&#xff0c;它在MediaWiki上运行&#xff0c;任何拥有Web浏览器的人…