C++类和对象(基础篇)

前言:

        其实任何东西,只要你想学,没人能挡得住你,而且其实学的也很快。那么本篇开始学习类和对象(C++的,由于作者有Java基础,可能有些东西过得很快)。

struct在C++中的含义:

        C++兼容C中的struct的用法,并将其升级,可以在里面写函数。

// C++兼容C中的struct的用法
// C++升级struct升级成了类
// 类和对象
// 1个类 实例化 N个对象

// 1.类里面可以定义函数
// 2.struct名称可以代表类型
struct Stack
{
	//成员函数
	void Init(int n = 4)
	{
		_arry = (int*)malloc(sizeof(int) * n);
		if (nullptr == _arry)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}

	//成员变量
	int* _arry;
	size_t _capacity;
	size_t _top;
};

int main()
{
	struct Stack s1;


	Stack s;
	s.Init();
	return 0;
}

        我们可以不用再写 struct + 结构体名称 去创建对象,相当于已经typedef了,并且可以直接在通过对象调用函数。

        这也体现了C++兼容C的特性。但是C++还是一般并不是用这种用法,一般是使用class来声明一个类。

class Stack
{
	void Init(int n = 4)
	{
		_arry = (int*)malloc(sizeof(int) * n);
		if (nullptr == _arry)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}

	//成员变量
	int* _arry;
	size_t _capacity;
	size_t _top;
};

int main()
{
	Stack s;
	//此时我们直接去使用里面的Init方法,发现报错
	s.Init();
	return 0;
}

 

访问权限: 

        上面我们看到报错,这是为啥?这是因为C++中有访问限定符。

1.public修饰的成员在类外可以直接访问

2.protected和private修饰的成员在类外不能直接被访问(此处protected 和 private 是类似的)

3.访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现为止

4.如果后面没有访问限定符,作用域就到 } 即类结束

5.class的默认访问权限为 private ,struct 为 public (因为 struct 要兼容C)

                所以报错的原因是因为前面默认被 private 修饰了。 

class Stack
{
public:
	void Init(int n = 4)
	{
		_arry = (int*)malloc(sizeof(int) * n);
		if (nullptr == _arry)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}

private:
	//成员变量
	int* _arry;
	size_t _capacity;
	size_t _top;
};

        所以一般是成员变量私有,成员方法公有。

        C++建议成员变量前面加_(这是软性建议)。

        我们先创建一个Stack.h头文件,并在里面写入:

Stack.h头文件(声明函数):

#include<iostream>

class Stack
{
public:
	void Init();
private:
	int* _a;
	int* _top;
	int* _capacity;
};

        此时我们在Stack.h头文件中定义一个类并声明其中的一个函数(没有定义),之后在Stack.cpp源文件中定义该函数,此时我们就需要指定类域去定义该函数。因为该函数并不是全局变量,必须指定类域。

Stack.cpp源文件中(定义函数):

void Stack::Init()
{
	_a = nullptr;
	_top = 0;
	_capacity = 0;
}

test.c源文件中(调用函数): 

int main()
{
	Stack st1;
	cout << sizeof(st1) << endl;
	cout << sizeof(Stack) << endl;
	return 0;
}

        可以发现没有计算函数的大小,因为实例化的对象调用的函数地址都是一样的,每个空间放一份,会造成空间的浪费。 

        所以对象占用的大小,只考虑成员变量,其大小规则和struct类似。

        对于一个空类(就是里面没有任何成员变量),空类的大小为1字节,以确保每个实例都有独一无二的地址,不储存有效数据,标识对象被定义出来了。

this指针:

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

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

int main()
{
	Date d1, d2;
	d1.Init(1990, 12, 1);
	d2.Init(1991, 12, 1);
	d1.Print(), d2.Print();
	return 0;
}

        这里有一个奇怪的现象,为什么打印的不同,它怎么会知道谁传给了我?其实这里的Print方法中有一个隐含的参数-this,这个this是一个指针。

void Print(Date* this)

        之后只要是成员变联名,它自动识别到了,都相当于前面加上了this指针。

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

        所以其实函数相当于是这样使用的,但是默认不加。所以我们还可以这样调用: 

d1.Print(&d1);

        严格来说是这样写的:

void Print(Date* const this)

注意事项一:

        我们先来观察以下代码:

class A
{
public:
	void Print()
	{
		cout << "Print()" << endl;
	}
private:
	int _a;
};

int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

        这里是其实没有对nullptr去进行解引用,因为默认传入this指针,并不影响对Print函数的使用。 

注意事项二:

        再来观察一下代码:

class A
{
public:
	void Print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};

int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}

        但这个结果是运行崩溃。我们来观察他们的区别: 

        this指针存在栈中,因为它是形参,也有可能是寄存器。

类的默认成员函数:

        类有6个默认成员函数,编译器会自动生成6个默认成员函数(很神奇,竟然有6个)。

        默认成员函数:用户没有显示实现,编译器会生成的成员函数成为默认成员函数。

构造函数:

        函数名与类名相同,无返回值,对象实例化编译器自动调用对应的构造函数,构造函数可以重载。分为无参构造和有参构造,类似于初始化函数。和Java使用方式是一样的,不赘述。

        当我们实例化一个对象后,会自动调用构造函数。

class Date
{
public:
	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}

	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
	void Print()
	{
		cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
		this->Fanacy();
	}

	void Fanacy()
	{
		cout << "hehe" << endl;
	}

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

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

        观察以下代码:

Date()
{
	_year = 1;
	_month = 1;
	_day = 1;
}

Date(int year, int month, int day)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}

        此时我们有两个构造函数,一个有参一个无参,并通过主函数这样调用:

int main()
{
	Date d1;
	Date d2(2, 3, 4);
	d1.Print();
	d2.Print();
	return 0;
}

        如果是无参的不要带括号,只是为了和函数声明区分开。 

Date d1;
Date d2(2, 3, 4);

Date d1();//函数声明

        构造函数一般喜欢写成全缺省函数。

Date(int year = 1, int month = 1, int day = 1)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}

        这样就可以把无参构造省略了,非常方便。 

        记住缺省函数定义和声明不能同时给,规定只能在声明的时候给,定义的时候不给。

        如果我们写了显示的默认成员函数,那么编译器则不会在生成默认成员函数,也是和Java一样,救急不救穷。

        编译器自动生成的构造函数,对于内置类型成员变量不做处理(也就是int了,double了等等基础类型),当然有些编译器会处理。

        不传参数就可以调用的函数就是默认构造。

        C++11为了解决初始化问题,我们可以在定义成员变量时给定缺省值。

class Date
{
public:
	void Print()
	{
		cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
	}

private:
	//给缺省值
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

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

 

        默认构造函数只能有一个。注意:无参构造函数、全缺省函数、编译器默认生成构造函数,都可以认为是默认构造函数。

        3个只能存在一个。

析构函数:

        析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作使用编译器完成的。而对象在销毁是会自动调用析构函数,完成对象中资源的清理工作。

        其也是一个特殊的成员函数,特征如下:

        析构函数名是在类前加上字符~;无参数无返回类型;一个类只能有一个析构函数。若未显示定义,系统会自动生成默认的析构函数。注意:析构函数不能重载;对象生命周期结束时,C++编译系统自动调用析构函数。

~Date()
{
	cout << "这是显示调用的析构函数!" << endl;
}

        析构函数我们也可以显示调用。 

d1.~Date();

        不是所有类都需要写析构函数,因为不需要释放空间。

        编译器默认的析构函数对内置类型不做处理,对自定义类型去调用它的析构函数。

拷贝构造:

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

        拷贝构造函数是构造函数的一个重载形式;拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

        若未显示定义,编译器会生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝或者值拷贝。

class A
{
public:
	A(int a = 100)
	{
		_a = a;
	}

	A(A& a)
	{
		_a = a._a;
		cout << "这里调用了拷贝构造!" << endl;
	}

	void Print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};

void func(A a)
{
	a.Print();
}

int main()
{
	A a1(5);
	func(a1);
	return 0;
}

        可以看到,我们并没有去调用任何的拷贝构造参数,但是调用了func函数之后却调用了。

        这是因为这是传值传参,自定义类型对象传值传参要调用拷贝构造。 除非传入指针或者使用引用才不会调用拷贝构造。

        这样就会引起死递归。所以要修改为引用: 

A(const A& a)
{
	_a = a._a;
	cout << "这里调用了拷贝构造!" << endl;
}

        我们一般习惯往里面写入const,是为了防止修改被拷贝的内容。

        这里相当于权限的缩小。

// 下面的两种写法是等价的
A a2(a1);
A a3 = a2; //这也是拷贝构造

        默认构造会实现浅拷贝,也就是不会拷贝引用类型。 默认构造会实现浅拷贝,也就是内置类型的拷贝。

总结:

        如果没有管理资源,一般不要写拷贝构造,默认生成的即可使用;如果都是自定义类型成员,内置类型成员没有指向资源,也类似默认生成的拷贝构造就可以(比如用栈实现队列);一般情况下,不需要显示写析构函数,就不需要写拷贝构造;如果内部有指针或者一些值指向资源,需要显示写析构,通常就需要显示写拷贝构造完成深拷贝。

赋值运算符重载函数: 

        赋值运算符重载是默认成员函数,不写编译器默认生成。用户没有显示实现时,会以值的方式逐字节拷贝。和拷贝构造函数类似。

        复制运算符重载不能写成全局函数,这是规定!

运算符重载:

        运算符重载:是具有特殊函数名的函数,也具有其返回值类型,函数名及参数和返回值与普通函数类似。

        函数名字为:关键字operator后面需要重载运算符符号。

class Date 
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	Date(Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

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

//private:
	//给缺省值
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

//大于
bool Compare1(const Date& d1, const Date& d2)
{
	if (d1._year > d2._year)
	{//年大就大
		return true;
	} 
	else if (d1._year == d2._year)
	{
		if (d1._month > d1._month)
		{//月大就大
			return true;
		}
		else if (d1._month == d2._month)
		{//天大就大
			return d1._day > d2._day;
		}
	}
}

//小于
bool Compare2(const Date& d1, const Date& d2)
{
	if (d1._year < d2._year)
	{//年小就小
		return true;
	}
	else if (d1._year == d2._year)
	{
		if (d1._month < d1._month)
		{//月小就小
			return true;
		}
		else if (d1._month == d2._month)
		{//天小就小
			return d1._day < d2._day;
		}
	}
}

//等于
bool Compare1(const Date& d1, const Date& d2)
{
	if (d1._day == d2._day && d1._year == d2._year && d1._month == d1._month)
	{
		return true;
	}
	return false;
}

int main()
{
	Date d1(2024, 4, 10);
	Date d2(2024, 4, 9);
	cout << Compare1(d1, d2) << endl;

	//cout << (d1 > d2) << endl;
	return 0;
}

        比如此时我对日期类进行比较,写了3个函数来实现,这样很麻烦,但是有操作符重载就会很方便。

cout << (d1 > d2) << endl;

        比如此时我们就像通过这样来完成这个比较方法。 

        重载操作符必须有一个类类型参数,也就是说不能这样写:

//运算符重载是函数,以下形式非法!
int operator-(int i, int j)

        .* :: sizefof  ? :  . 这5个运算符不能重载。 

//大于
bool operator>(const Date& d1, const Date& d2)
{
	if (d1._year > d2._year)
	{//年大就大
		return true;
	}
	else if (d1._year == d2._year)
	{
		if (d1._month > d1._month)
		{//月大就大
			return true;
		}
		else if (d1._month == d2._month)
		{//天大就大
			return d1._day > d2._day;
		}
	}
}

        之后可以直接这样使用:

cout << (d1 > d2) << endl;

        插一嘴,其中.*是一个运算符(蒙了吧,我也蒙了,解释一下)。

class OB
{
public:
	void func()
	{
		cout << "func:" << endl;
	}
};

//重命名函数指针
typedef void(OB::* Ptr)();//重命名

int main()
{
	//这里必须使用&
	Ptr fp = &OB::func;
	OB tmp;
	//此时也就用到了.*这个操作符
	(tmp.*fp)();//通过函数指针调用函数
	return 0;
}

        这里我们使用到了.*。

        一个类要重载哪些元素符是看需求。

class Date 
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	bool operator==(const Date& d)
	{
		return _day == d._day
			&& _year == d._year
			&& _month == d._month;
	}

private:
	//给缺省值
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

int main()
{
	Date d1(20, 1, 3);
	Date d2(20, 1, 4);
	//显示调用
	d1.operator==(d2);//这样就没有优势了

	//直接写,转换调用,编译器会转换为 operator==(d1, d2)
	d1 == d2;
	return 0;
}

        此时我们发现,我都是在类外定义的函数,也就意味着要把类中的成员变量都变为公有的才能这样写。 

        有3种解决方法:提供这些成员get和set方法;友元(后期讲);重载为成员函数。

        相信各位对get和set方法都了解,我们不再赘述。

class A
{
public:
	A(int a = 100)
	{
		_a = a;
	}

	A(const A& a)
	{
		_a = a._a;
		cout << "这里调用了拷贝构造!" << endl;
	}

	A operator=(const A& a)
	{//这里面最好加上返回值,这样就可以连续赋值并且不会出错
		_a = a._a;
		return *this;
	}

	void Print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};

int main()
{
	A a1(100);
	A a2;//拷贝一个
	A a3;

	a3 = a2 = a1;
	a3.Print();
	return 0;
}

        我们在使用操作符重载的时候,最好加上返回值,这样可以连续赋值不会出错。

注意事项:        

class Date 
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	Date(const Date& d)
	{
		cout << "这里调用了拷贝构造" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	bool operator==(const Date& d)
	{
		return _day == d._day
			&& _year == d._year
			&& _month == d._month;
	}

//private:
	//给缺省值
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

bool operator==(const Date& d1, const Date& d2)
{
	return d1._day == d2._day
		&& d1._year == d2._year
		&& d1._month == d2._month;
}

Date func()
{
	Date d;
	return d;
}

int main()
{
	Date d1(20, 1, 3);
	Date d2(20, 1, 4);
	func();
	
	return 0;
}

        这里注意我们调用了func函数,返回的是Date类,会去调用类中的拷贝构造!但是可以发现,执行结果并没有执行拷贝构造中的语句,这是为啥?

        但是确实会调用拷贝构造,是因为优化没有调用。

        编译器在某些情况下会对代码进行优化,以提高执行效率。其中之一就是返回值优化(Return Value Optimization,RVO)。RVO 是一种优化技术,它可以避免不必要的拷贝构造函数调用。
        在 func() 函数中,返回了一个局部对象 d。如果编译器启用了 RVO,它会直接将 d 放在函数调用者的位置,而不是创建临时副本。这样,拷贝构造函数就不会被调用。

        但是我们严谨一点,这只是编译器帮助了我们优化,此时我们如何才能让其不拷贝?就是返回引用。

Date& func()
{
	Date d;
	return d;
}

        传值返回是返回d的拷贝,引用返回是d的别名。

class Date 
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	Date(const Date& d)
	{
		cout << "这里调用了拷贝构造" << endl;
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	bool operator==(const Date& d)
	{
		return _day == d._day
			&& _year == d._year
			&& _month == d._month;
	}

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

	~Date()
	{
		cout << "调用了析构" << endl;
		_year = -1;
	}
//private:
	//给缺省值
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

bool operator==(const Date& d1, const Date& d2)
{
	return d1._day == d2._day
		&& d1._year == d2._year
		&& d1._month == d2._month;
}

Date& func()
{
	Date d;
	return d;
}

int main()
{
	Date& d3 = func();
	d3.Print();
	
	return 0;
}

        如果不用引用返回,返回的是d的拷贝,这里d有是临时拷贝,临时对象具有常性。 

Date& func()
{
	Date d(1022, 1, 3);
	return d;
}

int main()
{
	Date& d3 = func();
	d3.Print();
	return 0;
}

        再来观察以下代码:

Date& func()
{
	Date d(1022, 1, 3);
	return d;
}

int funcs()
{
	int a = 1;
	int b = 2;
	int c = 3;
	return a + b + c;
}

int main()
{
	Date& d3 = func();
	d3.Print();
	funcs();
	return 0;
}

        此时我们在调用一个函数,发现d3里面的值也已经改变,这是因为:

小结: 

        返回对象生命周期到了,会析构,传值返回。

        返回对象生命周期没到,不会析构,传引用返回。

        出了作用域,返回对象还没有析构,就可以用引用返回,减少拷贝。

         为了优化程序,我们一般对于类的返回使用的是引用返回。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

组件通信-props详解

目录 一、什么是prop 二、props校验 三、组件中prop和data的区别 一、什么是prop Prop定义&#xff1a;组件上注册的一些自定义属性。 Prop作用&#xff1a;向子组件传递数据。 特点&#xff1a; 可以传递任意数量的prop可以传递任意类型的prop 二、props校验 组件的pr…

智能化采购管理系统助力光伏行业提高效率

光伏行业是指太阳能电池板的制造、安装和维护等相关产业&#xff0c;是新能源领域的重要组成部分。近年来&#xff0c;随着全球对于环保和可持续发展的重视&#xff0c;光伏行业进入全球化和智能化的新阶段。光伏企业开始加强国际合作&#xff0c;推广智能化技术&#xff0c;提…

数据结构学习/复习11--二叉树分治与递归思想练习题

一、二叉树相关练习题 1.判断单值二叉树 2. 判断两颗树是否相同 3.先序遍历的实现 注意事项&#xff1a;此处中的数组的下标用指针控制&#xff0c;因为受到递归与函数栈帧创建与销毁的影响。最后的返回值是指向前序遍历排好后的数组指针 4.判断一棵树是否是另一棵树的子树 …

速来get!多微信聚合聊天功能大揭秘!

随着网络时代的发展&#xff0c;微信成为了职场中不可或缺的沟通工具&#xff0c;很多人都有着多个微信号&#xff0c;而要想高效管理这些账号&#xff0c;那就少不了工具的帮忙。 通过微信管理系统&#xff0c;可以轻松实现多个微信号聚合聊天&#xff0c;提高沟通效率。 1、…

电商风口的最后一班快车?有些人甚至正在All in视频号!

我是王路飞。 当抖音、快手、淘宝上的商家还在内卷的时候&#xff0c;有些人却转移了阵地&#xff0c;搭上了电商风口的“最后一般列车”&#xff0c;甚至正在All in 视频号。 内容来源于【醒醒团队-电商王路飞】 随着“微视”想要三分天下野心的失败&#xff08;与抖音、快手…

ansible 深入介绍之 主机清单与playbook

目录​​​​​​​ 一 inventory 主机清单 1&#xff0c;主机清单 是什么 2&#xff0c;主机清单 定义方式 2.1 自定义主机端口 2.2 定义 范围ip 地址 2.3 定义 拥有相似的主机名 3&#xff0c; inventory 中的变量 3.1 常见 变量 3.2 主机变量 3.3 组变量 3.…

c语言练习5.8

1.分析代码 VS开发环境调试下面的代码&#xff0c;画图解释下面代码的问题 #include <stdio.h> int main() {int i 0;int arr[] {1,2,3,4,5,6,7,8,9,10};for(i0; i<12; i){arr[i] 0;printf("hello bit\n");}return 0; } 分析: 2.喝汽水问题 喝汽水&a…

Python数据可视化------地图

基础地图使用 # 地图基本演示 # 导包 from pyecharts.charts import Map from pyecharts.options import TitleOpts, VisualMapOpts# 准备地图对象 cmap Map() # 准备数据&#xff08;列表&#xff09; data [("北京市", 99), ("上海市", 199), ("…

淘宝扭蛋机小程序,开启你的惊喜探索之旅!

亲爱的淘宝用户们&#xff0c;我们非常高兴地宣布&#xff0c;全新的淘宝扭蛋机小程序即将上线&#xff01;这是一款集合了趣味、惊喜与购物乐趣于一体的创新应用&#xff0c;让你在淘宝的海洋里&#xff0c;找到那份独特的快乐。 一、淘宝扭蛋机小程序是什么&#xff1f; 淘…

后端常用技能:解决java项目前后端传输数据中文出现乱码、问号问题

0. 问题背景 最近做一个解析数据的小工具&#xff0c;本地运行时都正常&#xff0c;发布到服务器上后在导出文件数据时发现中文全部变成了问号&#xff0c;特此记录下问题解决的思路和过程 1. 环境 java 1.8 springboot 2.6.13 额外引入了fastjson&#xff0c;commons-csv等…

Linux网络编程:TCP编程实现

目录 1、前言 2、函数介绍 2.1 socket函数 与 通信域 2.2 bind函数 与 通信结构体 2.2.1 domain通信地址族 与 通信结构体 2.2.2 IPv4地址族结构体 2.2.3 通用地址族结构体 2.2.4 示例&#xff1a;为套接字fd绑定通信结构体addr 2.3 listen函数 与 accept函数 …

onlyoffice容器打包成镜像

书接上篇&#xff0c;onlyoffice容器已经更改在本地docker环境中了&#xff0c;之后需要部署到测试环境的docker中&#xff0c;采用容器打包成本地镜像 1、本地docker 查看容器&#xff1a;docker ps 生成镜像&#xff1a;docker commit -p blissful_lichterman 重命名镜像&a…

MySql表的增删查改(CRUD)

对表中的数据操作分为4大类&#xff0c;增加数据&#xff0c;删除数据&#xff0c;查找数据&#xff0c;修改数据。对表中的数据进行增删查改操作简称为CRUD。Create(增),Retrieve(查找),Updata(修改&#xff09;,Delete(删除)CRUD的操作是对表中的数据进行操作的&#xff0c;是…

RTT PIN设备学习

获取GPIO编号 GET_PIN(port, pin)#define LED_BLUE_PIN GET_PIN(A, 0)设置引脚模式 void rt_pin_mode(rt_base_t pin, rt_base_t mode);设置引脚电平 void rt_pin_write(rt_base_t pin, rt_base_t value);rt_base_t pin 同上&#xff0c; 为引脚编号&#xff0c;尽量通过宏定…

c++ socket基于TCP

linux网络编程基础api socket 地址api&#xff1a;ip地址和端口对&#xff0c;成为 soccket 地址。 socket 基础api&#xff1a; sys/socket.h 中&#xff0c;包括创建、命名、监听 socket &#xff1b;接受连接、发起连接、读写数据、获取地址信息、检测带外标记、读取设置 s…

网络机顶盒哪个牌子好?经销商整理热门网络机顶盒排名

做实体数码店多年来&#xff0c;网络机顶盒这行我非常了解&#xff0c;各种品牌的网络机顶盒我们全销售过。近来很多朋友咨询我网络机顶盒哪个牌子好&#xff0c;我按照店内近一个季度的销量情况整理了是实体店最畅销的网络机顶盒排名&#xff0c;最受欢迎的品牌是以下这些&…

WM Shell多动画场景处理

Shell导致的内存泄漏 基本上都是某个动画未正常结束&#xff0c;执行时间太久导致后续动画堆积或被merge到异常动画导致相关Surface得不到释放导致的。 某个Transition执行时间太久导致后续动画堆积 Visible layers 中有1558 个Transition Root相关layer Visible layers (c…

卡牌——蓝桥杯十三届2022国赛大学B组真题

样例输入 4 5 1 2 3 4 5 5 5 5样例输出 3样例说明 这 5 张空白牌中,拿2张写1,拿1张写2,这样每种牌的牌数就变为了3,3,3,4, 可以凑出 3套牌,剩下2张空白牌不能再帮助小明凑出一套。 评测用例规模与约定 对于30%的数据&#xff0c;保证n ⩽ \leqslant ⩽ 2000; 对于100%的数据…

笔记85:如何计算递归算法的“时间复杂度”和空间复杂度?

先上公式&#xff1a; 递归算法的时间复杂度 递归次数 x 每次递归消耗的时间颗粒数递归算法的空间复杂度 递归深度 x 每次递归消耗的内存空间大小 注意&#xff1a; 时间复杂度指的是在执行这一段程序的时候&#xff0c;所花费的全部的时间&#xff0c;即时间的总和而空间复…

ORA-28575: unable to open RPC connection to external procedure agent

环境&#xff1a; Oracle 11.2.0.4x64 RAC AIX6.1版本SDE for aix oracle11g版本10.0 x64 sde配置情况如下&#xff1a; 检查oracle和grid用户下的$ORACLE_HOME/hs/admin/extproc.ora文件均包含有如下&#xff1a; SET EXTPROC_DLLSANY 两个节点sde下的user_libraries都正常…