C++的运算符重载
使对象的运算表现得和编译器内置类型一样
template<typename T>
T sum(T a, T b)
{
return a+b;
}
如果T是编译器的内置类型的话,编译器对a+b是可以做的。 但是如果T是我们自定义的对象类型,a和b是两个对象,对象和对象之间该怎么相加???编译器是不知道的。 这里就要使用运算符的重载了。
return a+b;
加法运算符的重载函数。
复数类的实现(运算符重载)
这个构造函数相当于可以构造3种不同的复数对象。
#include <iostream>
using namespace std;
class CComplex
{
public:
CComplex(int r = 0, int i = 0)
:mreal(r), mimage(i) {}
CComplex operator++(int)
{
return CComplex(mreal++, mimage++);
}
CComplex& operator++()
{
mreal += 1;
mimage += 1;
return *this;
}
void operator+=(const CComplex &src)
{
mreal += src.mreal;
mimage += src.mimage;
}
void show() { cout << "real:" << mreal << " image:" << mimage << endl; }
private:
int mreal;
int mimage;
friend CComplex operator+(const CComplex &lhs, const CComplex &rhs);
friend ostream& operator<<(ostream &out, const CComplex &src);
friend istream& operator>>(istream &in, CComplex &src);
};
CComplex operator+(const CComplex &lhs, const CComplex &rhs)
{
return CComplex(lhs.mreal + rhs.mreal, lhs.mimage + rhs.mimage);
}
ostream& operator<<(ostream &out, const CComplex &src)
{
out << "mreal:" << src.mreal << " mimage:" << src.mimage << endl;
return out;
}
istream& operator>>(istream &in, CComplex &src)
{
in >> src.mreal >> src.mimage;
return in;
}
int main()
{
CComplex comp1(10, 10);
CComplex comp2(20, 20);
CComplex comp3 = comp1 + comp2;
comp3.show();
CComplex comp4 = comp1 + 20;
comp4.show();
CComplex comp5 = 30 + comp1;
comp5.show();
comp5 = comp1++;
comp1.show();
comp5.show();
comp5 = ++comp1;
comp1.show();
comp5.show();
comp1 += comp2;
cout << comp1 << endl;
cin >> comp1 >> comp2;
cout << comp1 << comp2 << endl;
return 0;
}
C++string类的实现
这个写法的效率不好。ptmp指向new出来的内存,然后字符串拷贝,连接,当做参数传入tmp对象,tmp构造的时候又会根据传进来的指针进行判空,然后开辟内存,进行字符串拷贝,然后把这个ptmp指针delete掉,tmp是局部对象,return tmp,析构的时候又要把刚才构造时new出来的空间delete掉,2次new2次delete,太麻烦了。 我们应该这么做:
String operator+(const String& lhs, const String& rhs)
{
String tmp;
tmp._pstr = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
strcpy(tmp._pstr, lhs._pstr);
strcat(tmp._pstr, rhs._pstr);
return tmp;
}
这样就比刚才少了1次的new和delete操作。 但是是临时对象,还是要进行大量的拷贝构造,优化的方法是调用右值引用构造。
迭代器是容器类型的嵌套类。 我们假设有一个string对象,里面有一堆字符串,这些内容我们是看不见,因为是私有的。 我们想迭代string对象底层的字符串的字符,用迭代器是怎么做到的? 容器有一个begin方法,返回的是底层首元素的迭代器。 it指向了字符串底层的首元素。 容器的end方法,返回的是最后一个元素的后继位置的迭代器。 我们只需要不断的遍历,遍历到最后一个元素,往后再走,遇到end()迭代器,就退出。 ++it,就是从当前元素跳到下一个元素去遍历。不需要管底层的数据结构。我们作为使用者只需要用迭代器++,不同的数据结构的差异都封装在迭代器++的重载运算符函数里面。 对迭代器解引用,就是访问迭代器访问的底层的数据。 不同容器底层的数据结构不一样,每一种容器都有自己的迭代器,设置成嵌套类型。 迭代器用的都是前置++,因为返回的是*this,效率比较高,不用生成临时对象。 迭代器的功能:提供一种统一的方式,来透明的遍历容器,我们不需要知道底层的数据结构,都封装在迭代器的++操作里面
#include <iostream>
#include <string>
using namespace std;
class String
{
public:
String(const char *p = nullptr)
{
if (p != nullptr)
{
_pstr = new char[strlen(p) + 1];
strcpy(_pstr, p);
}
else
{
_pstr = new char[1];
*_pstr = '\0';
}
}
~String()
{
delete[]_pstr;
_pstr = nullptr;
}
String(const String &str)
{
_pstr = new char[strlen(str._pstr) + 1];
strcpy(_pstr, str._pstr);
}
String& operator=(const String &str)
{
if (this == &str)
return *this;
delete[]_pstr;
_pstr = new char[strlen(str._pstr) + 1];
strcpy(_pstr, str._pstr);
return *this;
}
bool operator>(const String &str)const
{
return strcmp(_pstr, str._pstr) > 0;
}
bool operator<(const String &str)const
{
return strcmp(_pstr, str._pstr) < 0;
}
bool operator==(const String &str)const
{
return strcmp(_pstr, str._pstr) == 0;
}
int length()const { return strlen(_pstr); }
const char* c_str()const { return _pstr; }
char& operator[](int index) { return _pstr[index]; }
const char& operator[](int index)const { return _pstr[index]; }
class iterator
{
public:
iterator(char *p = nullptr) :_p(p) {}
bool operator!=(const iterator &it)
{
return _p != it._p;
}
void operator++()
{
++_p;
}
char& operator*() { return *_p; }
private:
char *_p;
};
iterator begin() { return iterator(_pstr); }
iterator end() { return iterator(_pstr + length()); }
private:
char *_pstr;
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)
{
String tmp;
tmp._pstr = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];
strcpy(tmp._pstr, lhs._pstr);
strcat(tmp._pstr, rhs._pstr);
return tmp;
}
ostream& operator<<(ostream &out, const String &str)
{
out << str._pstr;
return out;
}
int main()
{
String str1 = "hello world!";
auto it = str1.begin();
for (; it != str1.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
for(char ch : str1)
{
cout << ch << " ";
}
cout << endl;
String str1;
String str2 = "aaa";
String str3 = "bbb";
String str4 = str2 + str3;
String str5 = str2 + "ccc";
String str6 = "ddd" + str2;
cout << "str6:" << str6 << endl;
if (str5 > str6)
{
cout << str5 << " > " << str6 << endl;
}
else
{
cout << str5 << " < " << str6 << endl;
}
int len = str6.length();
for (int i = 0; i < len; ++i)
{
cout << str6[i] << " ";
}
cout << endl;
char buf[1024] = { 0 };
strcpy(buf, str6.c_str());
cout << "buf:" << buf << endl;
return 0;
}
这2种写法等价。
auto自动根据等号右边的类型推导左边的类型,写起来比较简单方便。
|