C++知识点总结:2.类和对象(自用)

类和对象

  • 1. 类和对象的关系
  • 2. 对象指针
  • 3. 在堆上创建对象
  • 4. 成员访问限定符
  • 5. 名字编码(Name Mangling)
  • 6.构造函数
  • 7.构造函数的重载
  • 8.初始化列表
  • 8. 成员变量初始化的顺序(通过初始化列表)
  • 9. 初始化 const 成员变量
  • 10. 析构函数
  • 11. 析构函数的执行时机!!
  • 12. 对象数组及其初始化
  • 12. 成员对象和封闭类
  • 13. 成员对象的初始化和析构顺序
  • 14. this 指针
  • 15. static静态成员变量
  • 16. static静态成员函数和普通成员函数的区别
  • 17. const成员变量和const成员函数
  • 18. const在函数的位置区别。
  • 18. const对象(常对象)
  • 19. 友元函数和友元类(friend关键字)
  • 20. string类
  • 21. 附录总结


引用:
[1]C语言中文网


1. 类和对象的关系

类是一种复杂数据类型的声明,并不占用内存空间。对象是类实例化后的具体实例,是类这个数据类型的一个变量,占用内存空间

类的定义(声明)不占用内存空间,所以在定义类时不能对成员变量进行初始化,因为没有地方存储数据。只有在创建对象以后才会给成员变量分配内存,这个时候就可以赋值了。

类名的首字母一般大写

类定义的最后有一个分号";",它是类定义的一部分,表示类定义结束了,不能省略。

除了创建单个对象,还可以创建对象数组:

class Student {int age;char *name;
};Student liyi; //创建单个对象
Student class_51[100]; //创建对象数组
liyi.age = 18; //创建对象以后才会给成员变量分配内存
liyi.name = 'liyi';

2. 对象指针

可以创建对象指针指向实例化后的对象。具体方法如下:

Student liyi; //创建单个对象
Student *pstu = &liyi;

3. 在堆上创建对象

知识点前提:栈区是程序自动管理的,不需要人为的释放内存。堆区是程序员自己管理的,必须自行释放内存。即,new和delete必须成对出现。

Student liyi; //在栈区实例化对象
Student *pstu = new Student; //在堆区实例化对象

我们在栈区创建的对象是有名字,即liyi。我们可以通过liyi这个对象名直接访问到对应的数据。所以,一般没必要用对象指针指向它。但是new操作符所创建的对象在堆区,返回的是一个指针,没有名字(简单来说就是,new创建的对象是匿名的)。如果没有对应的对象指针进行接收,则该对象无法访问了。

对象指针后,可以通过箭头->来访问对象的成员变量和成员函数。

通过对象名字访问成员使用点号.,通过对象指针访问成员使用箭头->。

4. 成员访问限定符

public: 类内可以访问,类外可以访问。
private:类内可以访问,类外不可以通过对象访问。
protected:类内可以访问,类外不可以通过对象访问,但是在它的派生类内部可以访问。

如果既不写 private 也不写 public,就默认为 private。

5. 名字编码(Name Mangling)

前提知识:C++对于对象进行分配内存时,只分配成员变量的内存。
不同对象的成员函数代码相同,所以不同对象分别分配自己的成员变量,同时共享成员函数代码。截图来自C语言中文网。在这里插入图片描述

那么如何确定每个对象自己的成员函数代码呢。这就需要借助C++编译器的名字编码。C++在每次编译的时候,会根据所属类名,命名空间,参数列表等不同对成员函数名进行重新编码。

在这里插入图片描述

6.构造函数

  • 构造函数会在创建对象时自动调用,不需要用户显式调用(用户也不能调用)。如果用户没有创建,则编译器会自动创建构造函数。一旦用户自己定义了构造函数,编译器则不会自动生成。
  • 构造函数必须是public属性,其他属性虽然不会报错,但是创建的构造函数没有意义。
  • 构造函数没有返回值,所以函数声明前不能有任何数据类型,并且函数体中不能有 return 语句。
  • 构造函数在实际开发中往往用来做一些初始化工作

7.构造函数的重载

构造函数是必须调用的,在创建对象的时候,必定会执行一个构造函数。如果构造函数重载,则必须有一组参数列表和其中一个构造函数相匹配。

8.初始化列表

class Student{
private:char* m_name;int m_age;
public:// 初始化列表方法:Student(char* name, int age):m_name(name), m_age(age){}//等价于Student(char* name, int age){ m_name = name; m_age=age;}
}

使用构造函数初始化列表并没有效率上的优势,仅仅是书写方便。

8. 成员变量初始化的顺序(通过初始化列表)

成员变量的初始化顺序与初始化列表中列出的变量的顺序无关,它只与成员变量在类中声明的顺序有关。

class Student{
private:int m_age;int m_age2;
public:Student(int age):m_age2(age), m_age(m_age2){}//错误理解:Student(int age){ m_age2= age; m_age=m_age2;}//正确理解:Student(int age){ m_age= m_age2; m_age2=age;}
}

在这里插入图片描述顺序修改后:
在这里插入图片描述
所以,尽量按照成员变量的声明的顺序进行初始化。

9. 初始化 const 成员变量

初始化 const 成员变量的唯一方法就是使用初始化列表。

错误方法:
在这里插入图片描述

10. 析构函数

  • 析构函数会在销毁对象时自动调用,不需要用户显式调用(用户也不能调用)。如果用户没有创建,则编译器会自动创建构造函数。析构函数是唯一的,不能重载!!!
  • 析构函数必须是public属性,其他属性虽然不会报错,但是创建的析构函数没有意义。
  • 析构函数没有返回值,所以函数声明前不能有任何数据类型,并且函数体中不能有 return 语句。
  • 析构函数在实际开发中往往用来做一些销毁内存(new,malloc创建的堆区变量,关闭文件)

示例:
在这里插入图片描述

11. 析构函数的执行时机!!

  • 在函数外创建的对象,是全局对象,类似于全局变量。数据存储在全局数据区,当全局作用域结束后,程序自动销毁存储在全局数据区的对象,调用其析构函数。
  • 在函数中创建的对象,是局部对象,类似于局部变量。数据存储在栈区,当函数结束后,程序自动销毁存储在栈区的对象,调用其析构函数。
  • 通过new创建的对象,也是局部对象,但是其存储在堆区,由程序员自动管理如果没有delete操作,则程序结束也不会调用其析构函数。所以,new申请的对象内存,一定要delete进行删除。
  • 析构遵循,先构造的后析构原则。

举例如下:
在这里插入图片描述

12. 对象数组及其初始化

对象数组的初始化,如果只有一个参数,可以隐式调用。如果由多个参数则应该显式调用

举例:

class Student{
private:char* m_name;int m_age;
public:// 没有参数Student():m_name("Null"),m_age(0){cout<<" construct m_name is "<< m_name << ", m_age is "<<m_age<<endl;}// 只有一个参数Student(char* name):m_name(name),m_age(0){cout<<" construct m_name is "<< m_name << ", m_age is "<<m_age<<endl;}// 两个参数(可类比多个)Student(char* name, int age):m_name(name), m_age(age){cout<<" construct m_name is "<< m_name << ", m_age is "<<m_age<<endl;}~Student(){cout<<" destruct m_name is "<< m_name << ", m_age is "<<m_age<<endl;}
};int main(){// 如果不给参数,默认调用Student()Student stu[2] = {}; // 如果只有一个参数,则可以隐式的直接给参数,例如"only_one_params"。Student stu2[2] = {"only_one_params"};// 第一个是隐式调用,第二个是默认构造(也是隐式)// 如果只有两个参数(多个),则需要显示调用,例如Student("only_two_params", 2)。Student stu3[2] = {"only_one_params", Student("only_two_params", 2)}; // 第二个就是显示调用。return 0;
}

在这里插入图片描述
注意:
如果是对象指针数组,则必须显示调用,并且创建几个对象就是几个对象。少的那个没有初始化,其指针值是随机的。

举例:

    Student* stu4[3] = {new Student("only_one_params"),new Student("only_two_params", 2),};

同时也可以验证之前的观点,new创建的对象,如果没有delete则不会进行析构。

12. 成员对象和封闭类

  • 当类中的成员变量是对象时,被称为成员对象。
  • 包含成员对象的类叫封闭类。

13. 成员对象的初始化和析构顺序

当封闭类创建对象时,需要先创建成员对象。对于成员对象的初始化,需要借助封闭类的构造函数初始化列表方法

特殊情况,当封闭类的构造函数没有对成员对象进行初始化时,如果成员对象有无参数的构造函数。则会通过无参数的构造函数进行初始化,如果有参数,则会报错。因此,封闭类必须对成员对象进行初始化。

成员对象的构造和析构,遵循先构造后析构的原则。即,先对成员对象进行构造,再对封闭类对象进行构造。先对封闭类对象进行析构,再对成员对象进行析构。

举例:

class Age{
private:int m_age;
public://无参数的构造函数Age():m_age(0){cout<<" construct Age , m_age is "<<m_age<<endl;}Age(int age):m_age(age){cout<<" construct Age, m_age is "<<m_age<<endl;}~Age(){cout<<" destruct Age, m_age is "<<m_age<<endl;}
};class Name{
private:char* m_family_name;char* m_last_name;
public:Name(char* f_name, char* l_name):m_family_name(f_name), m_last_name(l_name){cout<<" construct is "<< m_family_name<<" " << m_last_name <<endl;}~Name(){cout<<" destruct is "<< m_family_name<<" " << m_last_name <<endl;}
};// 封闭类
class Student{
private:// 成员对象Name m_c_name;Age m_c_age;
public:// 初始化构建Age类和Name类的成员对象。Student(char* f_name, char* l_name, int age):m_c_name(f_name, l_name), m_c_age(age){cout<<" construct Student is Class"<<endl;};// 测试是否调用Age类中无参数构造函数的成员对象Student(char* f_name, char* l_name):m_c_name(f_name, l_name){cout<<" construct Student is Class"<<endl;};~Student(){cout<<" destruct Student is Class"<<endl;}
};int main(){Student stu("li", "si", 22);
//    Student stu2("zhang", "san"); return 0;
}

从结果看,可以发现先通过构造函数创建成员对象m_c_name和成员对象m_c_age(顺序是成员对象声明顺序和初始化列表顺序无关),然后再通过封闭类构造函数创建对象stu。析构时的顺序先是封闭类析构函数,再是成员类析构函数。遵循先构造后析构原则。
(成员类析构函数顺序也是先构造后析构)
在这里插入图片描述

 Student stu2("zhang", "san"); //会调用无参数的构造函数

在这里插入图片描述

14. this 指针

this指针是一个const 指针,指向当前对象,且作用域范围是在成员函数内部。调用方法为"->"

注意:

  • this 是 const 指针,它的值是不能被修改的。
  • this 只能在成员函数内部使用。
  • 只有当对象被创建后 this 才有意义,因此不能在 static 成员函数中使用。
  • this 实际上是成员函数的一个隐式形参

15. static静态成员变量

不同对象之间成员变量相互独立。但是有时想要多个对象共享一个成员变量,此时就可以通过静态成员变量来实现。静态成员变量是一种特殊的成员变量,它被关键字static修饰

静态成员变量在类内声明,属于类,不属于对象。

static 成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。反过来说,没有在类外初始化的 static 成员变量不能使用。


初始化:

  • static 成员变量必须在类声明的外部初始化
  • 静态成员变量在初始化时不能再加 static,但必须要有数据类型
  • static 成员变量不占用对象的内存,而是在所有对象之外开辟内存,即使不创建对象也可以访问。

static 成员变量和普通的 static 变量类似,都在内存分区中的全局数据区分配内存,到程序结束时才释放。

初始化时可以赋初值,也可以不赋值。如果不赋值,那么会被默认初始化为 0。全局数据区的变量都有默认的初始值 0,而动态数据区(堆区、栈区)变量的默认值是不确定的,一般认为是垃圾值。[1]

静态成员变量既可以通过对象名访问,也可以通过类名访问

举例:

class Student{
private:char* m_name;int m_age;
public:static int m_num;
public:// 初始化构建Age类和Name类的成员对象。Student(char* name, int age):m_name(name), m_age(age){m_num ++;};~Student(){}void show();
};void Student::show(){cout << "class num is "<<m_num<<endl;
}// 在类外对静态成员变量进行初始化。该数据存储在全局数据区,程序结束自动销毁。
int Student::m_num = 0;int main(){// 通过对象调用。(new Student("zhangsan", 20))->show();(new Student("lisi", 18))->show();(new Student("wangwu", 22))->show();//直接通过类名直接调用。cout << "check class num by class name. the num is "<<Student::m_num<<endl;return 0;
}
/*
输出:
class num is 1
class num is 2
class num is 3
check class num by class name. the num is 3
*/

16. static静态成员函数和普通成员函数的区别

静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量静态成员函数)。

类似于python中的@staticmethod修饰的成员函数,其中没有self变量。

17. const成员变量和const成员函数

const成员变量只能通过初始化列表进行初始化,这点在第9点说过。

const成员函数可以访问类中所有的成员变量,但是不能修改它们的值。目的是为了保护数据。

方法是在成员函数头的尾部加上const关键字。

举例:

class Student{
private:char* m_name;int m_age;
public:
// 声明时函数头后加const关键字int getAge() const;
public:Student(char* name, int age):m_name(name), m_age(age){};~Student(){}
};// 定义时,函数头后也加const关键字
int Student::getAge() const{return m_age;
}int main(){Student stu("zhaoliu", 25);int num = stu.getAge();cout << "check class num by class name. the num is "<<num<<endl;return 0;
}

const成员函数不能修改内部的成员变量。如下图:
在这里插入图片描述

18. const在函数的位置区别。

  • 函数开头的 const 用来修饰函数的返回值,表示返回值是 const 类型,也就是不能被修改,例如const char * getname()。
  • 函数头部的结尾加上 const 表示常成员函数,这种函数只能读取成员变量的值,而不能修改成员变量的值,例如char * getname() const。

18. const对象(常对象)

如果对象被const修饰,则被称为常对象。在常对象中,只能使用const成员变量和const成员函数。

19. 友元函数和友元类(friend关键字)

当外部函数想要访问一个类中的private修饰的成员变量和成员函数时,可以借助friend关键字进行修饰,如果修饰的函数,则是友元函数,如果修饰的是类,则是友元类(友元类中所有的成员函数都是友元函数。)

  • 友元函数可以类外的函数(全局函数),也可以是类内的成员函数
  • friend关键字一定在类内。其声明的函数或者类,称为友元函数和友元类,可以访问该类中的所有成员变量。
  • friend修饰的函数,一定要有对象,对象指针或者对象引用。类比于this指针,友元函数和友元类中的成员函数,都需要借助对象对该类的private成员进行访问。
  • 友元函数和友元类是单向的不是双向的,例如B是A的友元类,可以访问A中所有成员变量。但是A不是B的友元类。
  • 友元函数和友元类不可传递,例如B是A的友元类,A是C的友元类,但是B不是C的友元类。

全局函数:

class Student{
private:char* m_name;int m_age;
public:Student(char* name, int age):m_name(name), m_age(age){};~Student(){}// 第二步:声明为Student类的友元函数,我们要访问Student类,就把friend定义到Student类中。friend void show(Student * ptu);
};//类外的全局函数想要访问Student类中的私有成员变量。
//第一步:参数需要有对象、对象指针或者对象引用
void show(Student * ptu){cout<< "this student name is "<< ptu->m_name << "  , age is "<<ptu->m_age<<endl;
}int main(){Student stu("zhaoliu", 25);// 直接调用全局函数show(),并把对象传进去。show(&stu);return 0;
}
/*
输出:
this student name is zhaoliu  , age is 25
*/

类内的成员函数:

class Student; // 提前声明,不然void show(Student * ptu);中Student未定义。class Test{//类内的成员函数想要访问Student类中的私有成员变量。//第一步:参数需要有对象、对象指针或者对象引用
public:void show(Student * ptu);
};class Student{
private:char* m_name;int m_age;
public:Student(char* name, int age):m_name(name), m_age(age){};~Student(){}// 第二步:声明为Student类的友元函数,我们要访问Student类,就把friend定义到Student类中。friend void Test::show(Student * ptu);
};void Test::show(Student * ptu){cout<< "this student name is "<< ptu->m_name << "  , age is "<<ptu->m_age<<endl;
}int main(){Student stu("zhaoliu", 25);// 直接调用全局函数show(),并把对象传进去。Test test;test.show(&stu);return 0;
}
/*
输出:
this student name is zhaoliu  , age is 25
*/

友元类:

// 除了friend void Test::show(Student * ptu);改为 friend Test;
// 其他把和类内成员函数声明为友元函数一样
class Student{
private:char* m_name;int m_age;
public:Student(char* name, int age):m_name(name), m_age(age){};~Student(){}// 第二步:声明为Student类的友元类,我们要访问Student类,就把friend定义到Student类中。friend Test;
};void Test::show(Student * ptu){cout<< "this student name is "<< ptu->m_name << "  , age is "<<ptu->m_age<<endl;
}

除非有必要,一般不建议把整个类声明为友元类,而只将某些成员函数声明为友元函数,这样更安全一些。

20. string类

  • 相比C语言中的字符串,string类对象声明的字符串数据,末尾不包括’\0’。
  • string类可以直接用 “=”进行赋值。
  • string类中有length()函数,该函数直接返回字符串的长度,因为末尾没有’\0’,所以返回的也是真是字符串长度。
  • string 类可以使用+或+=运算符来直接拼接字符串,不需要使用C语言中的 strcat()、strcpy()、malloc() 等函数来拼接字符串了,也不用担心空间不够会溢出。
  • string类转化为c语言的字符串,可以通过 “.c_str()”来实现。

string类的增上改查:

  • 插入字符串:
int main(){string s1, s2;s1 = "1234567890";s2 = "aaa";s1.insert(2, s2);//第一个是字符串下表,第二个是插入的字符或字符串cout<< s1 <<endl;return 0;
}
/*
输出:12aaa34567890
*/
  • 删除字符串:
int main(){string s1;s1 = "1234567890";s1.erase(5);// 第二个参数如果不指定,则从第一个下标(包含)后到末尾全删除cout<< s1 <<endl;s1.erase(2, 1); // 第一个是字符串下标,第二个是要删除几个字符。cout<< s1 <<endl;return 0;
}
/*
输出:
12345
1245
*/
  • 提取子字符串
int main(){string s1, s2;s1 = "1234567890";s2= s1.substr(5, 2);// 第一个是字符串下标,第二个是从下标开始(包含)提取多少个字符cout<< s2 <<endl;return 0;
}
/*
输出:
67
*/
  • 字符串查找
int main(){string s1, s2;s1 = "1234567890";s2 = "567";int index= s1.find(s2, 2); // 第一个参数是需要查找的子字符串,第二个参数是从第几个字符开始查,如果不指定则从第0个字符开始查。cout<< index <<endl;return 0;
}
/*
输出:
4
*/

还有其他两个查找函数:
rfind()函数:在find函数中,第二个参数表示从该参数下标开始查,而rfind函数则是从0字符查到第二个参数的下标。如果查不到返回-1

int main(){string s1, s2;s1 = "1234567890";s2 = "567";int index= s1.find(s2, 2);cout<< index <<endl;int index2= s1.rfind(s2, 2);cout<< index2 <<endl;int index3= s1.rfind(s2, 6);cout<< index3 <<endl;return 0;
}
/*
输出:
4
-1
4
*/

find_first_of() 函数:find_first_of() 函数用于查找子字符串和字符串共同具有的字符在字符串中首次出现的位置。

int main(){string s1, s2;s1 = "123 234 345";s2 = "a32";int index= s1.find_first_of(s2);cout<< index <<endl;return 0;
}
/*
输出:
1
*/

s1和s2共有的字符有“3”和“2”,在这两个中,首次出现下标是1。

21. 附录总结

该总结引用自[1]C语言中文网,如果想学习更详细的内容,可以去该网址学习。

  • 类的成员有成员变量和成员函数两种。

  • 成员函数之间可以互相调用,成员函数内部可以访问成员变量。

  • 私有成员只能在类的成员函数内部访问。默认情况下,class 类的成员是私有的,struct 类的成员是公有的。

  • 可以用“对象名.成员名”、“引用名.成员名”、“对象指针->成员名”的方法访问对象的成员变量或调用成员函数。成员函数被调用时,可以用上述三种方法指定函数是作用在哪个对象上的。

  • 对象所占用的存储空间的大小等于各成员变量所占用的存储空间的大小之和(如果不考虑成员变量对齐问题的话)。

  • 定义类时,如果一个构造函数都不写,则编译器自动生成默认(无参)构造函数和复制构造函数。如果编写了构造函数,则编译器不自动生成默认构造函数。一个类不一定会有默认构造函数,但一定会有复制构造函数。

  • 任何生成对象的语句都要说明对象是用哪个构造函数初始化的。即便定义对象数组,也要对数组中的每个元素如何初始化进行说明。如果不说明,则编译器认为对象是用默认构造函数或参数全部可以省略的构造函数初始化。在这种情况下,如果类没有默认构造函数或参数全部可以省略的构造函数,则编译出错。

  • 对象在消亡时会调用析构函数。

  • 每个对象有各自的一份普通成员变量,但是静态成员变量只有一份,被所有对象所共享。静态成员函数不具体作用于某个对象。即便对象不存在,也可以访问类的静态成员。静态成员函数内部不能访问非静态成员变量,也不能调用非静态成员函数。

  • 常量对象上面不能执行非常量成员函数,只能执行常量成员函数。

  • 包含成员对象的类叫封闭类。任何能够生成封闭类对象的语句,都要说明对象中包含的成员对象是如何初始化的。如果不说明,则编译器认为成员对象是用默认构造函数或参数全部可以省略的构造函数初始化。

  • 在封闭类的构造函数的初始化列表中可以说明成员对象如何初始化。封闭类对象生成时,先执行成员对象的构造函数,再执行自身的构造函数;封闭类对象消亡时,先执行自身的析构函数,再执行成员对象的析构函数。

  • const 成员和引用成员必须在构造函数的初始化列表中初始化,此后值不可修改。

  • 友元分为友元函数和友元类。友元关系不能传递。

  • 成员函数中出现的 this 指针,就是指向成员函数所作用的对象的指针。因此,静态成员函数内部不能出现 this 指针。成员函数实际上的参数个数比表面上看到的多一个,多出来的参数就是 this 指针。

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

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

相关文章

【机器学习】pytorch 常用函数解析

目录 一、基本函数介绍 1.1 nn.Module 类 1.2 nn.Embedding 1.3 nn.LSTM 1.4 nn.Linear 1.5 nn.CrossEntropyLoss 1.6 torch.save 1.7 torch.load 1.8 nn.functional 1.9 nn.functional.softmax 本文主要对 pytorch 中用到的函数进行介绍&#xff0c;本文会不断更新~…

C语言内存函数精讲

目录 引言 1.内存分配函数malloc 2.内存释放函数free 3.内存拷贝函数memcpy 4.内存移动函数memmove 5.内存设置函数memset 6.内存比较函数memcmp 总结 引言 在C语言编程中&#xff0c;内存管理是核心技能之一。C语言提供了一系列内存操作函数&#xff0c;这些函数在动…

jmeter-beanshell学习-try处理异常

有时候代码执行过程中&#xff0c;出现一些不能处理的情况&#xff0c;就会报错&#xff0c;还影响之后的代码执行&#xff0c;就需要跳过异常。 上面这情况报错了&#xff0c;还影响了下面的打印。beanshell用try和catch处理异常&#xff0c;下面是try的用法&#xff0c;和if有…

技术守护尊严||Chat GPT在抵抗性骚扰的作用分析

就在本周&#xff0c;中国人民大学女博士实名举报导师性骚扰的事情&#xff0c;引发全网关注&#xff01; 性骚扰&#xff0c;无论在线上还是线下&#xff0c;无论在职场还是校园&#xff0c;都是对个人尊严与权益的严重侵犯。 幸运的是&#xff0c;随着人工智能技术的飞速发…

优化冗余代码:提升前端项目开发效率的实用方法

目录 前言代码复用与组件化模块化开发与代码分割工具辅助与自动化结束语 前言 在前端开发中&#xff0c;我们常常会遇到代码冗余的问题&#xff0c;这不仅增加了代码量&#xff0c;还影响了项目的可维护性和开发效率。还有就是有时候会接到紧急业务需求&#xff0c;要求立马完…

[网络通信原理]——TCP/IP模型—网络层

网络层 网络层概述 网络层位于OSI模型的第三层&#xff0c;它定义网络设备的逻辑地址&#xff0c;也就是我们说的IP地址&#xff0c;能够在不同的网段之间选择最佳数据转发路径。在网络层中有许多协议&#xff0c;其中主要的协议是IP协议。 IP数据包格式 IP数据报是可变长度…

《最新出炉》系列入门篇-Python+Playwright自动化测试-55- 上传文件 (非input控件)- 中篇

软件测试微信群&#xff1a;https://bbs.csdn.net/topics/618423372 有兴趣的可以扫码加入 1.简介 在实际工作中&#xff0c;我们进行web自动化的时候&#xff0c;文件上传是很常见的操作&#xff0c;例如上传用户头像&#xff0c;上传身份证信息等。所以宏哥打算按上传文件…

Java从入门到精通(十二)~ 动态代理

晚上好&#xff0c;愿这深深的夜色给你带来安宁&#xff0c;让温馨的夜晚抚平你一天的疲惫&#xff0c;美好的梦想在这个寂静的夜晚悄悄成长。 文章目录 目录 前言 主要作用和功能&#xff1a; 应用场景&#xff1a; 二、代理概念 1.静态代理 2.动态代理 2.1 概念介绍 …

网址导航系统PHP源码分享

1、采用光年全新v5模板开发后台 2、后台内置8款主题色&#xff0c;分别是简约白、炫光绿、渐变紫、活力橙、少女粉、少女紫、科幻蓝、护眼黑 3、可管理无数引导页主题并且主题内可以进行不同的自定义设置&#xff0c;目前内置16套主题 持续增加中… 4、可单独开发各种插件&a…

OSPF Type2 Message / DBD Packet (Database Descriptor)

注&#xff1a;机翻&#xff0c;未校对。 OSPF Type2 Message / DBD Packet (Database Descriptor) DBD (Database Description or Type2 OSPF Packet) is a sort of summary of the OSPF Database in a router. DBD is used to check if the LSDB between 2 routers is the s…

Linux---make/makefile工具

目录 基本了解 makefile基础语法 依赖关系 依赖方法 makefile文件内容格式 make执行机制 补充知识 机制解释 PHONY关键字 makefile补充语法 基本了解 在Linux中&#xff0c;make/makefile是项目自动化构建工具。如果我们没有make/makefile&#xff0c;那我们要编译一…

基于Java的模拟写字板的设计与实现

点击下载链接 基于Java的模拟写字板的设计与实现 摘要&#xff1a;目前&#xff0c;很多新的技术领域都涉及到了Java语言&#xff0c;Java语言是面向对象编程&#xff0c;并且涉及到网络、多线程等重要的基础知识&#xff0c;因此Java语言也是学习面向对象编程和网络编程的首…

Linux系统编程——生产者消费者模型

目录 一&#xff0c;模型介绍 1.1 预备知识&#xff08;超市买东西的例子&#xff09; 1.2 模型介绍 1.3 CP模型特点 二&#xff0c;基于阻塞队列的CP模型 2.1 介绍 2.2 阻塞队列的实现 2.3 主函数实现 2.4 效果展示 三&#xff0c;POSIX信号量 3.1 信号量原理 3…

力扣 快慢指针

1 环形链表 141. 环形链表 - 力扣&#xff08;LeetCode&#xff09; 定义两个指针&#xff0c;一快一慢。慢指针每次只移动一步&#xff0c;而快指针每次移动两步。初始时&#xff0c;慢指针和快指针都在位置 head&#xff0c;这样一来&#xff0c;如果在移动的过程中&#x…

05。拿捏ArkTS 第 3 天 --- 对象、联合类型、枚举

1&#xff0c;什么是对象&#xff1f;对象是干什么的&#xff1f; &#xff5e;用来存储不同类型数据的容器 &#xff5e;用来描述物体的特征和行为 //特征就是属性&#xff0c;行为就是方法&#xff08;对象内的函数&#xff09; 2&#xff0c;对象的基本样式是&#xff1f; …

Noah-MP陆面生态水文模拟与多源遥感数据同化技术

了解陆表过程的主要研究内容以及陆面模型在生态水文研究中的地位和作用&#xff1b;熟悉模型的发展历程&#xff0c;常见模型及各自特点&#xff1b;理解Noah-MP模型的原理&#xff0c;掌握Noah-MP模型在单站和区域的模拟、模拟结果的输出和后续分析及可视化等方法&#xff1b;…

OpenGL入门第六步:材质

目录 结果显示 材质介绍 函数解析 具体代码 结果显示 材质介绍 当描述一个表面时&#xff0c;我们可以分别为三个光照分量定义一个材质颜色(Material Color)&#xff1a;环境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和镜面光照(Specular Lighting)。通过为每…

23.jdk源码阅读之Thread(下)

1. 写在前面 上篇文章我们介绍了Tread的一些方法的底层代码实现&#xff0c;这篇文章我们继续。 2. join()方法的底层实现 /*** Waits at most {code millis} milliseconds for this thread to* die. A timeout of {code 0} means to wait forever.** <p> This impleme…

从工艺到性能:模具3D打印材料不断革新

在模具3D打印领域&#xff0c;材料性能的持续优化与创新是推动模具3D打印的关键因素&#xff0c;近年来&#xff0c;各种3D打印新材料不断涌现&#xff0c;模具3D打印材料也开始重工艺导向逐步向性能导向发展&#xff0c;如毅速公司推出的ESU-EM191/191S及ESU-EM201不锈钢粉末、…

电脑文件误删除如何恢复?数据恢复第一步是什么?这五点要第一时间处理!

电脑文件误删除如何恢复&#xff1f;数据删除恢复的第一时间要做什么&#xff0c;你知道吗&#xff1f; 在使用电脑的过程中&#xff0c;误删除重要文件的情况时有发生。面对这种情况&#xff0c;不必过于慌张&#xff0c;因为有多种方法可以帮助你恢复误删除的文件。以下是恢复…