2023/9/11 -- C++/QT

Operation

Modeled on the string class, complete the myString class

02mystring.h:

#ifndef __02MYSTRING_H__
#define __02MYSTRING_H__

#include <iostream>
#include <cstring>

using namespace std;

class myString{
private:
    char *str;
    int size;
public:
    //无参构造
    myString();
    //有参构造
    myString(const char *s);
    //拷贝构造
    myString(const myString &other);
    //析构函数
    ~myString();
    //拷贝赋值函数
    myString & operator=(const myString &other);
    //判空
    bool empty()const;
    //size
    size_t string_size()const;
    //c_str
    const char *c_str()const;
    //at
    char &at(int pos);
    //+运算符
    const myString operator+(const myString &s)const;
    //+=运算符
    myString &operator+=(const myString &s);
    //>运算符
    bool operator>(const myString &s)const;
    //[]运算符
    char operator[](int index);
};

#endif // 02MYSTRING_H

 02mystring.cpp:

#include <02mystring.h>
//无参构造
myString::myString():size(10){
    str = new char[size];
    strcpy(str,"");
    //cout<<"无参构造函数"<<endl;
}
//有参构造
myString::myString(const char *s){
    size = strlen(s);
    str = new char[size+1];
    strcpy(str,s);
    //cout<<"有参构造函数"<<endl;
}
//拷贝构造
myString::myString(const myString &other):size(other.size){
    str = new char[other.size+1];
    strcpy(str,other.str);
    //cout<<"拷贝构造函数"<<endl;
}
//析构函数
myString::~myString(){
    delete []str;
    str = nullptr;
    //cout<<"析构函数"<<endl;
}
//拷贝赋值函数
myString & myString::operator=(const myString &other){
    size = other.size;
    strcpy(str,other.str);
    //cout<<"拷贝赋值函数"<<endl;
    return *this;
}
//判空
bool myString::empty()const{
    return size == 0;
}
//size
size_t myString::string_size()const{
    return size;
}
//c_str
const char *myString::c_str()const{
    return str;
}
//at
char &myString::at(int pos){
    if(pos < 0 || pos >= size){
        cout<<"pos出错啦!"<<endl;
        return *str;             //不知道返回值些什么...嘻嘻,就返回第一个位置...
    }
    return *(str+pos);
}
//+运算符
const myString myString::operator+(const myString &s)const{
    myString S;
    delete []S.str;
    S.size = size + s.size;
    S.str = new char[S.size+1];
    strcpy(S.str,str);
    strcat(S.str,s.str);
    return S;
}
//+=运算符
myString &myString::operator+=(const myString &s){
    size += s.size;
    strcat(str,s.str);
    return *this;
}
//>运算符
bool myString::operator>(const myString &s)const{
    return strcmp(str,s.str) > 0;
}
//[]运算符
char myString::operator[](int index){
    return *(str+index);
}

main.cpp:

#include <02mystring.h>

int main()
{
    myString s1("hello");
    myString s2("world");
    myString s5;
    cout<<"s1.size = "<<s1.string_size()<<endl;
    cout<<"c_str(s2) = "<<s2.c_str()<<endl;
    myString s3 = s1 + s2;
    cout<<"s3.at(5) = "<<s3.at(5)<<endl;
    myString s4("nihao");
    s4 += s2;
    if(s4 > s3){
        cout<<"s4 > s3"<<endl;
    }else {
        cout<<"s4 <= s3"<<endl;
    }
    cout<<"s4[4] = "<<s4[4]<<endl;
    return 0;
}

 Rendering:

1. Friend

1.1 Friend functions

1> Ordinary non-member functions of a class do not have the right to access protected members and private members of the class. However, if a function is set as a friend function, then the function can access members of the class with all permissions. ,

2> Friend functions are divided into global functions as friend functions and member functions of other classes as friend functions.

3> Global function as a friend function format: declare the global function within the class: friend function header;

4> Member functions of other classes are used as friend functions, and the declaration format is: friend other classes:: function name (formal parameter list);

1.2 Friend classes

Declare a class as a friend class, then run all member functions in this class to access private members in your own class

#include <iostream>

using namespace std;
class Stu;             //对类的前置声明

void fun(Stu &s);            //将函数进行前置声明

class Teacher
{
private:
    string name;
    string subject;          //科目

public:
    Teacher() {}
    Teacher(string n, string s):name(n), subject(s) {}

    void display(Stu &s);             //类内声明,类外定义

};

class Stu
{
private:
    string name;
    int age;
    double score;

public:
    Stu() {}
    Stu(string n, int a, double s):name(n),age(a),score(s) {}

    //类中的成员函数,可以直接使用所有权限下的成员
    void show()
    {
        cout<<"name = "<<name<<"  age = "<<age<<"  score = "<<score<<endl;
    }

    //将全局函数声明成友元函数,那么该全局函数可以访问该类中的所有权限下的成员
    friend void fun(Stu &s);

    //将老师类中的成员函数设置成友元函数
    //friend void Teacher::display(Stu &s);

    //将整个老师类都声明成友元类
    friend class Teacher;
};

//定义一个全局函数
void fun(Stu &s)
{
    cout<<"name = "<<s.name<<"  age = "<<s.age<<"  score = "<<s.score<<endl;
}

//将老师类中的成员函数类外定义
void Teacher::display(Stu &s)
{
    cout<<"my_name = "<<name<<endl;
    cout<<"my_subject = "<<subject<<endl;

    cout<<"stu_name = "<<s.name<<endl;
}

int main()
{
    Stu s("zhangpp", 18, 90);
    fun(s);

    Teacher t("zhansan", "C++");
    t.display(s);

    return 0;
}

1.3 Summary of Youyuan

  1. Friends are one-way. If A sets B as a friend, A allows B to access its own members, but B does not necessarily allow A to access its members.
  2. Friends are not transitive: A is a friend of B, and B is a friend of C, so A is not necessarily a friend of C.
  3. Friends do not have inheritance: friends of the parent class are not necessarily friends of the subclass
  4. Friends destroy the encapsulation of classes and make access rights useless. Therefore, friends should not be used as much as possible unless absolutely necessary.
  5. When friends must be used: When overloading the insertion and extraction operators, you need to use global functions as friend functions

2. Constant members (const)

2.1 Constant member functions

1> After defining the member function, add the keyword const, then the function is a constant member function

2> In a constant member function, the value of the member variable cannot be modified, and the member variable is protected from being modified, but the member variable can be used

3> A constant member function and a non-member function with the same name constitute an overloading relationship even if the type and number of parameters are the same, because the types of this pointers are different.

                This in non-member functions: class name * const this;

                This in constant member functions: const class name * const this;

4> For extraordinary objects, when calling a member function, the extraordinary member function is called first. If there is no extraordinary member function, then the constant member function with the same name is called.

2.2 Constant objects

1> When defining an object, add the keyword const: const class name object name;

2> A constant object can only call constant member functions, but cannot call extraordinary member functions.

2.3 mutable keyword

This keyword can modify the member variable in the class, indicating that the variable can be modified in the member function

#include <iostream>

using namespace std;
class Stu
{
private:
    string name;
    mutable int age;            //由mutable修饰的成员变量,可以在常成员函数中被修改
    double score;

public:
    Stu() {}
    Stu(string n, int a, double s):name(n),age(a),score(s) {}

    //类中的成员函数,可以直接使用所有权限下的成员
    void show()const            //this原型:const 类名  * const this;
    {
        //this->score = 100;              //更改成员变量的值
        this->age = 16;            //由于该成员变量由mutable修饰,取消了其常属性
        cout<<"name = "<<name<<"  age = "<<age<<"  score = "<<this->score<<endl;
    }

    //定义同名的非常成员函数
    void show()                   //this原型:类名  * const this;
    {
        this->score = 100;              //更改成员变量的值
        cout<<"name = "<<name<<"  age = "<<age<<"  score = "<<score<<endl;
    }
};

int main()
{
    Stu s1("zhangs", 18, 90);
    //s1.show();                      //100

    const Stu s2("lisi", 20, 50);        //该对象为常对象
    //s2.show();

    //定义常引用,目标为非常对象
    const Stu &ref = s1;

    ref.show();            // 常引用也有常属性,调用成员函数时,只能调用常成员函数,不能调用非常成员函数
    s1.show();            //调用非常成员函数

    return 0;
}

3. Operator overloading (operator)

3.1 Definition

The so-called operator overloading is essentially a type of static polymorphism, which can achieve "one operator for multiple purposes". Using operator overloading can complete the operation of operators between class objects, making the code more concise and more readable.

3.2 Overloaded methods

All operator overloads have a unified name: operator# (# represents the operator symbol)

Parameters: Determined according to the characteristics of the operator itself. If it is a unary operator, it has at most one parameter. If it is a binary operator, it has at most two parameters.

Return value: decided by the user

3.3 Calling principles and calling timing

1> Calling timing: When using this operator, the system automatically calls it, no need to call it manually

2> Calling principle: adjust left parameters and right parameters (the left side of the operator is the function caller, and the right side is the parameters of the function) For example: a = b; //a.operator=(b)

3.4 Reloaded version

Each operator overloading can implement two versions of the overloaded function, namely the member function version and the global function version.

The member function version has one less parameter than the global function version, because the class object itself is a parameter

Only one global function version and member function version can be implemented, otherwise it will cause confusion when calling.

3.5 Arithmetic operator overloading

1> Type: +, -, *, /, %

2> Expression format: L # R //L represents the left operand # represents the operator R represents the right operand

3> Left operand: It can be either an lvalue or an rvalue and will not be modified during the operation.

4> Right operand: It can be either an lvalue or an rvalue and will not be modified during the operation.

5> Result: The result is an rvalue of the same type and cannot be changed.

6> Define format:

Global function version: const class name operator# (const class name&L, const class name&R)

Member function version: const class name operator# ( const class name &R) const

3.6 Relational operator overloading

1> Type: >, =,

2> Expression format: L # R //L represents the left operand # represents the operator R represents the right operand

3> Left operand: It can be either an lvalue or an rvalue and will not be modified during the operation.

4> Right operand: It can be either an lvalue or an rvalue and will not be modified during the operation.

5> Result: bool type, indicating true or false

6> Define format:

Global function version: bool operator# (const class name&L, const class name&R)

Member function version: bool operator# (const class name&R)const

3.7 Assignment class operator overloading

1> Type: =, +=, -=, *=, /=, %=

2> Expression format: L # R //L represents the left operand # represents the operator R represents the right operand

3> Left operand: can only be an lvalue

4> Right operand: It can be either an lvalue or an rvalue and will not be modified during the operation.

5> Result: reference to itself

6> Define format:

Global function version: class name&operator# (class name&L, const class name&R)

Member function version: class name & operator# ( const class name & R)

3.8 Unary operator overloading

1> Type:! ,~,*,&,-

2> Expression format: # O // # represents the operator O represents the operand

3> Operand: It can be either an lvalue or an rvalue and cannot be changed during the operation.

4> Result: rvalues ​​of the same type

5> Define format:

Global function version: class name operator# (const class name &O)

Member function version: class name operator# ()const

#include <iostream>


using namespace std;

//定义一个复数类 5 + 3i
class Complex
{
private:
    int real;         //实部
    int vir;          //虚部
public:
    Complex() {}
    Complex(int r, int v):real(r), vir(v) {}         //有参构造
    //定义展示函数
    void show()
    {
        if(vir>=0)
        {
            cout<<real<<" + "<<vir<<"i"<<endl;
        }else
        {
            cout<<real<<vir<<"i"<<endl;
        }
    }

    //全局函数版实现加运算符重载
    friend const Complex operator+ (const Complex &L, const Complex &R);

    //成员函数版实现运算符重载
    const  Complex  operator- ( const Complex  &R)const
    {
        Complex c;
        c.real = this->real - R.real;
        c.vir = this->vir - R.vir;
        return c;
    }

    //成员函数版实现关系运算符的重载:实部>实部  && 虚部>虚部
    bool operator>(const Complex &R)const
    {
        return this->real>R.real&&this->vir>R.vir;
    }

    //重载中括号运算符
    int & operator[](int index)
    {
        if(index == 0)
        {
            return real;          //返回实部
        }else if(index == 1)
        {
            return vir;           //返回虚部
        }
    }

    //重载+=运算符:实部+=实部   虚部+=虚部
    Complex & operator+=(const Complex &R)
    {
        this->real += R.real;
        this->vir += R.vir;
        return *this;                //返回自身的引用
    }

    //重载负号运算符: 实部= -实部, 虚部 = -虚部
    Complex operator-()
    {
        Complex c;
        c.real = -this->real;
        c.vir = -this->vir;
        return c;
    }
};

//全局函数版实现加号运算符重载:实部+实部  虚部+虚部
const Complex operator+ (const Complex &L, const Complex &R)
{
    //定义一个临时空间
    Complex c;


    c.real = L.real + R.real;
    c.vir = L.vir + R.vir;


    return c;
}

int main()
{
    Complex c1(5,3);
    c1.show();                    //5+3i

    Complex c2(2,-1);
    c2.show();                      //2-1i

    Complex c3 = c1-c2;             //调用加法运算符重载函数  c1.operator-(c2)

    c3.show();                      //3+4i

    if(c3 > c2)              //调用关系运算符重载函数
    {
        cout<<"yes"<<endl;
    }else
    {
        cout<<"no"<<endl;
    }

    c3[0] = 5;               //将实部进行修改成5,调用中括号运算符重载
    c3.show();                  //5+4i

    c3 += c2;            //调用+=运算符重载函数
    c3.show();             //7+3i

    Complex c4 = -c3;      //调用-号运算符重载
    c4.show();              //-7 - 3i
    c3.show();            //7+3i

    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_54147737/article/details/132816928