C++类和对象篇

1.类的定义


在C语言结构体中,只能定义变量,C++扩展了类的概念,能够在类定义函数;同时,struct仍然可以使用,但更常用class来表示类

1.1类中函数的两种定义方式

  • 函数的声明和定义都在类中

    class Date
    {
    public:
    	void Init()
    	{
    		cout << _year << "-" << _month << "-" << _day << endl;
    	}
    
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
  • 函数的声明在.h文件中,定义在.cpp文件中,此时定义函数时必须指定类域

    //Date.h
    class Date
    {
    public:
    	void Init();
    
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    //Date.cpp
    void Date::Init()
    {
    	cout << _year << "-" << _month << "-" << _day << endl;
    }
    

2.访问限定符和封装


C++有三大访问限定符,分别是public、protected、private

  • 被public修饰的成员可以在类外直接被访问
  • 被protected和private修饰的成员只能在类中访问
  • struct的默认访问限定符是public,而class是private

通过访问限定符对成员进行修饰,想让外部访问的成员和不想让外部访问的成员,达到封装的效果

3. 类的作用域和实例化


3.1 作用域

在上篇文章中说到过,C++中有4种域:

  • 局部域
  • 全局域
  • 类域
  • 命名空间域

我们定义出来的类也是一种域,外部想要使用类中的成员,必须指定域

3.2 实例化

用类创建变量,叫做类的实例化;类的定义不会占用空间,只有实例化才会占用内存

3.3 类大小的计算

一个类中既有函数,又有变量,怎么计算一个类的大小呢?

//有成员函数和成员变量
class C1
{
	void Fun1() {}
	int _year;
};

//只有成员函数
class C2
{
	void Fun2() {};
};

//空类
class C3
{};

int main()
{
	cout << sizeof(C1) << endl;// 4
	cout << sizeof(C2) << endl;// 1
	cout << sizeof(C3) << endl;// 1

	return 0;
}

实际上,如果想调用类中的函数,没有必要再复制函数的内容,因为每次调用的函数都是同一份;因此,类中函数的地址存放在公共代码区;计算类大小时,只计算成员变量所占的大小,并且要符合结构体内存对齐规则

注意:空类占1byte,很多人好奇为什么不是0byte,因为得知道这个类是存在的,只是什么都没有,如果是0byte,连内存都不占,我怎么知道它存在

说到结构体内存对齐,这里再提一个小问题:为什么要内存对齐?

  1. 效率方面,由于硬件在设计时,一次只能读取4byte或8byte,内存对齐更有利于拿取内存中的数据

  2. 更主要的原因,是因为硬件在读取时,只能在对应类型的整数倍处读取,不能在任意地方读取

    在这里插入图片描述

class V
{
public:
	void Fun()
	{
		cout << "Fun()" << endl;
	}
};

int main()
{
	V v1;
	V* p1 = &v1;
	p1->Fun();//打印Fun()

	V* p2 = nullptr;
	p2->Fun();//打印Fun()

	return 0;
}

上面的代码中,p1访问类中的Fun()函数我们不难理解,但为什么p2明明是空指针,仍然能访问Fun()函数?

其实这个问题前面已经说过,是因为Fun函数在公共代码区;编译器首先会查找Fun()函数,既然它不在类中,那就没必要解引用了

4. this指针


4.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;
	Date d2;
	d1.Init(2024, 1, 27);
	d2.Init(2024, 2, 27);
	d1.Print();// 打印2024-1-27
	d2.Print();// 打印2024-2-27

	return 0;
}

上面的代码中,调用Init()函数时,编译器怎么知道应该是去初始化d1,而不是d2呢?

实际上,编译器默认给每个成员函数增加了一个隐式指针参数,在调用时也会默认增加一个指针,该指针指向目标的地址,这就是this指针

4.2 this指针的特性

  • 我们不能在形参或实参中显示this指针

  • 我们可以在成员函数内部使用this指针,如果不对成员变量加上this指针,编译器会默认帮我们加上

    void Print()
    {
    	cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
    }
    
  • 不能对this指针进行修改,因为this指针被const修饰

    Date* const this
    
  • this指针在哪?

    this指针在栈上,因为它实际上是一个形参,只不过传参和使用由编译器自动帮我们完成

class A1
{
public:
	void Print()
	{
		cout << "Print()" << endl;
	}

private:
	int _a;
};

class A2
{
public:
	void Print()
	{
		cout << _a << endl;
	}

private:
	int _a;
};

int main()
{
	A1* p1 = nullptr;
	A2* p2 = nullptr;
	p1->Print();// 正常打印
	p2->Print();// 程序崩溃
	return 0;
}

出现两种情况,第一种前面已经解释过;第二种,因为调用Print()函数时,编译器默认帮我们传了p2,在Print()函数中,_a实际上是this->_a,因为this位nullptr,所以发生了空指针的解引用,程序崩溃

5. 默认成员函数


一个类中,其实默认含有一系列函数,这些函数如果程序员自己不定义,编译器会自动帮我们定义;有了这些函数,我们可以更加方便写代码,这就叫默认成员函数,主要有六个成员函数

在这里插入图片描述

5.1 构造函数

相信大家都犯过这样的错误,用C语言实现栈时,忘记初始化栈导致程序运行错误;为了防止未初始化函数就直接使用这种情况,祖师爷引入了构造函数的概念

5.1.2 概念

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;
	Date d2;
	d1.Init(2024, 1, 27);
	d2.Init(2024, 2, 27);
	d1.Print();
	d2.Print();

	return 0;
}

拿日期函数举例,我们发现每次调用Init()函数都要自己手动初始化,显得比较麻烦,能不能在类对象实例化时就直接给我们初始化了呢?

构造函数是一个特殊的成员函数,名字和类相同,创建类对象时由编译器自动调用,确保每一个成员变量都有一个初始值

5.1.3 特性

  • 函数名与类名相同

  • 无返回值

  • 对象实例化时编译器自动调用

  • 可以重载

    class Date
    {
    public:
        //无参构造函数
    	Date(){}
    	
        //带参构造函数
    	Date(int year, int month, int day)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
    	
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    int main()
    {
    	Date d1;// 调用无参构造函数
    	Date d2(2024, 1, 27);// 调用带参构造函数
    
    	return 0;
    }
    //注意:如果是调用无参构造函数,不能写成【Date d1()】,因为这就和函数声明冲突了,编译器无法识别这到底是函数声明,还是调用无参构造函数
    
  • 如果类中没有显式定义构造函数,那么编译器会自动生成一个无参构造函数;而如果类中有显式构造函数,编译器就不会生成默认构造函数

  • 默认构造函数不会对内置类型进行初始化;而如果有自定义类型,会去调用自定义类型的构造函数

    class Date
    {
    private:
    	int _year;
    	int _month;
    	int _day;
    };
    
    int main()
    {
    	Date d1;
        //实例化之后,发现d1中的成员变量是随机值,也就是说默认构造函数没有做任何事情
    
    	return 0;
    }
    
    class Week
    {
    public:
    	Week()
    	{
    		_week = 0;
    	}
    private:
    	int _week;
    };
    
    class Date
    {
    private:
    	int _year;
    	int _month;
    	int _day;
    
    	Week _date;
    };
    
    int main()
    {
    	Date d1;
    
    	return 0;
    }
    //对于_date,编译器会去调用类Week中的构造函数Week()
    

    不管怎么看,构造函数的这个特性都不太对劲,我本来想让你帮我完成初始化的工作,结果你什么都没做,有点不太合理;因此C++11增加了新的规则,可以在成员变量声明时给默认值

    class Date
    {
    private:
    	int _year = 1;
    	int _month = 1;
    	int _day = 1;
    };
    
  • 无参构造函数、全缺省构造函数、编译器生成的构造参数,都可以叫做默认构造参数,且三个只能存在一个

    class Date
    {
    public:
    	Date() 
    	{
    		_year = 2024;
    		_month = 1;
    		_day = 27;
    	}
          
    	Date(int year = 2024, int month = 1, int day = 27)
    	{
    		_year = year;
    		_month = month;
    		_day = day;
    	}
          
    private:
    	int _year;
    	int _month;
    	int _day;
    };
          
    int main()
    {
    	Date d1;
          
    	return 0;
    }
    //编译器会报错,因为实例化d1时,没有指定数据,表明是调用默认构造函数,而类中有两个默认构造函数,编译器无法区分,因此会报错
    

5.2 析构函数

5.2.1 概念

析构函数是类中特殊的函数,当对象销毁时,他会自动帮我们完成内存清理的工作

5.2.2 特性

  • 析构函数的函数名是在类名前加上~

  • 无参数无返回值

  • 一个类只能有一个析构函数,若没有显式定义,则调用默认析构函数

  • 析构函数不能重载

  • 对象生命周期结束时,自动调用析构函数

    class Stack
    {
    public:
    	Stack(int capacity = 4)
    	{
    		_arr = (int*)malloc(sizeof(int) * capacity);
    		if (_arr == NULL)
    		{
    			perror("mallco fail");
    			return;
    		}
    		_size = 0;
    		_capacity = capacity;
    	}
    
    	void Push(int x)
    	{
    		//CheckCapacity();
    		_arr[_size++] = x;
    	}
    
    	void Pop()
    	{
    		assert(_size > 0);
    		_size--;
    	}
    
    	void Print()
    	{
    		for (int i = 0; i < _size; i++)
    		{
    			printf("%d\n", _arr[i]);
    		}
    	}
    
    	~Stack()
    	{
    		free(_arr);
    		_arr = NULL;
    		_size = _capacity = 0;
    	}
    
    private:
    	int* _arr;
    	int _size;
    	int _capacity;
    };
    
    int main()
    {
    	Stack s;
    	s.Push(1);
    	s.Push(2);
    	s.Print();
    	s.Pop();
    	s.Print();
    
    	return 0;
    }
    
  • 如果没有显式析构函数,编译器调用默认析构函数;默认析构函数会调用自定义类型成员中的析构函数

    class Time
    {
    public:
    	~Time()
    	{
    		cout << "Time()" << endl;
    	}
    
    private:
    	int _value = 1;
    };
    
    class Date
    {
    private:
    	int _year = 2024;
    	int _month = 1;
    	int _day = 27;
    	Time _t;
    };
    
    int main()
    {
    	Date d1;
    
    	return 0;
    }
    //Date类中的内置类型_year、_month、_day,在d1销毁时自己释放,不需要析构函数对其进行资源释放
    //对于自定义类型_t,d1在销毁前需要对其进行检查,是否进行资源释放,但main函数中不能直接访问Time类
    //因此Date类中编译器生成的默认析构函数会去调用Time类中的析构函数
    
  • 如果类中没有申请资源时,析构函数可以不写,由编译器自动生成;但如果有申请资源,需要程序员自己写好对应的析构函数

  • 程序结束时,析构函数的调用规则满足后定义的先析构:局部变量–>局部静态变量–>全局或全局静态变量

    class Date
    {
    public:
    	Date(int year = 1)
    	{
    		_year = year;
    	}
    
    	~Date()
    	{
    		cout << "Date()->" << _year << endl;
    	}
    
    private:
    	int _year;
    	int _month = 1;
    	int _day = 1;
    };
    
    Date d4(4);
    Date d5(5);
    static Date d6(6);
    
    void fun()
    {
    	Date d7(7);
    	static Date d9(9);
    	Date d8(8);
    }
    
    int main()
    {
    	fun();
    	Date d1(1);
    	Date d2(2);
    	static Date d3(3);
    
    	return 0;
    }
    //正确的析构顺序:8->7->2->1->3->9->6->5->4
    

5.3 拷贝构造函数

5.3.1 概念

拷贝构造函数是一种成员函数,完成一个对象的拷贝工作

5.3.2 特性

  • 拷贝构造函数是构造函数的一个重载形式

  • 拷贝构造函数只能有一个形参(用const修饰),且类型必须是类名的引用,如果类型是类名,会引发无穷递归的问题

    C++中规定,对类进行传值传参,首先得调用该类的拷贝构造函数在这里插入图片描述

由此会一直调用下去,所以拷贝构造函数的参数类型必须是类名引用类型;同时,为了防止修改掉原来的数据,最好加上const修饰

  • 如果拷贝构造函数没有显示定义,则编译器会默认生成拷贝构造函数;与构造函数不同,默认生成的拷贝构造函数对于内置类型会按字节顺序拷贝数据,对于自定义类型,会去调用它的拷贝构造函数;按字节顺序拷贝数据叫做浅拷贝

    class Time
    {
    public:
    	Time() = default;
    
    	// Date d2(d1)
    	Time(const Time& t)
    	{
    		_hour = t._hour;
    		_minute = t._minute;
    		_second = t._second;
    	}
    
    private:
    	int _hour = 1;
    	int _minute = 1;
    	int _second = 1;
    };
    
    class Date
    {
    private:
    	int _year = 2024;
    	int _month = 2;
    	int _day = 26;
    
    	Time _t;
    };
    
    int main()
    {
    	Date d1;
    	Date d2(d1);
    
    	return 0;
    }
    

拷贝构造函数与之前的成员函数不同,它会帮我们完成拷贝,那么是不是说就不需要我们写拷贝构造函数了呢?对于上面的日期类,好像是这样的,但如果换成栈类呢?

typedef int DataType;

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

	void Push(const DataType& data)
	{
		//CheckCapacity();
		_array[_top] = data;
		_top++;
	}

	~Stack()
	{
		free(_array);
		_array = nullptr;
		_top = _capacity = 0;
	}

private:
	DataType* _array;
	int _top;
	int _capacity;
};

int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	Stack s2(s1);

	return 0;
}
// 执行这段代码,我们发现程序崩了

经过调试,我们发现s2确实完成了s1的拷贝在这里插入图片描述

但仔细分析一下,s1中的array是我们自己申请的空间,程序在结束前,会去调用析构函数,释放掉s1中array的空间,而此时s2仍指向被释放掉的空间,这就出现了野指针的问题;下次释放s2时,对同一块空间释放了两次,因此程序会崩掉

由此总结,对于不需要申请空间的类,拷贝构造函数确实可以不写;而如果有申请空间,需要我们自己写好拷贝构造函数;而对于申请空间的拷贝我们叫做深拷贝

//需要我们自行完成拷贝构造函数
Stack(const Stack& s)
{
	_array = (DataType*)malloc(sizeof(DataType) * s._capacity);
	if (_array == nullptr)
	{
		perror("malloc fail");
		exit(-1);
	}
	memcpy(_array, s._array, sizeof(DataType) * s._top);
	_top = s._top;
	_capacity = s._capacity;
}

6. 运算符重载


为了代码的可读性,C++提供了对运算符赋予新的涵义的操作,也叫运算符重载

对于日期的比较,按照之前的思路写代码:

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

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

	bool CompareMore(const Date& d2)
	{
		if (_year > d2._year)
			return true;
		else if (_year == d2._year)
		{
			if (_month > d2._month)
				return true;
			else if (_month == d2._month)
			{
				if (_day > d2._day)
					return true;
			}
		}

		return false;
	}

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

int main()
{
	Date d1(2024, 2, 28);
	Date d2(2024, 2, 26);
	cout << d1.CompareEqual(d2) << endl;
	cout << d1.CompareMore(d2) << endl;

	return 0;
}

这样写能完成我们想要的结果,但在函数的命名上有些问题;有时我们并不能通过函数名就知道该函数是做什么的;我希望通过函数名就能知道该函数比较的是什么;C++能够使用operator+运算符对函数命名

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

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

	bool operator>(const Date& d2)
	{
		if (_year > d2._year)
			return true;
		else if (_year == d2._year)
		{
			if (_month > d2._month)
				return true;
			else if (_month == d2._month)
			{
				if (_day > d2._day)
					return true;
			}
		}

		return false;
	}

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

int main()
{
	Date d1(2024, 2, 28);
	Date d2(2024, 2, 26);

	//cout << d1.operator==(d2) << endl;
	//cout << d1.operator>(d2) << endl;

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

	return 0;
}
函数比较的是什么;C++能够使用operator+运算符对函数命名

```C++
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

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

	bool operator>(const Date& d2)
	{
		if (_year > d2._year)
			return true;
		else if (_year == d2._year)
		{
			if (_month > d2._month)
				return true;
			else if (_month == d2._month)
			{
				if (_day > d2._day)
					return true;
			}
		}

		return false;
	}

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

int main()
{
	Date d1(2024, 2, 28);
	Date d2(2024, 2, 26);

	//cout << d1.operator==(d2) << endl;
	//cout << d1.operator>(d2) << endl;

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

	return 0;
}

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

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

相关文章

Pytorch训练RCAN QAT超分模型

Pytorch训练RCAN QAT超分模型 版本信息测试步骤准备数据集创建容器生成文件列表创建文件列表的代码执行脚本,生成文件列表训练RCAN模型准备工作修改开源代码编写训练代码执行训练脚本可视化本文以RCAN超分模型为例,演示了QAT的训练过程,步骤如下: 先训练FP32模型再加载FP32训练…

Qt QWidget 简约美观的加载动画 第二季

&#x1f603; 第二季来啦 &#x1f603; 简约的加载动画,用于网络查询等耗时操作时给用户的提示. 这是最终效果: 一共只有三个文件,可以直接编译运行 //main.cpp #include "LoadingAnimWidget.h" #include <QApplication> #include <QVBoxLayout> #i…

LeetCode704. 二分查找(C++)

LeetCode704. 二分查找 题目链接代码 题目链接 https://leetcode.cn/problems/binary-search/description/ 代码 class Solution { public:int search(vector<int>& nums, int target) {int left 0;int right nums.size() - 1;while(left < right){int midd…

主机字节序与网络字节序

大端序和小端序 大端序&#xff08;Big Endian&#xff09;和小端序&#xff08;Little Endian&#xff09;是两种计算机存储数据的方式。 大端序指的是将数据的高位字节存储在内存的低地址处&#xff0c;而将低位字节存储在内存的高地址处。这类似于我们阅读多位数时从左往右…

1.0 RK3399项目开发实录-Ubuntu环境搭建(物联技术666)

1.下载Ubuntu所需的版本&#xff1a;Index of /releases 2.安装vmplayer:Download VMware Workstation Player | VMware 3.安装Ubuntu时&#xff0c;磁盘空间尽量大些&#xff0c;开发板系统包都比较大&#xff0c;避免存不下&#xff0c;建议空间100G。 关闭Ubuntu自动更新…

卡玛网● 46. 携带研究材料 ● 01背包问题,你该了解这些! 滚动数组 力扣● 416. 分割等和子集

开始背包问题&#xff0c;掌握0-1背包和完全背包即可&#xff0c;注&#xff1a;0-1背包是完全背包的基础。 0-1背包问题&#xff1a;有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求…

【C进阶】顺序表详解

文章目录 &#x1f4dd;线性表的概念&#x1f320; 顺序表&#x1f309;顺序表的概念 &#x1f320;声明--接口&#x1f309;启动&#x1f320;初始化&#x1f309;扩容&#x1f320;尾插&#x1f309; 打印&#x1f320;销毁&#x1f309; 尾删&#x1f320;头插&#x1f309;…

内存函数(C语言进阶)

目录 前言 1、memcpy 2、memmove 3、memcmp 4、memset 结语 前言 本篇介绍了C语言中的内存函数&#xff0c;内存函数&#xff0c;顾名思义就是处理内存的函数。 1、memcpy memcpy&#xff1a;内存拷贝函数。 相对于strcpy只能拷贝字符串来讲&#xff0c;memcpy能拷…

Mysql学习之事务日志undolog深入剖析

Undo log redo log 是事务持久性的保证&#xff0c;undo log是事务原子性的保证。在事务中更新数据的前置操作其实是要先写入一个undo log。 如何理解undo 日志&#xff1f; 事务需要保证原子性&#xff0c;也就是事务中的操作要么全部完成&#xff0c;要么什么也不做。但有时…

kitti数据显示

画出track_id publish_utils.py中 def publish_3dbox(box3d_pub, corners_3d_velos, types, track_ids):marker_array MarkerArray()for i, corners_3d_velo in enumerate(corners_3d_velos):marker Marker()marker.header.frame_id FRAME_IDmarker.header.stamp rospy.T…

kubernetes的网络flannel与caclio

flannel网络 跨主机通信的一个解决方案是Flannel&#xff0c;由CoreOS推出&#xff0c;支持3种实现&#xff1a;UDP、VXLAN、host-gw udp模式&#xff1a;使用设备flannel.0进行封包解包&#xff0c;不是内核原生支持&#xff0c;上下文切换较大&#xff0c;性能非常差 vxlan模…

golang学习3,golang 项目中配置gin的web框架

1.go 初始化 mod文件 go mod init gin-ranking 2.gin的crm框架 go get -u github.com/gin-gonic/gin 3.go.mod爆红解决

五种多目标优化算法(MOFA、NSWOA、MOJS、MOAHA、MOPSO)性能对比(提供MATLAB代码)

一、5种多目标优化算法简介 多目标优化算法是用于解决具有多个目标函数的优化问题的一类算法。其求解流程通常包括以下几个步骤&#xff1a; 1. 定义问题&#xff1a;首先需要明确问题的目标函数和约束条件。多目标优化问题通常涉及多个目标函数&#xff0c;这些目标函数可能…

LeetCode刷题---从中序与后序遍历序列构造二叉树

解题思路: 首先还是定义哈希表将中序遍历的数插入进去&#xff0c;方便后序查阅 创建递归方法buildTreeNew(中序遍历数组&#xff0c;后序遍历数组&#xff0c;左或右子树在中序遍历数组中的起始和终止节点索引&#xff0c;左或右子树在后序遍历数组中的起始和终止节点索引) 后…

ThreadLocal从使用到实现原理与源码详解

ThreadLocal概述 ThreadLocal是多线程中对于解决线程安全的一个操作类&#xff0c;它会为每个线程都分配一个独立的线程副本从而解决了变量并发访问冲突的问题。ThreadLocal 同时实现了线程内的资源共享。 案例&#xff1a;使用JDBC操作数据库时&#xff0c;会将每一个线程的…

数据库系统概论(超详解!!!) 第一节 绪论

1.四个基本概念 1.数据&#xff08;Data&#xff09; 数据&#xff08;Data&#xff09;是数据库中存储的基本对象 数据的定义&#xff1a;描述事物的符号记录 数据的种类&#xff1a;数字、文字、图形、图像、音频、视频、学生的档案记录等 数据的含义称为数据的语义&…

第三百六十七回

文章目录 1. 概念介绍2. 方法与细节2.1 获取方法2.2 使用细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取当前系统语言"相关的内容&#xff0c;本章回中将介绍如何获取时间戳.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本章…

HCIA-Datacom实验指导手册:5.1 实验一:FTP SFTP TFTP 基础配置实验

HCIA-Datacom实验指导手册&#xff1a;5.1 实验一&#xff1a;FTP 基础配置实验 一、实验介绍&#xff1a;二、实验拓扑&#xff1a;三、实验目的&#xff1a;四、配置步骤&#xff1a;步骤 1 设备基础配置步骤 2 在 Router 上配置 FTP 和SFTP服务器功能及参数步骤 3 配置本地 …

MySQL数据库基础(十五):PyMySQL使用介绍

文章目录 PyMySQL使用介绍 一、为什么要学习PyMySQL 二、安装PyMySQL模块 三、PyMySQL的使用 1、导入 pymysql 包 2、创建连接对象 3、获取游标对象 4、pymysql完成数据的查询操作 5、pymysql完成对数据的增删改 PyMySQL使用介绍 提前安装MySQL数据库&#xff08;可以…

js里面有引用传递吗?

一&#xff1a;什么是引用传递 引用传递是相对于值传递的。那什么是值传递呢&#xff1f;值传递就是在传递过程中再复制一份&#xff0c;然后再赋值给变量&#xff0c;例如&#xff1a; let a 2; let b a;在这个代码中&#xff0c;let b a; 就是一个值传递&#xff0c;首先…