C++(学习)2024.9.23

目录

运算符重载

1.概念

2.友元函数运算符重载

3.成员函数运算符重载

4.特殊运算符重载

1.赋值运算符重载

2.类型转换运算符重载

5.注意事项

std::string字符串类:

模板与容器

模板

1.函数模板

2.类模板

类内实现

类内声明类外实现


运算符重载

1.概念

C++中可以把部分的运算符开做成函数,此时运算符也可以重载。

运算符预定义的操作只能针对基本数据类型。但是对于自定义类型,也需要类似运算操作,此时就可以重新定义这些运算符的功能,使其支持特定类型,完成特定的操作。
可以被重载的运算符:

算术运算符:+、-、*、/、%、++、--

位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)

逻辑运算符:!、&&、||

比较运算符:<、>、>=、<=、==、!=

赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=

其他运算符:[]、()、->、,、new、delete、new[]、delete[]

不被重载的运算符:

成员运算符"."、指针运算符"*"、三目运算符" ? : "、sizeof、作用域"::"
运算符重载有两种实现方式:
1.友元函数运算符重载
2.成员函数运算符重载

2.友元函数运算符重载

cpp 复制代码
#include <iostream>
using namespace std;

class MyInt
{
private:
    int a;
public:
    MyInt(int a)
    {
        this->a=a;
    }
    int get_int()
    {
        return a;
    }
    friend MyInt operator +(MyInt &i,MyInt &i2);
    friend MyInt operator ++(MyInt &i);//前置++
    friend MyInt operator ++(MyInt &i,int);//后置++
};
MyInt operator +(MyInt &i,MyInt &i2)
{
    return i.a+i2.a;
}
MyInt operator ++(MyInt &i)
{
    return ++i.a;
}

MyInt operator ++(MyInt &i,int)
{
    return i.a++;
}

int main()
{
    MyInt int1(1);
    MyInt int2(2);
    MyInt int3=int1+int2;
    cout<<"int1: "<<int1.get_int()<<endl;
    cout<<"int2: "<<int2.get_int()<<endl;
    cout<<"int3=int1+int2"<<endl;
    cout<<"++int3: "<<(++int3).get_int()<<endl;
    cout<<"int3++: "<<(int3++).get_int()<<endl;
    cout<<"int3: "<<int3.get_int()<<endl;
    return 0;
}

3.成员函数运算符重载

成员函数运算符重载相比于友元函数运算符重载,最主要的区别,在于友元函数的第一个输入参数,在成员函数中使用this指针代替,因此同样的运算符重载,成员函数比友元函数参数少一个。

cpp 复制代码
#include <iostream>
using namespace std;

class MyInt
{
private:
    int a;
public:
    MyInt(int a)
    {
        this->a=a;
    }
    int get_int()
    {
        return a;
    }
    MyInt operator +(MyInt &i);
    MyInt operator ++();//前置++
    MyInt operator ++(int);//后置++
};
MyInt MyInt::operator +(MyInt &i)
{
    return this->a+i.a;
}
MyInt MyInt::operator ++()
{
    return ++this->a;
}

MyInt MyInt::operator ++(int)
{
    return this->a++;
}

int main()
{
    MyInt int1(1);
    MyInt int2(2);
    MyInt int3=int1+int2;
    cout<<"int1: "<<int1.get_int()<<endl;
    cout<<"int2: "<<int2.get_int()<<endl;
    cout<<"int3=int1+int2"<<endl;
    cout<<"++int3: "<<(++int3).get_int()<<endl;
    cout<<"int3++: "<<(int3++).get_int()<<endl;
    cout<<"int3: "<<int3.get_int()<<endl;
    return 0;
}

4.特殊运算符重载

1.赋值运算符重载

除了之前学习的无参构造函数、拷贝构造函数、析构函数以外,如果程序员不手写,编译器还会添加一个赋值运算符重载函数。

赋值运算符重载只能使用成员函数运算符实现。

当类中出现指针类型的成员变量时,默认的赋值运算符重载函数,类似于默认的浅拷贝构造函数,因此需要手动编写解决"浅拷贝"的问题。

cpp 复制代码
#include <iostream>
using namespace std;

class MyInt
{
    int a;
public:
    MyInt(int a)
    {
        this->a=a;
    }
    int get_int()
    {
        return a;
    }
    MyInt &operator =(MyInt &i)
    {
        cout<<"调用赋值运算符重载函数"<<endl;
        this->a=i.a;
        return *this;
    }
};

int main()
{
    MyInt int1(1);
    MyInt int2(2);
    cout<<"int1: "<<int1.get_int()<<endl;
    cout<<"int2: "<<int2.get_int()<<endl;
    int2=int1;
    cout<<"int2: "<<int2.get_int()<<endl;

    return 0;
}

2.类型转换运算符重载

必须使用成员函数运算符重载,且格式比较特殊。

cpp 复制代码
#include <iostream>
using namespace std;

class MyInt
{
    int a;
    string b="hello";
public:
    MyInt(int a)
    {
        this->a=a;
    }
    operator int()
    {
        return a;
    }
    operator string()
    {
        return b;
    }
};

int main()
{
    MyInt int1(1);
    int a=int1;
    string b=int1;
    cout<<"int a = "<<a<<endl;
    cout<<"string b = "<<b<<endl;
    return 0;
}

5.注意事项

1.重载的运算符限制在C++语言中已有的运算符范围,不能创建新的运算符。

2.运算符重载本质上也是函数重载,但是不支持函数默认值设定。

3.重载之后运算符不能改变运算符的优先级和结合性,也不能改变运算符的操作数和语法结构。

4.运算符重载必须基于或包含自定义类型,即不能改变基本数据类的运算规则。

5.重载的功能应该与原有的功能相似,避免没有目的的滥用运算符重载。

6.一般情况下,双目运算符建议使用友元函数运算符重载,单目运算符建议使用成员函数运算符重载。

std::string字符串类:

字符串对象是一种特殊类型的容器,专门设计用于操作字符串。

cpp 复制代码
#include <iostream>
#include <string.h>
using namespace std;

int main()
{
    string s;
    // 判断是否为空
    cout<<s.empty()<<endl;  //1

    string s1="hello";//隐式调用构造函数
    cout<<s1<<endl; //hello

    string s2("world");//显式调用构造函数
    cout<<s2<<endl; //world

    //==、!=、> 、< 判断
    cout<<(s1==s2)<<endl;   //0
    cout<<(s1!=s2)<<endl;    //1
    cout<<(s1>s2)<<endl;    //0
    cout<<(s1<s2)<<endl;    //1

    string s3(s2);//拷贝构造函数
    cout<<s3<<endl; //world

    // 参数1:char * 源字符串
    // 参数2:保留的字符串数
    string s4("ABCDE",3);
    cout<<s4<<endl;     //ABC

    // 参数1:std::string 源字符串
    // 参数2:不保留的字符数,从头开始
    string s5(s2,3);
    cout<<s5<<endl;     //ld

    // 参数1:字符数量
    // 参数2:字符内容 char
    string s6(5,'a');
    cout<<s6<<endl;     //aaaaa

    cout << "原s5 = " << s5 << " " << "原s6 = " << s6 << endl;
    swap(s5,s6);    // 交换
    cout << "交换后s5 = " << s5 << " " << "交换后s6 = " << s6 << endl;

    string s7=s1+s2;//字符串连接
    cout<<s7<<endl;     //helloworld

    s7.append("你好世界");// 向后追加字符串
    cout<<s7<<endl;     //helloworld你好世界

    s7.push_back('a');// 向后追加单个字符
    cout<<s7<<endl;     //helloworld你好世界a

    // 插入
    // 参数1:插入的位置
    // 参数2:插入的内容
    s7.insert(0,"123");
    cout<<s7<<endl;      //123helloworld你好世界a

    // 删除字符串
    // 参数1:起始位置
    // 参数2:删除的字符数量
    s7.erase(2,5);
    cout<<s7<<endl;     //12oworld你好世界a

    // 替换
    // 参数1:起始位置
    // 参数2:被替换的字符数
    // 参数3:替换的新内容
    s7.replace(0,3,"++++");
    cout<<s7<<endl;     //++++world你好世界a

    s7.clear();   // 清空
    cout<<s7.length()<<endl;     //0

    string s8="heiheihei";
    cout<<s8<<endl;     //heiheihei

    s8="ABCDEFG";    // 重新赋值
    cout<<s8<<endl;     //ABCDEFG

    // 参数1:拷贝的目标
    // 参数2:拷贝的字符数量
    // 参数3:拷贝的起始位置
    // C++的string到C语言数组
    char a[20]={0};
    s8.copy(a,3,0);
    cout<<a<<endl;      //ABC

    // C++ string 到 c string 用到了C语言中的strcpy
    // c_str C++的字符串转成C语言的字符数组
    // c_str 返回一个 const char *
    char b[20]={0};
    strcpy(b,s8.c_str());
    cout<<b<<endl;      //ABCDEFG

    return 0;
}

模板与容器

模板

模板可以让类或者函数支持一种通用类型,这种通用类型在实际运行的过程中可以使用任何数据类型,因此可以写一些与类型无关的代码,这种编程方式也被称为"泛型编程"。

通常有两种形式:
1.函数模板
2.类模板

1.函数模板

使一个函数支持模板编程,可以使函数支持通用数据类型。

cpp 复制代码
#include <iostream>
using namespace std;
template<typename T>    // typename也可以是class
T add(T a,T b)
{
    return a + b;
}

int main()
{
    string str1 = "hello";
    string str2 = "world";
    cout << add(str1,str1) << endl;
    return 0;
}

2.类模板

使一个类支持模板编程,可以使一个类支持通用数据类型。

类内实现
cpp 复制代码
#include <iostream>
using namespace std;

template<class T>
class Test
{
private:
    T val;
public:
    Test(T v)
    {
        val = v;
    }

    T get_val()const
    {
        return val;
    }

    void set_val(const T &val)
    {
        this->val = val;
    }
};

int main()
{
    Test<int> t1(20);
    cout << t1.get_val() << endl;
    t1.set_val(10);
    cout << t1.get_val() << endl;

    t1.set_val(10.32);
    cout << t1.get_val() << endl;   // 数据窄化10

    Test<double> t2(2.56);
    cout << t2.get_val() << endl;
    t2.set_val(23.12);
    cout << t2.get_val() << endl;

    return 0;
}
类内声明类外实现
cpp 复制代码
#include <iostream>
using namespace std;

template<class T>
class Test
{
private:
    T val;
public:
    Test(T v);
    T get_val()const;
    void set_val(const T &val);
};

template<class T>
Test<T>::Test(T v)
{
    val = v;
}

template<class T>
T Test<T>::get_val()const
{
    return val;
}

template<class T>
void Test<T>::set_val(const T &val)
{
    this->val = val;
}


int main()
{
    Test<int> t1(20);
    cout << t1.get_val() << endl;
    t1.set_val(10);
    cout << t1.get_val() << endl;

    t1.set_val(10.32);
    cout << t1.get_val() << endl;   // 数据窄化10

    Test<double> t2(2.56);
    cout << t2.get_val() << endl;
    t2.set_val(23.12);
    cout << t2.get_val() << endl;

    return 0;
}
相关推荐
2401_872514972 分钟前
HTTP代理域名解析的先后顺序:深入解析
开发语言·网络·网络协议·tcp/ip·http·php
极地星光2 分钟前
设计模式-策略模式
c++·设计模式·策略模式
Q_hd2 分钟前
【Java】Java开发全攻略:从环境搭建到高效编程
java·开发语言
deardeer72 分钟前
Leetcode算法基础篇-分治算法
数据结构·算法·leetcode
乘风破浪的咸鱼君4 分钟前
2024/9/21 leetcode 19题 24题
数据结构·算法·leetcode
白帽黑客鹏哥8 分钟前
花8000元去培训机构学习网络安全值得吗,学成后就业前景如何?
运维·网络·学习·安全·web安全
洪大宇16 分钟前
常用的一些代码片段
开发语言
ᅠᅠᅠ@23 分钟前
js使用:
开发语言·javascript·ecmascript
无名之逆29 分钟前
云原生(Cloud Native)简介及相关技术
开发语言·c++·人工智能·ai·云原生·期末速成·大学期末
月夕花晨37433 分钟前
C++学习笔记(35)
c++·笔记·学习