c++_08_操作符重载(操作符重定义) 友元

news2024/11/29 5:26:58

1  操作符标记 

        单目操作符:        -    ++    --    *    ->    等

        双目操作符:        -    +    >    <    +=    -=    <<    >>    等

        三木操作符:        ? :  

2  操作符函数

2.0  前言

        C++编译器有能力把一个由操作数操作符组成的表达式,

        解释为对一个成员函数的调用,               a + b   -->   a.operator+( b )

        解释为对一个全员函数的调用。               a + b   -->   operator+( a,b )

        该  全员函数  或  成员函数  被称为操作符函数。两个函数不要重复定义。

        通过定义操作符函数,可以实现针对自定义类型的运算法则,并使之与基本类型一样参与各种表达式。

// complex_pre.cpp操作符函数
#include <iostream>
using namespace std;

class Human {
public:
    Human( int age=0, const char* name="无名" ) : m_age(age),m_name(name) {
        //【int m_age=age;】
        //【string m_name(name);】
    }
    void getinfo( ) {
        cout << "姓名: " << m_name << ", 年龄: " << m_age << endl;
    }
    Human sum( /* Human* this */ Human r ) {
        return Human(this->m_age+r.m_age, (this->m_name+"+"+r.m_name).c_str() );
    }
    Human sub( /* Human* this */ Human r ) {
        return Human(this->m_age-r.m_age, (this->m_name+"-"+r.m_name).c_str() );
    }
private:
    int m_age;
    string m_name;
};
// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    Human a(22,"张飞"), b(20,"赵云"), c(25,"关羽"), d(32,"马超");

    Human res = a.sum(b); // a + b; ==> a.operator+(b)  或  operator+(a,b)
    res.getinfo( );

    res = c.sub(d); // c - d; ==> c.operator-(d)  或 operator-(c,d)
    res.getinfo( );
    return 0;
}

2.1  单目运算符表达式    #O / O#

        成员函数形式:    O.operator# ()

        全局函数形式:    operator# (O)

2.2  双目运算符表达式    L#R

        成员函数形式:    L.operator# (R)    左调右参:左操作数是用对象,操作数是数对象

        全局函数形式:    operator# (L,R)    左一右二:操作数是第参数,操作数是第参数

2.3  三目运算符表达式    F#S#T

        无法重载。

3  典型双目操作符

3.1  运算类:  +  -  *  /  等

        左操作数可以为非常左值常左值右值 

        右操作数可以为非常左值常左值右值 

        表达式的结果为右值 (即,不是引用就行)

// double_operator1.cpp
#include <iostream>
using namespace std;

class Human { // 授权类(授予朋友权利的类)
public:
    Human( int age=0, const char* name="无名" ) : m_age(age),m_name(name) {
        //【int m_age=age;】
        //【string m_name(name);】
    }
    void getinfo( ) {
        cout << "姓名: " << m_name << ", 年龄: " << m_age << endl;
    }
    // 成员形式的操作符函数  万能指针是必要的      万能引用是必要的
//    Human operator+( /* const Human* this */ const Human& that ) const {
//        return Human(this->m_age+that.m_age, (this->m_name+"+"+that.m_name).c_str());
//    }
private:
    int m_age;
    string m_name;
    friend Human operator+( const Human& l, const Human& r ) ; // 友元声明
};
// 全局形式的操作符函数
Human operator+( const Human& l, const Human& r ) { 
    return Human(l.m_age+r.m_age, (l.m_name+"+"+r.m_name).c_str() );
}
// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    Human a(22,"张飞"), b(20,"赵云"); // 非常左值
    const Human c(25,"关羽"), d(32,"马超"); // 常左值

    Human res =  a + b; // ==> a.operator+(b)  或  operator+(a,b)
    res.getinfo( );
    
    res = c + d; // ==> c.operator+(d)  或  operator+(c,d)
    res.getinfo();

    res= Human(45,"黄忠")+ Human(35,"刘备");//Human(45,"黄忠").operator+(Human(35,"刘备"))
                                         //operator+( Human(45,"黄忠"), Human(35,"刘备"))
    res.getinfo();
    /*
    int a=10, b=20; // 非常左值
    const int c=30, d=40; // 常左值

    |30| a + b;
    a + c;
    a + 5;
    c + b;
    5 + b;
    */
    return 0;
}

3.2  赋值类  =  +=  -=  *=  /=  等

        左操作数必须为非常左值 

        右操作数可以为非常左值常左值右值 

        表达式结果为左操作数本身(而非副本)

        operator=()就是拷贝赋值函数,编译器会默认给。

// double_operator2.cpp
#include <iostream>
using namespace std;

class Human { // 授权类(授予朋友权利的类)
public:
    Human( int age=0, const char* name="无名" ) : m_age(age),m_name(name) {
        //【int m_age=age;】
        //【string m_name(name);】
    }
    void getinfo( ) {
        cout << "姓名: " << m_name << ", 年龄: " << m_age << endl;
    }
    // 成员形式的操作符函数
    Human& operator+=( /* Human* this */ const Human& that ) {
        this->m_age = this->m_age + that.m_age;
        this->m_name = this->m_name+"+"+that.m_name;
        return *this;
    }
private:
    int m_age;
    string m_name;
};
// 全局形式的操作符函数(自己课下写)

// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    Human a(22,"张飞"), b(20,"赵云"); // 非常左值
    const Human c(25,"关羽"), d(32,"马超"); // 常左值

    ((a+=b)+=c)+=Human(45,"黄忠");
    a.getinfo();
    /*
    a += b; // a.operator+=(b)  或  operator+=(a,b)
    a.getinfo();

    a += c; // a.operator+=(c)  或  operator+=(a,c)
    a.getinfo();

    a += Human(45,"黄忠"); //   a.operator+=(Human(45,"黄忠")) 
                          // 或 operator+=(a,Human(45,"黄忠"))
    a.getinfo();
    */

    /*
    int a=10, b=20; // 非常左值
    const int c=30, d=40; // 常左值

    a = b; 
    a = c;
    a = 5;
    c = b; // error
    5 = b; // error
    */
    return 0;
}

3.3  比较类   >   <   ==   <=   >=   等

        左操作数为非常左值常左值右值 

        右操作数为非常左值常左值右值

        表达式结果为bool 

// double_operator3.cpp
#include <iostream>
using namespace std;

class Human { // 授权类(授予朋友权利的类)
public:
    Human( int age=0, const char* name="无名" ) : m_age(age),m_name(name) {
        //【int m_age=age;】
        //【string m_name(name);】
    }
    void getinfo( ) {
        cout << "姓名: " << m_name << ", 年龄: " << m_age << endl;
    }
    // 成员形式的操作符函数
    bool operator==( /* const Human* this */ const Human& that ) const {
        return this->m_age==that.m_age && this->m_name==that.m_name;
    }
    bool operator!=( /* const Human* this */ const Human& that ) const {
//      return this->m_age!=that.m_age || this->m_name!=that.m_name;
        return !(*this==that);
    }
private:
    int m_age;
    string m_name;
};
// 全局形式的操作符函数(自己课下写)

// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    Human a(22,"张飞"), b(20,"赵云"); // 非常左值
    const Human c(25,"关羽"), d(32,"马超"); // 常左值

    cout << (a == b) << endl; // a.operator==(b)  或 ...
    cout << (a != b) << endl; // a.operator!=(b)  或 ...

    cout << (c == d) << endl; // c.operator==(d)  或 ...
    cout << (c != d) << endl; // c.operator!=(d)  或 ...

    cout << (Human(45,"黄忠")==Human(35,"刘备")) << endl; 
                              // Human(45,"黄忠").operator==(Human(35,"刘备"))
    cout << (Human(45,"黄忠")!=Human(35,"刘备")) << endl; 
                              // Human(45,"黄忠").operator!=(Human(35,"刘备"))

    /*
    int a=10, b=20; // 非常左值
    const int c=30, d=40; // 常左值

    a == b;
    a == c;
    a == 5;
    c == b;
    5 == b;

    */
    return 0;
}

4  典型单目操作符

4.1  运算类  -    ~    !   等

        操作数为非常左值常左值右值 

        表达式的结果为右值 

// single_operator1.cpp
#include <iostream>
using namespace std;

class Human { // 授权类(授予朋友权利的类)
public:
    Human( int age=0, const char* name="无名" ) : m_age(age),m_name(name) {
        //【int m_age=age;】
        //【string m_name(name);】
    }
    void getinfo( ) {
        cout << "姓名: " << m_name << ", 年龄: " << m_age << endl;
    }
    // 成员形式的操作符函数
    Human operator-( /* const Human* this */ ) const  {
        return Human(-this->m_age, ("-"+this->m_name).c_str() );
    }
private:
    int m_age;
    string m_name;
};
// 全局形式的操作符函数(自己课下写)

// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    Human a(22,"张飞"), b(20,"赵云"); // 非常左值
    const Human c(25,"关羽"), d(32,"马超"); // 常左值

    Human res = -a; // a.operator-()  或 ... 
    res.getinfo();

    res = -c; // c.operator-()  或 ...
    res.getinfo();

    res = -Human(45,"黄忠"); // Human(45,"黄忠").operator-()  或 ...
    res.getinfo();

    /*
    int a=10, b=20; // 非常左值
    const int c=30, d=40; // 常左值

    |-10| -a; // ok
    |-30| -c; // ok
    |-40| -40;// ok
    */
    return 0;
}

4.2  前自增减类  ++O  --O

        操作数为非常左值 

        表达式结果为操作数本身(而非副本)

4.3  后自增减类  O++  O--

        操作数为非常左值 

        表达式的结果为右值,且为自增减以前的值

// single_operator2.cpp
#include <iostream>
using namespace std;

class Human { // 授权类(授予朋友权利的类)
public:
    Human( int age=0, const char* name="无名" ) : m_age(age),m_name(name) {
        //【int m_age=age;】
        //【string m_name(name);】
    }
    void getinfo( ) {
        cout << "姓名: " << m_name << ", 年龄: " << m_age << endl;
    }
    // 成员形式的操作符函数
    Human& operator++( /* Human* this */ ) {
        this->m_age += 1; // 直接就加1
        return *this;
    }
    Human operator++( /* Human* this */ int ) {
        Human old = *this; // 克隆一份b原来的值
        this->m_age += 1; // 直接就加1
        return old; // 返回的为克隆的b原来的值
    } 
private:
    int m_age;
    string m_name;
};
// 全局形式的操作符函数(自己课下写)

// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    Human a(22,"张飞"), b(20,"赵云"); // 非常左值
    const Human c(25,"关羽"), d(32,"马超"); // 常左值

    (++a).getinfo(); // a.operator++()  或  operator++(a)

    (/*|...|*/b++).getinfo(); // b.operator++(0) 或  operator++(b,0) 
    b.getinfo();
    /*
    int a=10, b=20; // 非常左值
    const int c=30, d=40; // 常左值

    ++a; // ok
    ++c; // error
    ++5; // error

    b++; // ok
    c++; // error
    5++; // error
    */
    return 0;
}

5  其他操作符

5.1  输出流操作符  <<

        左操作数(cout)为  非常左值  形式的输出流( ostream )对象

        右操作数为  左值或右值

        表达式的结果为左操作符本身(而非副本)

        

        左操作数的类型为ostream,

        (若以成员函数形式重载该操作符,就应将其定义为ostream类的成员),

        但该类为标准库提供,无法添加新的成员,因此只能以全局函数形式重载该操作符:

        ostream&  operator<< ( ostream& os,  const RTGHT& right ) { ... } 

5.2  输入流操作符  >>

        左操作数为  非常左值  形式的输入流( istream )对象

        右操作数为  非常左值 

        表达式的结果为左操作符本身(而非副本)

        左操作数的类型为istream,

        (若以成员函数形式重载该操作符,就应将其定义为istream类的成员),

        但该类为标准库提供,无法添加新的成员,因此只能以全局函数形式重载该操作符:

        istream&  operator>> ( istream& is,  RIGHT& right ) { ... } 

// io.cpp
#include <iostream>
using namespace std;

class Human { 
public:
    Human( int age=0, const char* name="无名" ) : m_age(age),m_name(name) {
        //【int m_age=age;】
        //【string m_name(name);】
    }
    void getinfo( ) {
        cout << "姓名: " << m_name << ", 年龄: " << m_age << endl;
    }
private:
    int m_age;
    string m_name;
    friend ostream& operator<<( ostream& os, const Human& that ) ;
    friend istream& operator>>( istream& is, Human& that ) ;
};
// 全局形式的操作符函数(自己课下写)
ostream& operator<<( ostream& os, const Human& that ) {
    os << "姓名:" << that.m_name << ", 年龄:" << that.m_age;
    return os;
}
istream& operator>>( istream& is, Human& that ) {
    is >> that.m_name >> that.m_age;
    return is; 
}
// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    Human a(22,"张飞"), b(20,"赵云"); // 非常左值
    const Human c(25,"关羽"), d(32,"马超"); // 常左值

//    a.getinfo();
    cout << a << endl; // operator<<(cout, a)
    cout << c << endl; // operator<<(cout, c)
    cout << Human(45,"黄忠") << endl; // operator<<(cout, Human(45,"黄忠") )

    cin >> a; //  operator>>(cin,a)
    cout << a << endl;

    /*
     
    int a=10, b=20; // 非常左值
    const int c=30, d=40; // 常左值

    cout << a;
    cout << c;
    cout << 5;

    */
    return 0;
}

5.3  下标操作符  []

        一般用于在容器类型中以下标方式获取数据元素

        非常容器的元素为非常左值

        常容器的元素为常左值

// stack.cpp 
// 简易的栈容器 -- 先进后出
#include <iostream>
using namespace std;

class Stack {
public:
    Stack() : m_s(0) {
        //【int arr[20];】
        //【int m_s=0;】
    }
    void push(int data) {  arr[m_s++] = data; } // 判满操作,自己课下写
    int pop() { return arr[--m_s];  } // 判空操作,自己课下写
    int size() {  return m_s; }
    const int& operator[]( /* const Stack* this */ size_t i) const { // 常函数
        return this->arr[i];
    }
    int& operator[]( /* Stack* this */ size_t i) { // 非常函数
        return this->arr[i];
    }
private:
    int arr[20]; // 保存数据
    int m_s;     // 保存数据个数
};

// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    Stack s; // 非常容器
    for( int i=0; i<20; i++ ) {
        s.push( 1000+i );
    }
    cout << "压栈后s容器中数据的个数:" << s.size() << endl;
    s[5] = 888; // 非常容器的元素,就是非常左值   s.operator[](5)=888
    for( int i=0; i<20; i++ ) {
        cout << s[i] << ' ';
    }
    cout << endl;
    cout << "读数据后s容器中数据的个数:" << s.size() << endl;

    const Stack cs = s; // cs是常容器
    cs[5] = 999; // cs.operator[](5)=999    应该让编译器报readonly错误
    
    /*
    int s[20] = {...}; // s是非常容器,s的元素就是非常左值
    s[5] = 888;

    const int cs[20] = {...}; // cs是常容器,cs的元素就是常左值
    cs[5] = 999; // 报告readonly错误
    */
    return 0;
}

5.4  类型转换操作符

        1)若源类型是基本类型,目标类型是类型,则

        只能通过类型转换 构造 函数实现自定义类型转换:

                class 目标类型 {

                        目标类型 ( const 源类型& src ) {...}

                };

        2)若源类型是类型,目标类型是基本类型,则

        只能通过类型转换 操作符 函数实现自定义类型转换:

                class 源类型 {

                        operator 目标类型 (void) const {...}

                };

        3)若源类型和目标类型都是类型,则

        既优先通过类型转换 构造 函数,其次通过类型转换 操作符 函数实现自定义类型转换。

        但两者没必要同时使用。

        4)若源类型和目标类型都是基本类型,则

        无法实现自定义类型转换,基本类型之间的转换规则是由编译器内置的隐式转换。

// cast1.cpp
// 类型转换构造函数 和 类型转换操作符函数
#include <iostream>
using namespace std;
class Integer {
public:
    Integer(int i):m_i(i) {
        //【int m_i=i;】
        cout << "Integer类的类型转换构造函数被调用" << endl;
    }
    operator int( /* const Integer* this */ ) const {
        cout << "Integer类的类型转换操作符函数被调用" << endl;
        return this->m_i;
    }
private:
    int m_i;
};
// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    int m = 100;
    
    // int-->Integer (基本类型-->类类型)
    Integer ix = m; // 定义 匿名Integer类对象,利用 匿名Integer类对象.Integer(m)
                       ->类型转换构造函数
                    // Integer ix = m.operator Integer()
                       -->int类中绝对没有一个operator Integer成员函数(走不通)

    // Integer-->int (类类型-->基本类型)
    int n = ix; 
    // 定义 匿名int类对象,利用 匿名int类对象.int(ix)
       -->int类中绝对没有一个形参为Integer的构造函数(走不通)
    // int n = ix.operator int() --> 类型转换操作符函数
    return 0;
}
// cast2.cpp
// 类型转换构造函数/类型转换操作符函数 -- 指定 源类型 到 目标类型 的 转换规则
#include <iostream>
using namespace std;
class Dog; // 短式声明
class Cat {
public:
    Cat( const char* name ) : m_name(name) { 
        //【string m_name(name);】
    }
    void talk( ) {
        cout << m_name << ": 喵喵~~~" << endl;
    }
    operator Dog( /* const Cat* this */ ) const; // 声明
private:
    string m_name;
    friend class Dog; // 友元声明
};

class Dog {
public:
    Dog( const char* name ) : m_name(name) {
        //【string m_name(name);】
    }
    Dog( const Cat& c ) : m_name(c.m_name) { //类型转换构造函数(Cat-->Dog的转换规则)
        //【string m_name=c.m_name;】
        cout << "Dog类的类型转换构造函数被调用" << endl;
    }
    void talk( ) {
        cout << m_name << ": 汪汪~~~" << endl;
    }
private:
    string m_name;
};
Cat::operator Dog( /* const Cat* this */ ) const { // 定义
    cout << "Cat类的类型转换操作符函数被调用" << endl;
    return Dog( this->m_name.c_str() );
}
// 模拟类的设计者(类库、别人设计的类、自己设计的类)
// --------------------------------
// 模拟用户(使用类的人)
int main( void ) {
    Cat smallwhite("小白"); 
    // Cat-->Dog (类类型-->类类型)
    Dog bigyellow = smallwhite; //定义 匿名Dog类对象,利用 匿名Dog类对象.Dog(smallwhite)
                                   ->类型转换构造函数 
                                //Dog bigyellow = smallwhite.operator Dog()
                                   ->类型转换操作符函数
    return 0;
}

6  操作符重载的局限

        1)不是所有的操作符都能重载,以下操作符就不能重载:

                作用域限定操作符        ::  

                直接成员访问操作符        .  

                条件操作符        ? :  

                字节长度操作符        sizeof  

                类型信息操作符        typeid  

        2)所有操作数均为基本类型的操作符也不能重载:

                1 + 1 = 8 ?

7  友元

        可以通过friend关键字,把

        一个全局函数、另一个类的成员函数、另一个整体,

        声明为授权类的友元。

        友元拥有访问授权类任何非公有成员的特权。(即访问所有成员)

        友元声明可以出现在授权类的公有、私有、保护等任何区域,且不受  访问控制限定符  的约束。

        友元是成员,其作用域并隶属于授权类,也拥有授权类类型的this指针。

// twoDimensional_08.cpp 设计一个二维坐标系的 类
#include <iostream>
using namespace std;

class TwoDimensional {
public:
    TwoDimensional( int x=0, int y=0 ) {
        // 在this指向的内存空间中 定义m_x初值为随机数
        // 在this指向的内存空间中 定义m_y初值为随机数
        m_x = x;
        m_y = y;
    }
    TwoDimensional operator+( /* const TwoDimensional* this */ const TwoDimensional& that ) const {
        return TwoDimensional( this->m_x+that.m_x, this->m_y+that.m_y );
    }
    TwoDimensional& operator=( /* TwoDimensional* this */ const TwoDimensional& that ) {
        this->m_x = that.m_x;
        this->m_y = that.m_y;
        return *this;
    }
    bool operator>( /* const TwoDimensional* this */ const TwoDimensional& that ) const {
        return this->m_x*this->m_x+this->m_y*this->m_y > that.m_x*that.m_x + that.m_y*that.m_y;
    }
    TwoDimensional operator-( /* const TwoDimensional* this */ ) const {
        return TwoDimensional( -this->m_x, -this->m_y );
    }
    TwoDimensional& operator++( /* TwoDimensional& this*/ ) {
        ++this->m_x;
        ++this->m_y;
        return *this;
    }
private:
    int m_x; // 横坐标
    int m_y; // 纵坐标
    friend ostream& operator<<( ostream& os, const TwoDimensional& that );
};
ostream& operator<<( ostream& os, const TwoDimensional& that ) {
    os << "横坐标:" << that.m_x << ", 纵坐标:" << that.m_y;
    return os;
}

class ThreeDimensional {
public:
    ThreeDimensional( int x=0, int y=0, int z=0 ) : m_x(x),m_y(y),m_z(z) {}
    operator TwoDimensional( /* const ThreeDimensional* this */ ) const {
        return TwoDimensional( this->m_x, this->m_y );
    }
private:
    int m_x;
    int m_y;
    int m_z;
};
int main( void ) {
    TwoDimensional a(1,2), b(3,4);

    cout << "a-->" << a  << ", b-->" << b << endl; // cout 打印 坐标对象
    
    TwoDimensional res = a + b; // 坐标间求和
    cout << res << endl;
    a = b; // 坐标间赋值
    cout << a << endl;
    cout << (a > b) << endl; // 坐标间比较大小
    res = -a; // 坐标取反
    cout << res << endl;
    cout << ++a << endl; // 坐标自增

    ThreeDimensional c(100,200,300);

    TwoDimensional d = c; // TwoDimensional d = c.operator TwoDimensional();
    cout << d << endl;
    return 0;
}

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

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

相关文章

Ubuntu之修改时区/时间

1、查看当前时间及时区状态 sudo timedatectl status # 显示当前时区为Asia/Shanghai 2、查看当前系统时间 sudo date 3、查看当前系统时间及时区 sudo date -R # 显示当前时间及对应时区&#xff0c;时区为“0800”北京时区 4、修改硬件时间 修改日期格式&#xff1a…

论虚继承的作用

虚继承 实验介绍 在上一小节中学习了多继承与多重继承,实际在开发的时候可能会遇到一种情况,既用到了多继承又用到了多重继承,这种继承方式通常又称为菱形继承。但这样一来就会产生新的问题,过多消耗空间。希望通过本小节学习能知道菱形继承以及产生的问题和解决方式。 …

buuctf-Misc 题目解答分解103-105

103.[GKCTF 2021]签到 追踪流发现类似flag 字符 f14g 下面有大量的是16进制字符 64306c455357644251306c6e51554e4a5a3046355355737764306c7154586c4a616b31355357704e65556c7154586c4a616b31355357704e65556c7154586c4a616b31355357704e65556c7154586c4a616b31355357704e655…

动态内存管理篇

为什么要动态内存分配&#xff1f; 之前&#xff0c;我们向内存申请空间&#xff0c;有两种方式&#xff0c;一种是定义变量&#xff0c;一种是建立数组&#xff1b;但是&#xff0c;这两种方式都有缺陷&#xff0c;创建的空间大小是固定的&#xff0c;在程序的运行过程中&…

操作系统(Operator System)

这里写目录标题 1. 什么是操作系统2. 主要功能3. 计算机的层状结构4. 什么叫做管理5. 总结6. 为什么要有操作系统7. 最后 1. 什么是操作系统 操作系统&#xff08;英语&#xff1a;Operating System&#xff0c;缩写&#xff1a;OS&#xff09;是一组主管并控制计算机操作、运…

PostgreSQL PG的流复制搭建

注: 本文为云贝教育 刘峰 原创&#xff0c;请尊重知识产权&#xff0c;转发请注明出处&#xff0c;不接受任何抄袭、演绎和未经注明出处的转载。【PostgreSQL】PG的流复制搭建 - 课程体系 - 云贝教育https://www.yunbee.net/Home/News/detail/article_id/510.html 一 、主备机…

HarmonyOS资源分类与访问

资源分类与访问 应用开发过程中&#xff0c;经常需要用到颜色、字体、间距、图片等资源&#xff0c;在不同的设备或配置中&#xff0c;这些资源的值可能不同。 应用资源&#xff1a;借助资源文件能力&#xff0c;开发者在应用中自定义资源&#xff0c;自行管理这些资源在不同…

仿网易云音乐网站PHP源码,可运营的原创音乐分享平台源码,在线音乐库系统

源码介绍 使用PHP和MYSQL开发的原创音乐分享平台源码&#xff0c;仿网易云音乐网站。用户可以在网站上注册并上传自己的音乐作品&#xff0c;系统内置广告系统&#xff0c;为网站创造收入来源。 安装教程 1.导入sql.sql 2.修改 includes\config.php 数据库信息和网址都改成…

【教3妹学编程-算法题】一年中的第几天

3妹&#xff1a;“太阳当空照&#xff0c;花儿对我笑&#xff0c;小鸟说早早早&#xff0c;你为什么背上炸药包” 2哥 :3妹&#xff0c;什么事呀这么开森。 3妹&#xff1a;2哥你看今天的天气多好啊&#xff0c;经过了一周多的寒潮&#xff0c;天气总算暖和些了。 2哥&#xff…

最新ChatGPT网站AI系统源码,附详细搭建教程/支持GPT4.0/AI绘画/GPT语言对话/DALL-E3文生图/自定义知识库

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

搭建 Mac系统Arduino + MindPlus开发环境

搭建 Mac系统Arduino MindPlus开发环境 1.概述 2024年1月1号&#xff0c;元旦大家的安排丰富多彩&#xff0c;在这一天中我的安排依旧坚持初心&#xff0c;牢记使命。学习是我的起点也是我的终点&#xff0c;只要活着就要用知识丰富自己的生活。 今天是一个有意义的日子&…

GVRP实验配置

GVRP&#xff08;GARP VLAN Registration Protocol&#xff09;&#xff0c;称为VLAN注册协议。 GVRP基于GARP的工作机制&#xff0c;是GARP的一种应用。GVRP用来维护交换机中的VLAN动态注册信息&#xff0c;并传播该信息到其它的交换机中。支持GVRP特性的交换机能够接收来自其…

Servlet见解3

13 Cookie和Session http协议是一个无状态的协议&#xff0c;你每一个跳转到下一个页面的时候都是需要先登录才能使用&#xff0c;这样就很麻烦比如淘宝&#xff0c;没有cookie和session的话&#xff0c;用户在首页已经登录上去了&#xff0c;但是需要再次登录才能选择商品&am…

无监督关键词提取算法:TF-IDF、TextRank、RAKE、YAKE、 keyBERT

TF-IDF TF-IDF是一种经典的基于统计的方法&#xff0c;TF(Term frequency)是指一个单词在一个文档中出现的次数&#xff0c;通常一个单词在一个文档中出现的次数越多说明该词越重要。IDF(Inverse document frequency)是所有文档数比上出现某单词的个数&#xff0c;通常一个单词…

JMeter(十六)-JMeter断言

十六、JMeter断言 1.简介 断言组件用来对服务器的响应数据做验证&#xff0c;常用的断言是响应断言&#xff0c;其支持正则表达式。虽然我们的通过响应断言能够完成绝大多数的结果验证工作&#xff0c;但是JMeter还是为我们提供了适合多个场景的断言元件&#xff0c;辅助我们来…

Redis原理及常见问题

高性能之道 单线程模型基于内存操作epoll多路复用模型高效的数据存储结构redis的单线程指的是数据处理使用的单线程,实际上它主要包含 IO线程:处理网络消息收发主线程:处理数据读写操作,包括事务、Lua脚本等持久化线程:执行RDB或AOF时,使用持久化线程处理,避免主线程的阻…

服务器监控软件夜莺部署(一)

文章目录 一、夜莺介绍1. 简介2. 相关网站 二、夜莺部署1. 部署架构2. Docker启动3. 配置数据源4. 内置仪表盘效果5. 时序指标效果 一、夜莺介绍 1. 简介 夜莺监控系统是一款专业的服务器监控软件&#xff0c;它可以帮助用户实时监测服务器的CPU、内存、磁盘利用率等。 夜莺监…

二叉树题目:根到叶路径上的不足结点

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;根到叶路径上的不足结点 出处&#xff1a;1080. 根到叶路径上的不足结点 难度 6 级 题目描述 要求 给定二叉树的根结点 root \texttt{root} root…

C语言之sizeof详解,5点透析,帮你真正了解它

今天也要继续坚持 前言 今天复习C语言了解到不少和她有关的知识&#xff0c;才知道之前对他了解甚少&#xff0c;于是写下博客及时记录自己的所得&#xff0c;与大家分享一下 第一点&#xff1a;sizeof不是函数 sizeof是一个关键字而不是函数&#xff01;是的&#xff0c;他…

【AIGC矢量风格】黑色和白色一系列物体

基于矢量风格的一组画面&#xff1a; 矢量风格是海报设计中常见的一种风格&#xff0c;它主要使用矢量图形进行设计。矢量图形是由数学公式定义的图形&#xff0c;其特点是可以在不失去清晰度的情况下进行任意缩放&#xff0c;无论图形尺寸如何变化&#xff0c;都不会失真或模糊…