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

news2024/11/17 2:50:46

类和对象

  • 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.coloradmin.cn/o/1956177.html

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

相关文章

安装 moleculeSTM 踩坑日记

“学习 LLM &#xff0c;在大模型时代为自己存张船票”。 相信很多人都有这样的想法。那么&#xff0c;在 AI for science 领域&#xff0c;哪些 LLM 模型值得一试呢&#xff1f; 笔者认为&#xff1a; LLM 直接预测 SMILES 性质 or 直接生成 SMILES 的技术路线是行不通的。因…

成为git砖家(6): git restore 命令

文章目录 1. git restore 命令是新命令2. git官方对于restore命令的说明3. 总结 1. git restore 命令是新命令 在2019年8月发布的 Git 2.23 版本中&#xff0c;git checkout 命令的功能被拆解到两个新的命令中&#xff1a; git switch: 负责分支相关的操作git restore: 负责文…

微信小程序教程001:小程序简介

文章目录 学习目标小程序简介1、小程序和普通网页开发的区别2、注册小程序账号3、获取小程序的AppID4、安装开发者工具4.1 了解开发者工具4.2 下载开发工具 5、设置开发者工具外观 学习目标 如何创建小程序项目小程序项目的基本组成结构小程序页面由几部分组成小程序常见的组件…

Vscode——如何快速搜索项目工程中的某个文件的位置

第一步&#xff1a;按 shift ctrl p 第二步&#xff1a;然后把 > 删除 第三步&#xff1a;输入文件名称即可

Linux环境docker部署Firefox结合内网穿透远程使用浏览器测试

文章目录 前言1. 部署Firefox2. 本地访问Firefox3. Linux安装Cpolar4. 配置Firefox公网地址5. 远程访问Firefox6. 固定Firefox公网地址7. 固定地址访问Firefox 前言 本次实践部署环境为本地Linux环境&#xff0c;使用Docker部署Firefox浏览器后&#xff0c;并结合cpolar内网穿…

永磁同步电机双矢量模型预测(MPC)电流控制MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介 在电流环中采用双矢量模型预测电流控制方法&#xff0c;该方法在每一个采样周期中进行两次电压矢量选择&#xff0c;可以在进行第二次电压矢 量选择时采用非零电压矢量&#xff0c;电压矢量的选择范…

RAG优化技巧 | 7大挑战与解決方式 | 提高你的LLM: 下篇

RAG优化技巧 | 7大挑战与解决方式 | 提高你的LLM&#xff1a;下篇 在当今快速发展的人工智能领域&#xff0c;大型语言模型&#xff08;LLM&#xff09;已经成为无处不在的技术&#xff0c;它们不仅改变了我们与机器交流的方式&#xff0c;还在各行各业中发挥着革命性的影响。…

算法笔记--哈希表

创建和使用Python字典&#xff08;哈希表&#xff09; 在Python中&#xff0c;哈希表通常是通过字典&#xff08;dict&#xff09;来实现的。 字典是一种可变容器模型&#xff0c;可以存储任意类型的对象&#xff0c;如字符串、数字、元组等其他容器模型。 字典的每个键值对…

GAT知识总结

《GRAPH ATTENTION NETWORKS》 解决GNN聚合邻居节点的时候没有考虑到不同的邻居节点重要性不同的问题&#xff0c;GAT借鉴了Transformer的idea&#xff0c;引入masked self-attention机制&#xff0c; 在计算图中的每个节点的表示的时候&#xff0c;会根据邻居节点特征的不同来…

【文生视频系列】MoneyPrinterTurbo项目初探

1. 背景介绍 一直有在关注文生视频方面的进展信息。比较知名的可能还是sora这类文生视频模型。但今天要讲的是另外的文生视频项目&#xff0c;也是偶然间在git上看到的&#xff0c;项目名称叫MoneyPrinterTurbo&#xff0c;是基于MoneyPrinter项目增加了中文支持&#xff0c…

R语言统计分析——自编函数

参考资料&#xff1a;R语言统计分析【第2版】 一个函数的结构大致如此&#xff1a; myfunction<-function(arg1,arg2,...){ statements return(object) } 函数中的对象只在函数内部使用。返回对象的数据类型是任意的。 假设我们要编写一个函数&#xff0c;用来计算数据对象…

【C++BFS算法 二分查找】2812. 找出最安全路径

本文涉及知识点 CBFS算法 C二分查找 LeetCode2812. 找出最安全路径 给你一个下标从 0 开始、大小为 n x n 的二维矩阵 grid &#xff0c;其中 (r, c) 表示&#xff1a; 如果 grid[r][c] 1 &#xff0c;则表示一个存在小偷的单元格 如果 grid[r][c] 0 &#xff0c;则表示一…

【C语言篇】C语言常见概念

文章目录 C语言常见概念C语言是什么C语⾔的历史和辉煌编译器选择编译和连接编译器对比 第一段C语言代码main函数库函数关键字介绍字符和ASCII编码转义字符语句空语句表达式语句函数调⽤语句复合语句控制语句 注释两种形式/* */的形式//形式注释会被替换注释会被替换 C语言常见概…

关键路径算法(Critical Path)

这个算法《算法导论》中并没有提及&#xff0c;很多书和博客说的有点奇怪&#xff0c;所以写本文作为笔记。 关键路径是什么 关键路径的定义非常简单&#xff1a;就是一个图中&#xff0c;权值之和最大的路径就是关键路径。 那么就可以知道关键路径不唯一。 为什么有关键路…

让大脑处于顶峰的14个保养技巧

让大脑处于顶峰的14个保养技巧 阅读。 之所以第一个写阅读&#xff0c;是因为阅读需要大脑将已认知的信息与新接触信息结合从而更容易激发人的想象力&#xff0c;而图片与视频虽然更直观&#xff0c;但理解和思考的过程却缩短了&#xff0c;大脑得到的锻炼也十分局限。阅读是让…

Typesript的type和interface的异同?

详解TypeScript中type与interface的区别_javascript技巧_脚本之家 一、相同的地方 1、都可以用来定义对象&#xff0c;描述函数 我们在用typescript开发的时候经常要用到数据类型定义&#xff0c;比如我们写一个接口或者函数的时候定义传参数据类型及字段等。这样子方便知道这…

opencascade AIS_PointCloud源码学习

AIS_PointCloud 前言 交互对象用于一组点。 表示支持两种显示模式&#xff1a; 点。 用于高亮显示的边界框。 表示通过边界框提供选择。 选择和高亮显示可以通过将默认选择模式设置为 -1 来禁用。 这样在交互视图中将无法选择对象。任何调用 AIS_InteractiveContext::AddOrRem…

Lua编程

文章目录 概述lua数据类型元表注意 闭包表现 实现 lua/c 接口编程skynet中调用层次虚拟栈C闭包注册表userdatalightuserdata 小结 概述 这次是skynet&#xff0c;需要一些lua/c相关的。写一篇博客&#xff0c;记录下。希望有所收获。 lua数据类型 boolean , number , string…

【一图学技术】2.API测试9种方法图解

9种API测试方法 冒烟测试&#xff1a;冒烟测试是一种快速的表面级测试&#xff0c;用于验证软件的基本功能是否正常工作&#xff0c;以确定是否值得进行更详细的测试。功能测试&#xff1a;功能测试是验证软件是否符合预期功能要求的测试类型。它涉及对每个功能进行测试&#…