C++复健:运算符重载,实现string容器,实现string和vector的迭代器

使得对象的运算像内置类型一样

a.operator+(b);

重载运算符的一些注意点:

  1. 不能重载运算符操作基础数据类型:(1)重载运算符必须和用户定义的class类型一起使用(2)重载的运算符的参数至少有一个应该是一个类对象(或类对象的引用)

    int operator+(int x);//错误
    
  2. 编译器做对象运算会调用对象的运算符重载函数,优先调用成员方法,若无则在全局作用查找合适的运算符重载函数

双目运算符

#include <iostream>

class Complex {
public:
    Complex(int r = 0, int i = 0) :real(r), img(i) {}
    Complex operator+(const Complex& com) {
        Complex c;
        c.real = this->real + com.real;
        c.img = this->img + com.img;
        return c;
        //return Complex(this->real+).....
        //不要返回一个局部变量的指针或引用
    }
    int getreal()const { return real; }
private:
    int real;
    int img;
    friend Complex operator+(const Complex& lhs, const Complex& rhs);
};
//友元函数
Complex operator+(const Complex& lhs, const Complex& rhs) {
    return Complex(lhs.real+rhs.real,lhs.img+rhs.img);
}

//Complex operator+(int i,const Complex& com) {
//    return Complex(i+com.getreal());
//}
int main()
{
    //双目运算符:
    Complex c1(1, 1);
    Complex c2(2, 2);
    //加法运算符的重载函数 c1.operator+(c2);
    Complex c3 = c1 + c2;//需要返回一个对象
    Complex c4 = c1 + 20;//若类中有一个int参数的构造函数则可以隐式转换为复数类型
    //::operator+(20,c1);
    Complex c4 = 20 + c1;//无法调用成员重载函数,调用全局函数
    //此处的全局函数可以做三种运算

}

+=

//成员函数:
void operator+=(Complex& com){
        real += com.real;
        img += com.img;
    }

<<运算符

对象不在左侧,所以要写成全局方法 ::operator(cout,com1);为了连续的输出,要返回ostream&

//友元:
ostream& operator<<(ostream& out, const Complex& src) {
    out << "real:" << src.real << " img:" << src.img << endl;
    return out;
}
istream& operator>>(istream& in, Complex& src) {
    in >> src.real >> src.img;
    return in;
}

string实现了关系运算符<等和[]运算符,=运算符

关系运算符

//关系运算符
bool operator>(const String& str)const {
	return strcmp(m_str,str.m_str)>0;
}
bool operator<(const String& str)const {
	return strcmp(m_str, str.m_str) < 0;
}
bool operator==(const String& str)const {
	return strcmp(m_str, str.m_str) == 0;
}

[]运算符

将下标作为实参传入str.operator[](i)

	char& operator[](int index) { return m_str[index]; }
	//常对象调用下面的版本,不允许修改
	const char& operator[](int index)const { return m_str[index]; }

String的实现:

#include<iostream>
//#include<string>
using namespace std;

class String {
private:
	char* m_str;
public:
	String(const char* str = nullptr) {
		if (str != nullptr) {
			m_str = new char[strlen(str) + 1];
			strcpy(m_str,str);
		}
		else {
			m_str = new char[1];
			*m_str = '\0';
		}
	}
	~String() {
		delete[] m_str;
		m_str = nullptr;
	}
	//浅拷贝有问题
	//所以实现拷贝构造函数
	String(const String& str) {
		m_str = new char[strlen(str.m_str) + 1];
		strcpy(m_str,str.m_str);
	}
	//赋值运算符
	String& operator=(const String& src) {
		if (this == &src)return *this;
		delete[] m_str;
		m_str = new char[strlen(src.m_str) + 1];
		strcpy(m_str,src.m_str);
	}
	//关系运算符
	bool operator>(const String& str)const {
		return strcmp(m_str,str.m_str)>0;
	}
	bool operator<(const String& str)const {
		return strcmp(m_str, str.m_str) < 0;
	}
	bool operator==(const String& str)const {
		return strcmp(m_str, str.m_str) == 0;
	}
	int length() { return strlen(m_str); }

	char& operator[](int index) { return m_str[index]; }
	//常对象调用下面的版本,不允许修改
	const char& operator[](int index)const { return m_str[index]; }

	const char* c_str()const { return m_str; }
	friend String operator+(const String& lhs, const String& rhs);
	friend ostream& operator<<(ostream& out, const String& str);
};
String operator+(const String& lhs, const String& rhs) {
	char* tmp = new char[strlen(lhs.m_str) + strlen(rhs.m_str) + 1];
	strcpy(tmp,lhs.m_str);
	strcat(tmp,rhs.m_str);
	String t(tmp);//为了析构
	delete[] tmp;
	return t;
}
ostream& operator<<(ostream& out, const String& str) {
	out << str.m_str;
	return out;
}

这里的+运算符重载效率很低,进行了多次的空间开辟

//直接对对象底层的char*开辟空间
String operator+(const String& lhs, const String& rhs) {
	//char* tmp = new char[strlen(lhs.m_str) + strlen(rhs.m_str) + 1];
	String tmp;
	tmp.m_str = new char[strlen(lhs.m_str) + strlen(rhs.m_str) + 1];
	strcpy(tmp.m_str,lhs.m_str);
	strcat(tmp.m_str,rhs.m_str);
	return tmp;
}
//并非最优秀,涉及了临时对象的拷贝,构造

使用迭代器可以遍历string容器

实现String的迭代器

字符串底层成员是私有的

迭代器是容器类型的嵌套类,迭代器可以透明的访问容器内部的元素的值,无需知道底层类型(是一种统一的方式)

string::iterator it = str1.begin();//begin返回底层首元素的迭代器表示,it指向首元素
str1.ene()//表示最后一个元素的后继位置的迭代器

迭代器需要提供++运算符重载,*运算符重载

#include<iostream>
//#include<string>
using namespace std;

class String {
private:
	char* m_str;
public:
	String(const char* str = nullptr) {
		if (str != nullptr) {
			m_str = new char[strlen(str) + 1];
			strcpy(m_str,str);
		}
		else {
			m_str = new char[1];
			*m_str = '\0';
		}
	}
	~String() {
		delete[] m_str;
		m_str = nullptr;
	}
	//浅拷贝有问题
	//所以实现拷贝构造函数
	String(const String& str) {
		m_str = new char[strlen(str.m_str) + 1];
		strcpy(m_str,str.m_str);
	}
	//赋值运算符
	String& operator=(const String& src) {
		if (this == &src)return *this;
		delete[] m_str;
		m_str = new char[strlen(src.m_str) + 1];
		strcpy(m_str,src.m_str);
	}
	//关系运算符
	bool operator>(const String& str)const {
		return strcmp(m_str,str.m_str)>0;
	}
	bool operator<(const String& str)const {
		return strcmp(m_str, str.m_str) < 0;
	}
	bool operator==(const String& str)const {
		return strcmp(m_str, str.m_str) == 0;
	}
	int length() { return strlen(m_str); }

	char& operator[](int index) { return m_str[index]; }
	//常对象调用下面的版本,不允许修改
	const char& operator[](int index)const { return m_str[index]; }

	const char* c_str()const { return m_str; }
	friend String operator+(const String& lhs, const String& rhs);
	friend ostream& operator<<(ostream& out, const String& str);
	//迭代器
	class iterator {
	public:
		//迭代器的底层是一个位置
		iterator(char* p = nullptr):m_p(p) {

		}
	//两个迭代器不相等就是底层指针的不相等
		bool operator!=(const iterator& it) {
			return m_p != it.m_p;
		}
		void operator++() {
			++m_p;
		}
		char& operator*() { return *m_p; }
	private:
		char* m_p;//用指针去迭代m_str
	};
	//返回容器底层首元素的迭代器表示
	iterator begin() { return iterator(m_str); }
	//返回容器底层末尾元素后继位置的迭代器表示
	iterator end() { return iterator(m_str + length()); }

	
};
String operator+(const String& lhs, const String& rhs) {
	//char* tmp = new char[strlen(lhs.m_str) + strlen(rhs.m_str) + 1];
	String tmp;
	tmp.m_str = new char[strlen(lhs.m_str) + strlen(rhs.m_str) + 1];
	strcpy(tmp.m_str,lhs.m_str);
	strcat(tmp.m_str,rhs.m_str);
	return tmp;
}
ostream& operator<<(ostream& out, const String& str) {
	out << str.m_str;
	return out;
}
int main()
{

	String str = "hello,world";
	for (auto it = str.begin(); it != str.end(); ++it) {
		cout<<*it<<" ";
	}

}

自己实现的容器中设置了迭代器则可以使用foreach遍历容器,否则不可foreach

单目运算符

++,--运算符 单目运算符 operator++() operator(int) 为了区分前置后置,前者为前置

写为成员函数:

	Complex operator++(int) {
        //先返回旧值再++
        Complex comp = *this;
        real += 1;
        img += 1;
        return comp;
        //return Complex().....
    }
    Complex& operator++() {
        real += 1;
        img += 1;
        return *this;//非局部对象所以返回引用提高效率
    }

友元和重载

class Vec2D {
public:
  friend Vec2D operator+(Vec2D &firstVec, Vec2D &secondVec);
  // friend double& operator[](Vec2D &v, const int &index);
  // operator[] 不能重载为友元函数,只能重载为成员函数
  friend Vec2D operator++(Vec2D &v);
  friend Vec2D operator++(Vec2D &v, int dummy);
}

函数调用运算符(函数对象)

如果类定义了函数运算符,则此类的对象称为函数对象

一个类可以定义多个,只要它们参数类型或数量有所不同

#include<iostream>
using namespace std;

class absInt
{
public:
    int operator()(int val)const {
        return val<0?-val:val;
    }
};
int main()
{
    //调用方式:
    // 将i传递给absobj.operator()
    absInt absobj;
    int i = -1;
    int ui = absobj(i);
    system("pause");
    return 0;
}

vector的迭代器

实现为vector的嵌套类

template<typename T>
class Allocator
{
public:

    T* allocate(size_t size)//开辟内存
    {
        return (T*)malloc(sizeof(T) * size);

    }
    void deallocate(void* p)//释放内存
    {
        free(p);
    }
    void construct(T* p, const T& val)//
    {
        new (p) T(val);//在指定的内存上构造(调用T的拷贝构造)
    }
    void destory(T* p)//对象析构
    {
        p->~T();
    }
};
template<typename T,typename Alloc = Allocator<T>>
class Vector 
{
public:
    Vector(int size = 10,const Alloc& alloc = Allocator<T>())
        :m_alloc(alloc)
    {
        //m_first = new T[size];
        m_first = m_alloc.allocate(size);
        m_last = m_first;
        m_end = m_first + size;
    }
    ~Vector()
    {
        //delete[] m_first;
        for (T* p = m_first; p != m_last; ++p)
        {
            m_alloc.destory(p);//将有效元素析构
        }
        m_alloc.deallocate(m_first);//释放堆上的内存
        m_first = m_last = m_end = nullptr;
    }
    Vector(const Vector<T>& rhs)
    {
        int size = rhs.m_end - rhs.m_first;
        //m_first = new T[size];
        m_first = m_alloc.allocate(size);
        int len = rhs.m_last - rhs.m_first;
        for (int i = 0; i < len; i++)
        {
            //m_first[i] = rhs.m_first[i];
            m_alloc.construct(m_first + i, rhs.m_first[i]);
        }
        m_last = m_first + len;
        m_end = m_first + size;
    }
    Vector<T>& operator=(const Vector<T>& rhs)
    {
        if (this == &rhs)return *this;
        /*delete[] m_first;*/
        for (T* p = m_first; p != m_last; ++p)
        {
            m_alloc.destory(p);//将有效元素析构
        }
        m_alloc.deallocate(m_first);//释放堆上的内存
        int size = rhs.m_end - rhs.m_first;
        m_first = new T[size];
        int len = rhs.m_last - rhs.m_first;
        for (int i = 0; i < len; i++)
        {
            m_first[i] = rhs.m_first[i];
        }
        m_last = m_first + len;
        m_end = m_first + size;
        return *this;
    }
    void push_back(const T& val)
    {
        if (full())expand();
        //*m_last++ = val;
        m_alloc.construct(m_last,val);
        m_last++;
    }
    void pop_back()
    {
        if (empty())return;
        --m_last;
        m_alloc.destory(m_last);
    }
    T back()const
    {
        return *(m_last - 1);
    }
    bool full()const { return m_last == m_end; }
    bool empty()const { return m_first == m_last; }
    int size()const { return m_last - m_first; }

    //提供使用数组下标访问
    T& operator[](int index)
    {
        if (index < 0 || index >= size())
        {
            throw "OutOfRangeException";
        }
        return m_first[index];
    }
    //迭代器实现为嵌套类,所以知道vector底层的成员
    class iterator
    {
    public:
        iterator(T* ptr = nullptr)
            :m_p(ptr) {}
        bool operator!=(const iterator& it)const
        {
            return m_p != it.m_p;
        }
        void operator++()
        {
            m_p++;
        }
        T& operator*()
        {
            return *m_p;
        }
        const T& operator*()const
        {
            return *m_p;
        }
    private:
        T* m_p;
    };
    iterator begin() { return iterator(m_first); }
    iterator end() { return iterator(m_last); }
private:
    T* m_first;
    T* m_last;
    T* m_end;
    Allocator<T> m_alloc;
    void expand()
    {
        int size = m_end - m_first;
        //T* t = new T[2 * size];
        T* t = m_alloc.allocate(2*size);
        for (int i = 0; i < size; i++)
        {
            t[i] = m_first[i];
        }
        //delete[] m_first;
        for (T* p = m_first; p != m_last; ++p)
        {
            m_alloc.destory(p);//将有效元素析构
        }
        m_alloc.deallocate(m_first);//释放堆上的内存
        m_first = nullptr;
        m_first = t;
        m_last = m_first + size;
        m_end = m_first + 2 * size;
    }
};

测试:

int main()
{
    Vector<int>vec;
    for (int i = 0; i < 20; i++)
    {
        vec.push_back(i);
    }
    Vector<int>::iterator it = vec.begin();
    for (; it != vec.end(); ++it)
    {
        cout << *it <<" ";
    }
    cout << endl;
    return 0;
}
//输出:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

原文链接: https://www.cnblogs.com/ziggystardust-pop/p/17068141.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    C++复健:运算符重载,实现string容器,实现string和vector的迭代器

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/314503

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月16日 下午1:23
下一篇 2023年2月16日 下午1:23

相关推荐