运算符的重载(2)
5.左移(输出)运算符重载
如我们所知,IO标准库分别使用>>
和<<
执行输入输出操作。对于这两个运算符来说,IO库定义了其用读写内置类型的版本,但是类则需自定义适合其对象的新版本支持IO操作。
通过情况下左移运算符的第一形参是一个非常量ostream的引用。而ostream是非常量的原因是向流写入内容会改变其状态。而该形参是引用,是因为我们无法直接复制一个ostream对象。
第二个形参一般来说是一个常量的引用,该常量是我们想要打印的类类型。第二个形参是引用的原因是我们希望避免复制实参,而形参为常量是因为打印对象不会改变对象的内容。
举例如下:
#include <iostream>
#include<string>
using namespace std;
class Person
{
friend ostream &operator<<(ostream &cout, const Person &p);
public:
Person(string name, int age);
private:
string m_name;
int m_age;
};
Person::Person(string name, int age)
{
this->m_name = name;
this->m_age = age;
}
ostream &operator<<(ostream &cout, const Person &p)
{
cout << p.m_name << "的年龄为:" << p.m_age << endl;
return cout;
}
void test()
{
Person p("Aoki", 20);
cout << p;
cout << "Hello world" << endl;
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
输出结果如下:
6.右移(输入)运算符重载
通常情况下,输入运算符的第一个形参是运算符简要读取的流的引用,第二个形参是将要读入的非常量对象的引用。该运算符通常会返回某个给定流的引用。第二个形参之所以必须是个非常量是因为输入运算符本身的目的就是将数据读入到这个对象中。
#include <iostream>
#include<string>
using namespace std;
class Person
{
friend istream &operator>>(istream &cin, Person &p);
public:
Person (){}
Person(string name, int age);
void Show();
private:
string m_name;
int m_age;
};
Person::Person(string name, int age)
{
this->m_name = name;
this->m_age = age;
}
istream & operator>>(istream & cin, Person & p)
{
string name;
int age;
cin >> name >> age;
if (cin)
{
p.m_name = name;
p.m_age = age;
}
else
{
p = Person();//如果输入失败,对象被赋予默认状态
}
return cin;
}
void Person::Show()
{
cout << this->m_name << "的年龄是:" << this->m_age << endl;
}
void test()
{
Person p1;
cin >> p1;
p1.Show();
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
输出结果如下:
可以注意到,在输入运算符重载中,有输入失败的处理。那么输入时可能会发生什么错误呢?
- 当流含有错误类型的数据时读取操作可能失败
- 当读取操作到达文件末尾或遇到输入流的其他错误时也会失败
在程序中我们没有逐个检查每个读取操作,而是等读取了所有数据之后赶在使用这些数据前面进行了一次性的检查。
如果在发生错误之前对象已经有一部分改变,则适时地将对象置为合法状态显得异常重要。
通过将对象置为合法状态,我们能保护使用者免受到输入错误的影响。此时的对象处于可用状态,即它的成员都是被正确定义的。而且该对象也不会产生误导性结果,因为它的数据本质上是一致的。
7.指针运算符重载
#include <iostream>
#include<string>
using namespace std;
class Person
{
public:
Person(string name, int age);
void Display();
private:
string m_name;
int m_age;
};
class SmartPointer
{
public:
SmartPointer(Person *person);
Person* operator->();
Person& operator*();
~SmartPointer();
public:
Person *pPerson;
};
Person::Person(string name, int age)
{
this->m_name = name;
this->m_age = age;
}
void Person::Display()
{
cout << this->m_name << "的年龄是:" << this->m_age << endl;
}
SmartPointer::SmartPointer(Person * person)
{
this->pPerson = person;
}
Person * SmartPointer::operator->()
{
//重载指针的->运算符
return pPerson;
}
Person & SmartPointer::operator*()
{
//重载指针的*运算符
return *pPerson;
}
SmartPointer::~SmartPointer()
{
if (pPerson != NULL)
{
delete pPerson;
}
}
void test()
{
Person *person = new Person("Aoki", 20);
//如果忘记释放,那么就会造成内存泄漏
SmartPointer poiner(new Person("Aoki", 20));
poiner->Display();
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
输出结果如下:
8.赋值运算符重载
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include<string>
using namespace std;
class Person
{
public:
Person(const char *name);
Person& operator=(const Person &p);
~Person();
public:
char *name;
};
Person::Person(const char * name)
{
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
}
Person & Person::operator=(const Person & p)
{
if (this->name != NULL)
{//判断原来堆区中是否有内容,如果有,先释放
delete[] this->name;
this->name = NULL;
}
this->name = new char[strlen(p.name) + 1];
strcpy(this->name, p.name);
return *this;
}
Person::~Person()
{
if (this->name != NULL)
{
delete[] this->name;
this->name = NULL;
}
}
void test()
{
Person p1("Aoki");
Person p2("青木");
p1 = p2;
cout << p1.name << endl;
cout << p2.name << endl;
}
int main()
{
test();
system("pause");
return EXIT_SUCCESS;
}
输出结果如下: