C++ 运算符重载

本文介绍了C++ 运算符重载的用法,以我们构造的string类为例子,说明重载的用法。

构造我们自己的string类

声明如下

class mystring_
{
public:
    mystring_(/* args */);
    mystring_(const mystring_ &mstr);
    mystring_(const char *m_str);
    mystring_(const string);
    ~mystring_();

    friend ostream &operator<<(ostream &os, const mystring_ &mystr1);
    mystring_ &operator=(const mystring_ &mystr);
    mystring_ &operator=(string str);
    mystring_ &operator=(const char *cstr);
    friend mystring_ operator+(const mystring_ &str1, const mystring_ &str2);
    char operator[](unsigned int index);
    friend class mystringOpr_;

private:
    char *m_str;
};

在string类里重载了输出运算符<<,赋值运算符=, 加法运算符+, 取下标运算符[], 又声明了友元类mystringOpr。

class mystringOpr_
{
public:
    bool operator()(const mystring_ &, const mystring_ &);
};

该类重载了()运算符,这样mystringOpr的实例对象就是可调用对象了,可以当作仿函数使用。

mystring_类的具体实现

我们先实现构造函数和析构函数

mystring_::mystring_(/* args */) : m_str("")
{
}
mystring_::mystring_(const mystring_ &mystr)
{
    if (&mystr == this)
    {
        return;
    }

    if (mystr.m_str == nullptr)
    {
        m_str = nullptr;
        return;
    }
    size_t len = strlen(mystr.m_str);
    m_str = new char[len + 1];
    strcpy(m_str, mystr.m_str);
    m_str[len] = '\0';
}

mystring_::mystring_(const char *mstr)
{
    cout << "use mystring_ construct , param is const char *" << endl;
    size_t len = strlen(mstr);
    m_str = new char[len + 1];
    strcpy(m_str, mstr);
    m_str[len] = '\0';
}

mystring_::mystring_(const string str)
{
    cout << "use mystring_ construct string str" << endl;
    size_t len = str.length();
    m_str = new char[len + 1];
    strncpy(m_str, str.c_str(), len);
    m_str[len] = '\0';
}

mystring_::~mystring_()
{
    if (m_str == "" || m_str == nullptr)
    {
        cout << "begin destruct , str is null or empty" << endl;
    }
    else
    {
        cout << "begin destruct " << m_str << endl;
    }

    if (m_str == nullptr || m_str == "")
    {
        return;
    }

    delete[] m_str;
    m_str = nullptr;
}

实现了形参不同的拷贝构造函数,包括const string类型,const char*类型,const mystring_ &类型,以及默认的无参构造函数。
接下来重载+运算符

mystring_ operator+(const mystring_ &str1, const mystring_ &str2)
{
    size_t len = strlen(str1.m_str) + strlen(str2.m_str) + 1;
    mystring_ strtotal;
    strtotal.m_str = new char[len + 1];
    memset(strtotal.m_str, 0, len);
    memcpy(strtotal.m_str, str1.m_str, strlen(str1.m_str));
    strcat(strtotal.m_str, str2.m_str);
    return strtotal;
}

重载=运算符

mystring_ &mystring_::operator=(const mystring_ &mystr)
{
    if (&mystr == this)
    {
        return *this;
    }

    if (this->m_str != nullptr)
    {
        delete[] m_str;
        this->m_str = nullptr;
    }

    if (mystr.m_str == nullptr)
    {
        m_str = nullptr;
    }

    size_t len = strlen(mystr.m_str);
    m_str = new char[len + 1];
    strcpy(m_str, mystr.m_str);
    m_str[len] = '\0';
    return *this;
}

mystring_ &mystring_::operator=(string str)
{
    cout << "use operator = string str" << endl;
    if (this->m_str != nullptr)
    {
        delete[] m_str;
        this->m_str = nullptr;
    }

    size_t len = str.length();
    m_str = new char[len + 1];
    strncpy(m_str, str.c_str(), len);
    m_str[len] = '\0';
    return *this;
}

mystring_ &mystring_::operator=(const char *cstr)
{
    cout << "use operator = const char*" << endl;
    if (this->m_str != nullptr)
    {
        delete[] m_str;
        this->m_str = nullptr;
    }

    size_t len = strlen(cstr);
    m_str = new char[len + 1];
    strncpy(m_str, cstr, len);
    m_str[len] = '\0';
    return *this;
}

重载输出运算符

ostream &operator<<(ostream &os, const mystring_ &mystr1)
{
    if (mystr1.m_str == nullptr)
    {
        os << "mystring_ data is null" << endl;
        return os;
    }
    os << "mystring_ data is " << mystr1.m_str << endl;
    return os;
}

重载取下表运算符[]

char mystring_::operator[](unsigned int index)
{
    if (index >= strlen(m_str))
    {
        throw "index out of range!!!";
    }

    return m_str[index];
}

我们写一个函数测试重载效果

void use_mystr_1()
{
    auto mystr1 = mystring_("hello zack");
    auto mystr2(mystr1);
    auto mystr3 = mystring_();
    cout << mystr1 << mystr2 << mystr3 << endl;
    mystring_ mystr4 = ", i love u";
    auto mystr5 = mystr1 + mystr4;
    cout << "mystr4 is " << mystr4 << endl;
    cout << "mystr5 is " << mystr5 << endl;

    mystring_ mystr6 = "";
    auto mystr7 = mystr5 + mystr6;
    cout << "mystr7 is " << mystr7 << endl;

    auto ch = mystr1[4];
    cout << "index is 4, char is " << ch << endl;
}

测试结果如下

use mystring_ construct , param is const char *
mystring_ data is hello zack
mystring_ data is hello zack
mystring_ data is

use mystring_ construct , param is const char *
mystr4 is mystring_ data is , i love u

mystr5 is mystring_ data is hello zack, i love u

use mystring_ construct , param is const char *
mystr7 is mystring_ data is hello zack, i love u

index is 4, char is o

可以看出调用不同的构造函数会打印不同的日志,重载+运算符实现了字符串的拼接,重载赋值实现了拷贝。

通过仿函数mystringOpr_实现排序

我们先实现仿函数,这样就可以对我们mystring_类对象排序了

bool mystringOpr_::operator()(const mystring_ &str1, const mystring_ &str2)
{
    if (strlen(str1.m_str) > strlen(str2.m_str))
    {
        return true;
    }

    if (strlen(str1.m_str) < strlen(str2.m_str))
    {
        return false;
    }

    for (unsigned int i = 0; i < strlen(str1.m_str); i++)
    {
        return str1.m_str[i] > str2.m_str[i];
    }
}

我们调用sort实现mystring_排序,在原来的基础上补充排序代码

void use_mystr_1()
{
    auto mystr1 = mystring_("hello zack");
    auto mystr2(mystr1);
    auto mystr3 = mystring_();
    cout << mystr1 << mystr2 << mystr3 << endl;
    mystring_ mystr4 = ", i love u";
    auto mystr5 = mystr1 + mystr4;
    cout << "mystr4 is " << mystr4 << endl;
    cout << "mystr5 is " << mystr5 << endl;

    mystring_ mystr6 = "";
    auto mystr7 = mystr5 + mystr6;
    cout << "mystr7 is " << mystr7 << endl;

    auto ch = mystr1[4];
    cout << "index is 4, char is " << ch << endl;

    std::vector<mystring_> vec_mystring_;
    vec_mystring_.push_back(mystr1);
    vec_mystring_.push_back(mystr2);
    vec_mystring_.push_back(mystr3);
    vec_mystring_.push_back(mystr4);
    vec_mystring_.push_back(mystr5);
    vec_mystring_.push_back(mystr6);
    vec_mystring_.push_back(mystr7);
    sort(vec_mystring_.begin(), vec_mystring_.end(), mystringOpr_());
    cout << "====================after sort ..." << endl;
    for_each(vec_mystring_.begin(), vec_mystring_.end(), [](const mystring_ &str)
             { cout << str << endl; });
}

上述代码通过sort排序vector里的mystring_对象,并用lambda表达式输出,可以看到输出

use mystring_ construct , param is const char *
mystring_ data is hello zack
mystring_ data is hello zack
mystring_ data is

use mystring_ construct , param is const char *
mystr4 is mystring_ data is , i love u

mystr5 is mystring_ data is hello zack, i love u

use mystring_ construct , param is const char *
mystr7 is mystring_ data is hello zack, i love u

index is 4, char is o
====================after sort ...
mystring_ data is hello zack, i love u

mystring_ data is hello zack, i love u

mystring_ data is hello zack

mystring_ data is hello zack

mystring_ data is , i love u

mystring_ data is

mystring_ data is

我们通过仿函数和sort实现了mystring_从大到小的排序。

总结

源码链接:https://gitee.com/secondtonone1/cpplearn

视频链接: https://www.bilibili.com/video/BV1zu411e7DW/

热门评论

热门文章

  1. slice介绍和使用

    喜欢(521) 浏览(1665)
  2. Linux环境搭建和编码

    喜欢(594) 浏览(5342)
  3. windows环境搭建和vscode配置

    喜欢(587) 浏览(1691)
  4. 解密定时器的实现细节

    喜欢(566) 浏览(1789)
  5. C++ 类的继承封装和多态

    喜欢(588) 浏览(2499)

最新评论

  1. 利用内存模型优化无锁栈 卡西莫多的礼物:感谢博主指点,好人一生平安o(* ̄▽ ̄*)ブ
  2. 类和对象 陈宇航:支持!!!!
  3. 泛型算法的定制操作 secondtonone1:lambda和bind是C11新增的利器,善于利用这两个机制可以极大地提升编程安全性和效率。
  4. 基于锁实现线程安全队列和栈容器 secondtonone1:我是博主,你认真学习的样子的很可爱,哈哈,我画的是链表由空变成1个的情况。其余情况和你思考的类似,只不过我用了一个无效节点表示tail的指向,最初head和tail指向的都是这个节点。
  5. 解决博客回复区被脚本注入的问题 secondtonone1:走到现在我忽然明白一个道理,无论工作也好生活也罢,最重要的是开心,即使一份安稳的工作不能给我带来事业上的积累也要合理的舍弃,所以我还是想去做喜欢的方向。

个人公众号

个人微信